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
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 * This is really a wrapper for addxtypeChild
176 * it handles stuff relating to flexy:foreach / flexy:if
177 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
178 * -- this is a bit of a nightmare... and is even more confusing to debug..
183 addxtype : function(tree,cntr)
187 cn = Roo.factory(tree);
188 //Roo.log(['addxtype', cn]);
190 cn.parentType = this.xtype; //??
191 cn.parentId = this.id;
193 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
194 if (typeof(cn.container_method) == 'string') {
195 cntr = cn.container_method;
199 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
201 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
203 var build_from_html = Roo.XComponent.build_from_html;
205 var is_body = (tree.xtype == 'Body') ;
207 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
209 var self_cntr_el = Roo.get(this[cntr](false));
211 // do not try and build conditional elements
212 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
216 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
217 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
218 return this.addxtypeChild(tree,cntr, is_body);
221 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
224 return this.addxtypeChild(Roo.apply({}, tree),cntr);
227 Roo.log('skipping render');
233 if (!build_from_html) {
237 // this i think handles overlaying multiple children of the same type
238 // with the sam eelement.. - which might be buggy..
240 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
246 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
250 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
256 * add a child to this element
257 * - turn the child.cfg into a child_instance
258 * - call child_instance.render( this { getContainerMethod()} )
259 * - loop through the children, and call addxtype.. (reall this) on newly created child.
263 addxtypeChild : function (tree, cntr, is_body)
265 Roo.debug && Roo.log('addxtypeChild:' + cntr);
267 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
270 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
271 (typeof(tree['flexy:foreach']) != 'undefined');
275 skip_children = false;
276 // render the element if it's not BODY.
279 // if parent was disabled, then do not try and create the children..
280 if(!this[cntr](true)){
285 cn = Roo.factory(tree);
287 cn.parentType = this.xtype; //??
288 cn.parentId = this.id;
290 var build_from_html = Roo.XComponent.build_from_html;
293 // does the container contain child eleemnts with 'xtype' attributes.
294 // that match this xtype..
295 // note - when we render we create these as well..
296 // so we should check to see if body has xtype set.
297 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
299 var self_cntr_el = Roo.get(this[cntr](false));
300 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
302 //Roo.log(Roo.XComponent.build_from_html);
303 //Roo.log("got echild:");
306 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
307 // and are not displayed -this causes this to use up the wrong element when matching.
308 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
311 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
312 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
318 //echild.dom.removeAttribute('xtype');
320 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
321 Roo.debug && Roo.log(self_cntr_el);
322 Roo.debug && Roo.log(echild);
323 Roo.debug && Roo.log(cn);
329 // if object has flexy:if - then it may or may not be rendered.
330 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
331 // skip a flexy if element.
332 Roo.debug && Roo.log('skipping render');
333 Roo.debug && Roo.log(tree);
335 Roo.debug && Roo.log('skipping all children');
336 skip_children = true;
341 // actually if flexy:foreach is found, we really want to create
342 // multiple copies here...
344 //Roo.log(this[cntr]());
345 // some elements do not have render methods.. like the layouts...
347 if(this[cntr](true) === false){
352 cn.render && cn.render(this[cntr](true));
355 // then add the element..
362 cn.addxtypeChildren(tree.items, skip_children);
368 * add a number of children to this object,
369 * which in turn calls render...
373 addxtypeChildren: function(child_array, skip_children)
376 if (!child_array || !child_array.length ) {
381 for(var i =0;i < child_array.length;i++) {
385 // Roo.log(['add child', items[i]]);
386 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
390 this.fireEvent('childrenrendered', this);
397 * Set the element that will be used to show or hide
399 setVisibilityEl : function(el)
401 this.visibilityEl = el;
405 * Get the element that will be used to show or hide
407 getVisibilityEl : function()
409 if (typeof(this.visibilityEl) == 'object') {
410 return this.visibilityEl;
413 if (typeof(this.visibilityEl) == 'string') {
414 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
421 * Show a component - removes 'hidden' class
425 if(!this.getVisibilityEl()){
429 this.getVisibilityEl().removeClass(['hidden','d-none']);
431 this.fireEvent('show', this);
436 * Hide a component - adds 'hidden' class
440 if(!this.getVisibilityEl()){
444 this.getVisibilityEl().addClass(['hidden','d-none']);
446 this.fireEvent('hide', this);
459 * @class Roo.bootstrap.Body
460 * @extends Roo.bootstrap.Component
461 * Bootstrap Body class
465 * @param {Object} config The config object
468 Roo.bootstrap.Body = function(config){
470 config = config || {};
472 Roo.bootstrap.Body.superclass.constructor.call(this, config);
473 this.el = Roo.get(config.el ? config.el : document.body );
474 if (this.cls && this.cls.length) {
475 Roo.get(document.body).addClass(this.cls);
479 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
481 is_body : true,// just to make sure it's constructed?
486 onRender : function(ct, position)
488 /* Roo.log("Roo.bootstrap.Body - onRender");
489 if (this.cls && this.cls.length) {
490 Roo.get(document.body).addClass(this.cls);
509 * @class Roo.bootstrap.ButtonGroup
510 * @extends Roo.bootstrap.Component
511 * Bootstrap ButtonGroup class
512 * @cfg {String} size lg | sm | xs (default empty normal)
513 * @cfg {String} align vertical | justified (default none)
514 * @cfg {String} direction up | down (default down)
515 * @cfg {Boolean} toolbar false | true
516 * @cfg {Boolean} btn true | false
521 * @param {Object} config The config object
524 Roo.bootstrap.ButtonGroup = function(config){
525 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
528 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
536 getAutoCreate : function(){
542 cfg.html = this.html || cfg.html;
553 if (['vertical','justified'].indexOf(this.align)!==-1) {
554 cfg.cls = 'btn-group-' + this.align;
556 if (this.align == 'justified') {
557 console.log(this.items);
561 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
562 cfg.cls += ' btn-group-' + this.size;
565 if (this.direction == 'up') {
566 cfg.cls += ' dropup' ;
572 * Add a button to the group (similar to NavItem API.)
574 addItem : function(cfg)
576 var cn = new Roo.bootstrap.Button(cfg);
578 cn.parentId = this.id;
579 cn.onRender(this.el, null);
593 * @class Roo.bootstrap.Button
594 * @extends Roo.bootstrap.Component
595 * Bootstrap Button class
596 * @cfg {String} html The button content
597 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
598 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
599 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
600 * @cfg {String} size ( lg | sm | xs)
601 * @cfg {String} tag ( a | input | submit)
602 * @cfg {String} href empty or href
603 * @cfg {Boolean} disabled default false;
604 * @cfg {Boolean} isClose default false;
605 * @cfg {String} glyphicon depricated - use fa
606 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
607 * @cfg {String} badge text for badge
608 * @cfg {String} theme (default|glow)
609 * @cfg {Boolean} inverse dark themed version
610 * @cfg {Boolean} toggle is it a slidy toggle button
611 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
612 * @cfg {String} ontext text for on slidy toggle state
613 * @cfg {String} offtext text for off slidy toggle state
614 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
615 * @cfg {Boolean} removeClass remove the standard class..
616 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
619 * Create a new button
620 * @param {Object} config The config object
624 Roo.bootstrap.Button = function(config){
625 Roo.bootstrap.Button.superclass.constructor.call(this, config);
626 this.weightClass = ["btn-default btn-outline-secondary",
638 * When a butotn is pressed
639 * @param {Roo.bootstrap.Button} btn
640 * @param {Roo.EventObject} e
645 * After the button has been toggles
646 * @param {Roo.bootstrap.Button} btn
647 * @param {Roo.EventObject} e
648 * @param {boolean} pressed (also available as button.pressed)
654 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
675 preventDefault: true,
683 getAutoCreate : function(){
691 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
692 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
697 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
699 if (this.toggle == true) {
702 cls: 'slider-frame roo-button',
707 'data-off-text':'OFF',
708 cls: 'slider-button',
714 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
715 cfg.cls += ' '+this.weight;
724 cfg["aria-hidden"] = true;
726 cfg.html = "×";
732 if (this.theme==='default') {
733 cfg.cls = 'btn roo-button';
735 //if (this.parentType != 'Navbar') {
736 this.weight = this.weight.length ? this.weight : 'default';
738 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
740 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
741 var weight = this.weight == 'default' ? 'secondary' : this.weight;
742 cfg.cls += ' btn-' + outline + weight;
743 if (this.weight == 'default') {
745 cfg.cls += ' btn-' + this.weight;
748 } else if (this.theme==='glow') {
751 cfg.cls = 'btn-glow roo-button';
753 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
755 cfg.cls += ' ' + this.weight;
761 this.cls += ' inverse';
765 if (this.active || this.pressed === true) {
766 cfg.cls += ' active';
770 cfg.disabled = 'disabled';
774 Roo.log('changing to ul' );
776 this.glyphicon = 'caret';
777 if (Roo.bootstrap.version == 4) {
778 this.fa = 'caret-down';
783 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
785 //gsRoo.log(this.parentType);
786 if (this.parentType === 'Navbar' && !this.parent().bar) {
787 Roo.log('changing to li?');
796 href : this.href || '#'
799 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
800 cfg.cls += ' dropdown';
807 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
809 if (this.glyphicon) {
810 cfg.html = ' ' + cfg.html;
815 cls: 'glyphicon glyphicon-' + this.glyphicon
820 cfg.html = ' ' + cfg.html;
825 cls: 'fa fas fa-' + this.fa
835 // cfg.cls='btn roo-button';
839 var value = cfg.html;
844 cls: 'glyphicon glyphicon-' + this.glyphicon,
851 cls: 'fa fas fa-' + this.fa,
856 var bw = this.badge_weight.length ? this.badge_weight :
857 (this.weight.length ? this.weight : 'secondary');
858 bw = bw == 'default' ? 'secondary' : bw;
864 cls: 'badge badge-' + bw,
873 cfg.cls += ' dropdown';
874 cfg.html = typeof(cfg.html) != 'undefined' ?
875 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
878 if (cfg.tag !== 'a' && this.href !== '') {
879 throw "Tag must be a to set href.";
880 } else if (this.href.length > 0) {
881 cfg.href = this.href;
884 if(this.removeClass){
889 cfg.target = this.target;
894 initEvents: function() {
895 // Roo.log('init events?');
896 // Roo.log(this.el.dom);
899 if (typeof (this.menu) != 'undefined') {
900 this.menu.parentType = this.xtype;
901 this.menu.triggerEl = this.el;
902 this.addxtype(Roo.apply({}, this.menu));
906 if (this.el.hasClass('roo-button')) {
907 this.el.on('click', this.onClick, this);
909 this.el.select('.roo-button').on('click', this.onClick, this);
912 if(this.removeClass){
913 this.el.on('click', this.onClick, this);
916 this.el.enableDisplayMode();
919 onClick : function(e)
925 Roo.log('button on click ');
926 if(this.preventDefault){
930 if (this.pressed === true || this.pressed === false) {
931 this.toggleActive(e);
935 this.fireEvent('click', this, e);
939 * Enables this button
943 this.disabled = false;
944 this.el.removeClass('disabled');
948 * Disable this button
952 this.disabled = true;
953 this.el.addClass('disabled');
956 * sets the active state on/off,
957 * @param {Boolean} state (optional) Force a particular state
959 setActive : function(v) {
961 this.el[v ? 'addClass' : 'removeClass']('active');
965 * toggles the current active state
967 toggleActive : function(e)
969 this.setActive(!this.pressed);
970 this.fireEvent('toggle', this, e, !this.pressed);
973 * get the current active state
974 * @return {boolean} true if it's active
976 isActive : function()
978 return this.el.hasClass('active');
981 * set the text of the first selected button
983 setText : function(str)
985 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
988 * get the text of the first selected button
992 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
995 setWeight : function(str)
997 this.el.removeClass(this.weightClass);
999 var outline = this.outline ? 'outline-' : '';
1000 if (str == 'default') {
1001 this.el.addClass('btn-default btn-outline-secondary');
1004 this.el.addClass('btn-' + outline + str);
1018 * @class Roo.bootstrap.Column
1019 * @extends Roo.bootstrap.Component
1020 * Bootstrap Column class
1021 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1022 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1023 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1024 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1025 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1026 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1027 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1028 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1031 * @cfg {Boolean} hidden (true|false) hide the element
1032 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1033 * @cfg {String} fa (ban|check|...) font awesome icon
1034 * @cfg {Number} fasize (1|2|....) font awsome size
1036 * @cfg {String} icon (info-sign|check|...) glyphicon name
1038 * @cfg {String} html content of column.
1041 * Create a new Column
1042 * @param {Object} config The config object
1045 Roo.bootstrap.Column = function(config){
1046 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1049 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1067 getAutoCreate : function(){
1068 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1076 ['xs','sm','md','lg'].map(function(size){
1077 //Roo.log( size + ':' + settings[size]);
1079 if (settings[size+'off'] !== false) {
1080 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1083 if (settings[size] === false) {
1087 if (!settings[size]) { // 0 = hidden
1088 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1091 cfg.cls += ' col-' + size + '-' + settings[size] + (
1092 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1098 cfg.cls += ' hidden';
1101 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1102 cfg.cls +=' alert alert-' + this.alert;
1106 if (this.html.length) {
1107 cfg.html = this.html;
1111 if (this.fasize > 1) {
1112 fasize = ' fa-' + this.fasize + 'x';
1114 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1119 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1138 * @class Roo.bootstrap.Container
1139 * @extends Roo.bootstrap.Component
1140 * Bootstrap Container class
1141 * @cfg {Boolean} jumbotron is it a jumbotron element
1142 * @cfg {String} html content of element
1143 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1144 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1145 * @cfg {String} header content of header (for panel)
1146 * @cfg {String} footer content of footer (for panel)
1147 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1148 * @cfg {String} tag (header|aside|section) type of HTML tag.
1149 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1150 * @cfg {String} fa font awesome icon
1151 * @cfg {String} icon (info-sign|check|...) glyphicon name
1152 * @cfg {Boolean} hidden (true|false) hide the element
1153 * @cfg {Boolean} expandable (true|false) default false
1154 * @cfg {Boolean} expanded (true|false) default true
1155 * @cfg {String} rheader contet on the right of header
1156 * @cfg {Boolean} clickable (true|false) default false
1160 * Create a new Container
1161 * @param {Object} config The config object
1164 Roo.bootstrap.Container = function(config){
1165 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1171 * After the panel has been expand
1173 * @param {Roo.bootstrap.Container} this
1178 * After the panel has been collapsed
1180 * @param {Roo.bootstrap.Container} this
1185 * When a element is chick
1186 * @param {Roo.bootstrap.Container} this
1187 * @param {Roo.EventObject} e
1193 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1211 getChildContainer : function() {
1217 if (this.panel.length) {
1218 return this.el.select('.panel-body',true).first();
1225 getAutoCreate : function(){
1228 tag : this.tag || 'div',
1232 if (this.jumbotron) {
1233 cfg.cls = 'jumbotron';
1238 // - this is applied by the parent..
1240 // cfg.cls = this.cls + '';
1243 if (this.sticky.length) {
1245 var bd = Roo.get(document.body);
1246 if (!bd.hasClass('bootstrap-sticky')) {
1247 bd.addClass('bootstrap-sticky');
1248 Roo.select('html',true).setStyle('height', '100%');
1251 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1255 if (this.well.length) {
1256 switch (this.well) {
1259 cfg.cls +=' well well-' +this.well;
1268 cfg.cls += ' hidden';
1272 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1273 cfg.cls +=' alert alert-' + this.alert;
1278 if (this.panel.length) {
1279 cfg.cls += ' panel panel-' + this.panel;
1281 if (this.header.length) {
1285 if(this.expandable){
1287 cfg.cls = cfg.cls + ' expandable';
1291 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1299 cls : 'panel-title',
1300 html : (this.expandable ? ' ' : '') + this.header
1304 cls: 'panel-header-right',
1310 cls : 'panel-heading',
1311 style : this.expandable ? 'cursor: pointer' : '',
1319 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1324 if (this.footer.length) {
1326 cls : 'panel-footer',
1335 body.html = this.html || cfg.html;
1336 // prefix with the icons..
1338 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1341 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1346 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1347 cfg.cls = 'container';
1353 initEvents: function()
1355 if(this.expandable){
1356 var headerEl = this.headerEl();
1359 headerEl.on('click', this.onToggleClick, this);
1364 this.el.on('click', this.onClick, this);
1369 onToggleClick : function()
1371 var headerEl = this.headerEl();
1387 if(this.fireEvent('expand', this)) {
1389 this.expanded = true;
1391 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1393 this.el.select('.panel-body',true).first().removeClass('hide');
1395 var toggleEl = this.toggleEl();
1401 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1406 collapse : function()
1408 if(this.fireEvent('collapse', this)) {
1410 this.expanded = false;
1412 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1413 this.el.select('.panel-body',true).first().addClass('hide');
1415 var toggleEl = this.toggleEl();
1421 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1425 toggleEl : function()
1427 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1431 return this.el.select('.panel-heading .fa',true).first();
1434 headerEl : function()
1436 if(!this.el || !this.panel.length || !this.header.length){
1440 return this.el.select('.panel-heading',true).first()
1445 if(!this.el || !this.panel.length){
1449 return this.el.select('.panel-body',true).first()
1452 titleEl : function()
1454 if(!this.el || !this.panel.length || !this.header.length){
1458 return this.el.select('.panel-title',true).first();
1461 setTitle : function(v)
1463 var titleEl = this.titleEl();
1469 titleEl.dom.innerHTML = v;
1472 getTitle : function()
1475 var titleEl = this.titleEl();
1481 return titleEl.dom.innerHTML;
1484 setRightTitle : function(v)
1486 var t = this.el.select('.panel-header-right',true).first();
1492 t.dom.innerHTML = v;
1495 onClick : function(e)
1499 this.fireEvent('click', this, e);
1512 * @class Roo.bootstrap.Img
1513 * @extends Roo.bootstrap.Component
1514 * Bootstrap Img class
1515 * @cfg {Boolean} imgResponsive false | true
1516 * @cfg {String} border rounded | circle | thumbnail
1517 * @cfg {String} src image source
1518 * @cfg {String} alt image alternative text
1519 * @cfg {String} href a tag href
1520 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1521 * @cfg {String} xsUrl xs image source
1522 * @cfg {String} smUrl sm image source
1523 * @cfg {String} mdUrl md image source
1524 * @cfg {String} lgUrl lg image source
1527 * Create a new Input
1528 * @param {Object} config The config object
1531 Roo.bootstrap.Img = function(config){
1532 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1538 * The img click event for the img.
1539 * @param {Roo.EventObject} e
1545 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1547 imgResponsive: true,
1557 getAutoCreate : function()
1559 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1560 return this.createSingleImg();
1565 cls: 'roo-image-responsive-group',
1570 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1572 if(!_this[size + 'Url']){
1578 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1579 html: _this.html || cfg.html,
1580 src: _this[size + 'Url']
1583 img.cls += ' roo-image-responsive-' + size;
1585 var s = ['xs', 'sm', 'md', 'lg'];
1587 s.splice(s.indexOf(size), 1);
1589 Roo.each(s, function(ss){
1590 img.cls += ' hidden-' + ss;
1593 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1594 cfg.cls += ' img-' + _this.border;
1598 cfg.alt = _this.alt;
1611 a.target = _this.target;
1615 cfg.cn.push((_this.href) ? a : img);
1622 createSingleImg : function()
1626 cls: (this.imgResponsive) ? 'img-responsive' : '',
1628 src : 'about:blank' // just incase src get's set to undefined?!?
1631 cfg.html = this.html || cfg.html;
1633 cfg.src = this.src || cfg.src;
1635 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1636 cfg.cls += ' img-' + this.border;
1653 a.target = this.target;
1658 return (this.href) ? a : cfg;
1661 initEvents: function()
1664 this.el.on('click', this.onClick, this);
1669 onClick : function(e)
1671 Roo.log('img onclick');
1672 this.fireEvent('click', this, e);
1675 * Sets the url of the image - used to update it
1676 * @param {String} url the url of the image
1679 setSrc : function(url)
1683 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1684 this.el.dom.src = url;
1688 this.el.select('img', true).first().dom.src = url;
1704 * @class Roo.bootstrap.Link
1705 * @extends Roo.bootstrap.Component
1706 * Bootstrap Link Class
1707 * @cfg {String} alt image alternative text
1708 * @cfg {String} href a tag href
1709 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1710 * @cfg {String} html the content of the link.
1711 * @cfg {String} anchor name for the anchor link
1712 * @cfg {String} fa - favicon
1714 * @cfg {Boolean} preventDefault (true | false) default false
1718 * Create a new Input
1719 * @param {Object} config The config object
1722 Roo.bootstrap.Link = function(config){
1723 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1729 * The img click event for the img.
1730 * @param {Roo.EventObject} e
1736 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1740 preventDefault: false,
1746 getAutoCreate : function()
1748 var html = this.html || '';
1750 if (this.fa !== false) {
1751 html = '<i class="fa fa-' + this.fa + '"></i>';
1756 // anchor's do not require html/href...
1757 if (this.anchor === false) {
1759 cfg.href = this.href || '#';
1761 cfg.name = this.anchor;
1762 if (this.html !== false || this.fa !== false) {
1765 if (this.href !== false) {
1766 cfg.href = this.href;
1770 if(this.alt !== false){
1775 if(this.target !== false) {
1776 cfg.target = this.target;
1782 initEvents: function() {
1784 if(!this.href || this.preventDefault){
1785 this.el.on('click', this.onClick, this);
1789 onClick : function(e)
1791 if(this.preventDefault){
1794 //Roo.log('img onclick');
1795 this.fireEvent('click', this, e);
1808 * @class Roo.bootstrap.Header
1809 * @extends Roo.bootstrap.Component
1810 * Bootstrap Header class
1811 * @cfg {String} html content of header
1812 * @cfg {Number} level (1|2|3|4|5|6) default 1
1815 * Create a new Header
1816 * @param {Object} config The config object
1820 Roo.bootstrap.Header = function(config){
1821 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1824 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1832 getAutoCreate : function(){
1837 tag: 'h' + (1 *this.level),
1838 html: this.html || ''
1850 * Ext JS Library 1.1.1
1851 * Copyright(c) 2006-2007, Ext JS, LLC.
1853 * Originally Released Under LGPL - original licence link has changed is not relivant.
1856 * <script type="text/javascript">
1860 * @class Roo.bootstrap.MenuMgr
1861 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1864 Roo.bootstrap.MenuMgr = function(){
1865 var menus, active, groups = {}, attached = false, lastShow = new Date();
1867 // private - called when first menu is created
1870 active = new Roo.util.MixedCollection();
1871 Roo.get(document).addKeyListener(27, function(){
1872 if(active.length > 0){
1880 if(active && active.length > 0){
1881 var c = active.clone();
1891 if(active.length < 1){
1892 Roo.get(document).un("mouseup", onMouseDown);
1900 var last = active.last();
1901 lastShow = new Date();
1904 Roo.get(document).on("mouseup", onMouseDown);
1909 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1910 m.parentMenu.activeChild = m;
1911 }else if(last && last.isVisible()){
1912 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1917 function onBeforeHide(m){
1919 m.activeChild.hide();
1921 if(m.autoHideTimer){
1922 clearTimeout(m.autoHideTimer);
1923 delete m.autoHideTimer;
1928 function onBeforeShow(m){
1929 var pm = m.parentMenu;
1930 if(!pm && !m.allowOtherMenus){
1932 }else if(pm && pm.activeChild && active != m){
1933 pm.activeChild.hide();
1937 // private this should really trigger on mouseup..
1938 function onMouseDown(e){
1939 Roo.log("on Mouse Up");
1941 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1942 Roo.log("MenuManager hideAll");
1951 function onBeforeCheck(mi, state){
1953 var g = groups[mi.group];
1954 for(var i = 0, l = g.length; i < l; i++){
1956 g[i].setChecked(false);
1965 * Hides all menus that are currently visible
1967 hideAll : function(){
1972 register : function(menu){
1976 menus[menu.id] = menu;
1977 menu.on("beforehide", onBeforeHide);
1978 menu.on("hide", onHide);
1979 menu.on("beforeshow", onBeforeShow);
1980 menu.on("show", onShow);
1982 if(g && menu.events["checkchange"]){
1986 groups[g].push(menu);
1987 menu.on("checkchange", onCheck);
1992 * Returns a {@link Roo.menu.Menu} object
1993 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1994 * be used to generate and return a new Menu instance.
1996 get : function(menu){
1997 if(typeof menu == "string"){ // menu id
1999 }else if(menu.events){ // menu instance
2002 /*else if(typeof menu.length == 'number'){ // array of menu items?
2003 return new Roo.bootstrap.Menu({items:menu});
2004 }else{ // otherwise, must be a config
2005 return new Roo.bootstrap.Menu(menu);
2012 unregister : function(menu){
2013 delete menus[menu.id];
2014 menu.un("beforehide", onBeforeHide);
2015 menu.un("hide", onHide);
2016 menu.un("beforeshow", onBeforeShow);
2017 menu.un("show", onShow);
2019 if(g && menu.events["checkchange"]){
2020 groups[g].remove(menu);
2021 menu.un("checkchange", onCheck);
2026 registerCheckable : function(menuItem){
2027 var g = menuItem.group;
2032 groups[g].push(menuItem);
2033 menuItem.on("beforecheckchange", onBeforeCheck);
2038 unregisterCheckable : function(menuItem){
2039 var g = menuItem.group;
2041 groups[g].remove(menuItem);
2042 menuItem.un("beforecheckchange", onBeforeCheck);
2054 * @class Roo.bootstrap.Menu
2055 * @extends Roo.bootstrap.Component
2056 * Bootstrap Menu class - container for MenuItems
2057 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2058 * @cfg {bool} hidden if the menu should be hidden when rendered.
2059 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2060 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2064 * @param {Object} config The config object
2068 Roo.bootstrap.Menu = function(config){
2069 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2070 if (this.registerMenu && this.type != 'treeview') {
2071 Roo.bootstrap.MenuMgr.register(this);
2078 * Fires before this menu is displayed (return false to block)
2079 * @param {Roo.menu.Menu} this
2084 * Fires before this menu is hidden (return false to block)
2085 * @param {Roo.menu.Menu} this
2090 * Fires after this menu is displayed
2091 * @param {Roo.menu.Menu} this
2096 * Fires after this menu is hidden
2097 * @param {Roo.menu.Menu} this
2102 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2103 * @param {Roo.menu.Menu} this
2104 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2105 * @param {Roo.EventObject} e
2110 * Fires when the mouse is hovering over this menu
2111 * @param {Roo.menu.Menu} this
2112 * @param {Roo.EventObject} e
2113 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2118 * Fires when the mouse exits 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 a menu item contained in this menu is clicked
2127 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2128 * @param {Roo.EventObject} e
2132 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2135 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2139 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2142 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2144 registerMenu : true,
2146 menuItems :false, // stores the menu items..
2156 getChildContainer : function() {
2160 getAutoCreate : function(){
2162 //if (['right'].indexOf(this.align)!==-1) {
2163 // cfg.cn[1].cls += ' pull-right'
2169 cls : 'dropdown-menu' ,
2170 style : 'z-index:1000'
2174 if (this.type === 'submenu') {
2175 cfg.cls = 'submenu active';
2177 if (this.type === 'treeview') {
2178 cfg.cls = 'treeview-menu';
2183 initEvents : function() {
2185 // Roo.log("ADD event");
2186 // Roo.log(this.triggerEl.dom);
2188 this.triggerEl.on('click', this.onTriggerClick, this);
2190 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2193 if (this.triggerEl.hasClass('nav-item')) {
2194 // dropdown toggle on the 'a' in BS4?
2195 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2197 this.triggerEl.addClass('dropdown-toggle');
2200 this.el.on('touchstart' , this.onTouch, this);
2202 this.el.on('click' , this.onClick, this);
2204 this.el.on("mouseover", this.onMouseOver, this);
2205 this.el.on("mouseout", this.onMouseOut, this);
2209 findTargetItem : function(e)
2211 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2215 //Roo.log(t); Roo.log(t.id);
2217 //Roo.log(this.menuitems);
2218 return this.menuitems.get(t.id);
2220 //return this.items.get(t.menuItemId);
2226 onTouch : function(e)
2228 Roo.log("menu.onTouch");
2229 //e.stopEvent(); this make the user popdown broken
2233 onClick : function(e)
2235 Roo.log("menu.onClick");
2237 var t = this.findTargetItem(e);
2238 if(!t || t.isContainer){
2243 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2244 if(t == this.activeItem && t.shouldDeactivate(e)){
2245 this.activeItem.deactivate();
2246 delete this.activeItem;
2250 this.setActiveItem(t, true);
2258 Roo.log('pass click event');
2262 this.fireEvent("click", this, t, e);
2266 if(!t.href.length || t.href == '#'){
2267 (function() { _this.hide(); }).defer(100);
2272 onMouseOver : function(e){
2273 var t = this.findTargetItem(e);
2276 // if(t.canActivate && !t.disabled){
2277 // this.setActiveItem(t, true);
2281 this.fireEvent("mouseover", this, e, t);
2283 isVisible : function(){
2284 return !this.hidden;
2286 onMouseOut : function(e){
2287 var t = this.findTargetItem(e);
2290 // if(t == this.activeItem && t.shouldDeactivate(e)){
2291 // this.activeItem.deactivate();
2292 // delete this.activeItem;
2295 this.fireEvent("mouseout", this, e, t);
2300 * Displays this menu relative to another element
2301 * @param {String/HTMLElement/Roo.Element} element The element to align to
2302 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2303 * the element (defaults to this.defaultAlign)
2304 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2306 show : function(el, pos, parentMenu)
2308 if (false === this.fireEvent("beforeshow", this)) {
2309 Roo.log("show canceled");
2312 this.parentMenu = parentMenu;
2317 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2320 * Displays this menu at a specific xy position
2321 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2322 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2324 showAt : function(xy, parentMenu, /* private: */_e){
2325 this.parentMenu = parentMenu;
2330 this.fireEvent("beforeshow", this);
2331 //xy = this.el.adjustForConstraints(xy);
2335 this.hideMenuItems();
2336 this.hidden = false;
2337 this.triggerEl.addClass('open');
2338 this.el.addClass('show');
2340 // reassign x when hitting right
2341 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2342 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2345 // reassign y when hitting bottom
2346 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2347 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2350 // but the list may align on trigger left or trigger top... should it be a properity?
2352 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2357 this.fireEvent("show", this);
2363 this.doFocus.defer(50, this);
2367 doFocus : function(){
2369 this.focusEl.focus();
2374 * Hides this menu and optionally all parent menus
2375 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2377 hide : function(deep)
2379 if (false === this.fireEvent("beforehide", this)) {
2380 Roo.log("hide canceled");
2383 this.hideMenuItems();
2384 if(this.el && this.isVisible()){
2386 if(this.activeItem){
2387 this.activeItem.deactivate();
2388 this.activeItem = null;
2390 this.triggerEl.removeClass('open');;
2391 this.el.removeClass('show');
2393 this.fireEvent("hide", this);
2395 if(deep === true && this.parentMenu){
2396 this.parentMenu.hide(true);
2400 onTriggerClick : function(e)
2402 Roo.log('trigger click');
2404 var target = e.getTarget();
2406 Roo.log(target.nodeName.toLowerCase());
2408 if(target.nodeName.toLowerCase() === 'i'){
2414 onTriggerPress : function(e)
2416 Roo.log('trigger press');
2417 //Roo.log(e.getTarget());
2418 // Roo.log(this.triggerEl.dom);
2420 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2421 var pel = Roo.get(e.getTarget());
2422 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2423 Roo.log('is treeview or dropdown?');
2427 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2431 if (this.isVisible()) {
2436 this.show(this.triggerEl, '?', false);
2439 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2446 hideMenuItems : function()
2448 Roo.log("hide Menu Items");
2453 this.el.select('.open',true).each(function(aa) {
2455 aa.removeClass('open');
2459 addxtypeChild : function (tree, cntr) {
2460 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2462 this.menuitems.add(comp);
2474 this.getEl().dom.innerHTML = '';
2475 this.menuitems.clear();
2489 * @class Roo.bootstrap.MenuItem
2490 * @extends Roo.bootstrap.Component
2491 * Bootstrap MenuItem class
2492 * @cfg {String} html the menu label
2493 * @cfg {String} href the link
2494 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2495 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2496 * @cfg {Boolean} active used on sidebars to highlight active itesm
2497 * @cfg {String} fa favicon to show on left of menu item.
2498 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2502 * Create a new MenuItem
2503 * @param {Object} config The config object
2507 Roo.bootstrap.MenuItem = function(config){
2508 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2513 * The raw click event for the entire grid.
2514 * @param {Roo.bootstrap.MenuItem} this
2515 * @param {Roo.EventObject} e
2521 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2525 preventDefault: false,
2526 isContainer : false,
2530 getAutoCreate : function(){
2532 if(this.isContainer){
2535 cls: 'dropdown-menu-item '
2545 cls : 'dropdown-item',
2550 if (this.fa !== false) {
2553 cls : 'fa fa-' + this.fa
2562 cls: 'dropdown-menu-item',
2565 if (this.parent().type == 'treeview') {
2566 cfg.cls = 'treeview-menu';
2569 cfg.cls += ' active';
2574 anc.href = this.href || cfg.cn[0].href ;
2575 ctag.html = this.html || cfg.cn[0].html ;
2579 initEvents: function()
2581 if (this.parent().type == 'treeview') {
2582 this.el.select('a').on('click', this.onClick, this);
2586 this.menu.parentType = this.xtype;
2587 this.menu.triggerEl = this.el;
2588 this.menu = this.addxtype(Roo.apply({}, this.menu));
2592 onClick : function(e)
2594 Roo.log('item on click ');
2596 if(this.preventDefault){
2599 //this.parent().hideMenuItems();
2601 this.fireEvent('click', this, e);
2620 * @class Roo.bootstrap.MenuSeparator
2621 * @extends Roo.bootstrap.Component
2622 * Bootstrap MenuSeparator class
2625 * Create a new MenuItem
2626 * @param {Object} config The config object
2630 Roo.bootstrap.MenuSeparator = function(config){
2631 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2634 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2636 getAutoCreate : function(){
2655 * @class Roo.bootstrap.Modal
2656 * @extends Roo.bootstrap.Component
2657 * Bootstrap Modal class
2658 * @cfg {String} title Title of dialog
2659 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2660 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2661 * @cfg {Boolean} specificTitle default false
2662 * @cfg {Array} buttons Array of buttons or standard button set..
2663 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2664 * @cfg {Boolean} animate default true
2665 * @cfg {Boolean} allow_close default true
2666 * @cfg {Boolean} fitwindow default false
2667 * @cfg {String} size (sm|lg) default empty
2668 * @cfg {Number} max_width set the max width of modal
2672 * Create a new Modal Dialog
2673 * @param {Object} config The config object
2676 Roo.bootstrap.Modal = function(config){
2677 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2682 * The raw btnclick event for the button
2683 * @param {Roo.EventObject} e
2688 * Fire when dialog resize
2689 * @param {Roo.bootstrap.Modal} this
2690 * @param {Roo.EventObject} e
2694 this.buttons = this.buttons || [];
2697 this.tmpl = Roo.factory(this.tmpl);
2702 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2704 title : 'test dialog',
2714 specificTitle: false,
2716 buttonPosition: 'right',
2739 onRender : function(ct, position)
2741 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2744 var cfg = Roo.apply({}, this.getAutoCreate());
2747 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2749 //if (!cfg.name.length) {
2753 cfg.cls += ' ' + this.cls;
2756 cfg.style = this.style;
2758 this.el = Roo.get(document.body).createChild(cfg, position);
2760 //var type = this.el.dom.type;
2763 if(this.tabIndex !== undefined){
2764 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2767 this.dialogEl = this.el.select('.modal-dialog',true).first();
2768 this.bodyEl = this.el.select('.modal-body',true).first();
2769 this.closeEl = this.el.select('.modal-header .close', true).first();
2770 this.headerEl = this.el.select('.modal-header',true).first();
2771 this.titleEl = this.el.select('.modal-title',true).first();
2772 this.footerEl = this.el.select('.modal-footer',true).first();
2774 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2776 //this.el.addClass("x-dlg-modal");
2778 if (this.buttons.length) {
2779 Roo.each(this.buttons, function(bb) {
2780 var b = Roo.apply({}, bb);
2781 b.xns = b.xns || Roo.bootstrap;
2782 b.xtype = b.xtype || 'Button';
2783 if (typeof(b.listeners) == 'undefined') {
2784 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2787 var btn = Roo.factory(b);
2789 btn.render(this.getButtonContainer());
2793 // render the children.
2796 if(typeof(this.items) != 'undefined'){
2797 var items = this.items;
2800 for(var i =0;i < items.length;i++) {
2801 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2805 this.items = nitems;
2807 // where are these used - they used to be body/close/footer
2811 //this.el.addClass([this.fieldClass, this.cls]);
2815 getAutoCreate : function()
2819 html : this.html || ''
2824 cls : 'modal-title',
2828 if(this.specificTitle){
2834 if (this.allow_close && Roo.bootstrap.version == 3) {
2844 if (this.allow_close && Roo.bootstrap.version == 4) {
2854 if(this.size.length){
2855 size = 'modal-' + this.size;
2858 var footer = Roo.bootstrap.version == 3 ?
2860 cls : 'modal-footer',
2864 cls: 'btn-' + this.buttonPosition
2869 { // BS4 uses mr-auto on left buttons....
2870 cls : 'modal-footer'
2881 cls: "modal-dialog " + size,
2884 cls : "modal-content",
2887 cls : 'modal-header',
2902 modal.cls += ' fade';
2908 getChildContainer : function() {
2913 getButtonContainer : function() {
2915 return Roo.bootstrap.version == 4 ?
2916 this.el.select('.modal-footer',true).first()
2917 : this.el.select('.modal-footer div',true).first();
2920 initEvents : function()
2922 if (this.allow_close) {
2923 this.closeEl.on('click', this.hide, this);
2925 Roo.EventManager.onWindowResize(this.resize, this, true);
2933 this.maskEl.setSize(
2934 Roo.lib.Dom.getViewWidth(true),
2935 Roo.lib.Dom.getViewHeight(true)
2938 if (this.fitwindow) {
2942 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2943 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2948 if(this.max_width !== 0) {
2950 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2953 this.setSize(w, this.height);
2957 if(this.max_height) {
2958 this.setSize(w,Math.min(
2960 Roo.lib.Dom.getViewportHeight(true) - 60
2966 if(!this.fit_content) {
2967 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2971 this.setSize(w, Math.min(
2973 this.headerEl.getHeight() +
2974 this.footerEl.getHeight() +
2975 this.getChildHeight(this.bodyEl.dom.childNodes),
2976 Roo.lib.Dom.getViewportHeight(true) - 60)
2982 setSize : function(w,h)
2993 if (!this.rendered) {
2997 //this.el.setStyle('display', 'block');
2998 this.el.removeClass('hideing');
2999 this.el.dom.style.display='block';
3001 Roo.get(document.body).addClass('modal-open');
3003 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3006 this.el.addClass('show');
3007 this.el.addClass('in');
3010 this.el.addClass('show');
3011 this.el.addClass('in');
3014 // not sure how we can show data in here..
3016 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3019 Roo.get(document.body).addClass("x-body-masked");
3021 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3022 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3023 this.maskEl.dom.style.display = 'block';
3024 this.maskEl.addClass('show');
3029 this.fireEvent('show', this);
3031 // set zindex here - otherwise it appears to be ignored...
3032 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3035 this.items.forEach( function(e) {
3036 e.layout ? e.layout() : false;
3044 if(this.fireEvent("beforehide", this) !== false){
3046 this.maskEl.removeClass('show');
3048 this.maskEl.dom.style.display = '';
3049 Roo.get(document.body).removeClass("x-body-masked");
3050 this.el.removeClass('in');
3051 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3053 if(this.animate){ // why
3054 this.el.addClass('hideing');
3055 this.el.removeClass('show');
3057 if (!this.el.hasClass('hideing')) {
3058 return; // it's been shown again...
3061 this.el.dom.style.display='';
3063 Roo.get(document.body).removeClass('modal-open');
3064 this.el.removeClass('hideing');
3068 this.el.removeClass('show');
3069 this.el.dom.style.display='';
3070 Roo.get(document.body).removeClass('modal-open');
3073 this.fireEvent('hide', this);
3076 isVisible : function()
3079 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3083 addButton : function(str, cb)
3087 var b = Roo.apply({}, { html : str } );
3088 b.xns = b.xns || Roo.bootstrap;
3089 b.xtype = b.xtype || 'Button';
3090 if (typeof(b.listeners) == 'undefined') {
3091 b.listeners = { click : cb.createDelegate(this) };
3094 var btn = Roo.factory(b);
3096 btn.render(this.getButtonContainer());
3102 setDefaultButton : function(btn)
3104 //this.el.select('.modal-footer').()
3107 resizeTo: function(w,h)
3109 this.dialogEl.setWidth(w);
3111 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3113 this.bodyEl.setHeight(h - diff);
3115 this.fireEvent('resize', this);
3118 setContentSize : function(w, h)
3122 onButtonClick: function(btn,e)
3125 this.fireEvent('btnclick', btn.name, e);
3128 * Set the title of the Dialog
3129 * @param {String} str new Title
3131 setTitle: function(str) {
3132 this.titleEl.dom.innerHTML = str;
3135 * Set the body of the Dialog
3136 * @param {String} str new Title
3138 setBody: function(str) {
3139 this.bodyEl.dom.innerHTML = str;
3142 * Set the body of the Dialog using the template
3143 * @param {Obj} data - apply this data to the template and replace the body contents.
3145 applyBody: function(obj)
3148 Roo.log("Error - using apply Body without a template");
3151 this.tmpl.overwrite(this.bodyEl, obj);
3154 getChildHeight : function(child_nodes)
3158 child_nodes.length == 0
3163 var child_height = 0;
3165 for(var i = 0; i < child_nodes.length; i++) {
3168 * for modal with tabs...
3169 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3171 var layout_childs = child_nodes[i].childNodes;
3173 for(var j = 0; j < layout_childs.length; j++) {
3175 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3177 var layout_body_childs = layout_childs[j].childNodes;
3179 for(var k = 0; k < layout_body_childs.length; k++) {
3181 if(layout_body_childs[k].classList.contains('navbar')) {
3182 child_height += layout_body_childs[k].offsetHeight;
3186 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3188 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3190 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3192 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3193 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3208 child_height += child_nodes[i].offsetHeight;
3209 // Roo.log(child_nodes[i].offsetHeight);
3212 return child_height;
3218 Roo.apply(Roo.bootstrap.Modal, {
3220 * Button config that displays a single OK button
3229 * Button config that displays Yes and No buttons
3245 * Button config that displays OK and Cancel buttons
3260 * Button config that displays Yes, No and Cancel buttons
3284 * messagebox - can be used as a replace
3288 * @class Roo.MessageBox
3289 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3293 Roo.Msg.alert('Status', 'Changes saved successfully.');
3295 // Prompt for user data:
3296 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3298 // process text value...
3302 // Show a dialog using config options:
3304 title:'Save Changes?',
3305 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3306 buttons: Roo.Msg.YESNOCANCEL,
3313 Roo.bootstrap.MessageBox = function(){
3314 var dlg, opt, mask, waitTimer;
3315 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3316 var buttons, activeTextEl, bwidth;
3320 var handleButton = function(button){
3322 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3326 var handleHide = function(){
3328 dlg.el.removeClass(opt.cls);
3331 // Roo.TaskMgr.stop(waitTimer);
3332 // waitTimer = null;
3337 var updateButtons = function(b){
3340 buttons["ok"].hide();
3341 buttons["cancel"].hide();
3342 buttons["yes"].hide();
3343 buttons["no"].hide();
3344 dlg.footerEl.hide();
3348 dlg.footerEl.show();
3349 for(var k in buttons){
3350 if(typeof buttons[k] != "function"){
3353 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3354 width += buttons[k].el.getWidth()+15;
3364 var handleEsc = function(d, k, e){
3365 if(opt && opt.closable !== false){
3375 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3376 * @return {Roo.BasicDialog} The BasicDialog element
3378 getDialog : function(){
3380 dlg = new Roo.bootstrap.Modal( {
3383 //constraintoviewport:false,
3385 //collapsible : false,
3390 //buttonAlign:"center",
3391 closeClick : function(){
3392 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3395 handleButton("cancel");
3400 dlg.on("hide", handleHide);
3402 //dlg.addKeyListener(27, handleEsc);
3404 this.buttons = buttons;
3405 var bt = this.buttonText;
3406 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3407 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3408 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3409 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3411 bodyEl = dlg.bodyEl.createChild({
3413 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3414 '<textarea class="roo-mb-textarea"></textarea>' +
3415 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3417 msgEl = bodyEl.dom.firstChild;
3418 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3419 textboxEl.enableDisplayMode();
3420 textboxEl.addKeyListener([10,13], function(){
3421 if(dlg.isVisible() && opt && opt.buttons){
3424 }else if(opt.buttons.yes){
3425 handleButton("yes");
3429 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3430 textareaEl.enableDisplayMode();
3431 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3432 progressEl.enableDisplayMode();
3434 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3435 var pf = progressEl.dom.firstChild;
3437 pp = Roo.get(pf.firstChild);
3438 pp.setHeight(pf.offsetHeight);
3446 * Updates the message box body text
3447 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3448 * the XHTML-compliant non-breaking space character '&#160;')
3449 * @return {Roo.MessageBox} This message box
3451 updateText : function(text)
3453 if(!dlg.isVisible() && !opt.width){
3454 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3455 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3457 msgEl.innerHTML = text || ' ';
3459 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3460 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3462 Math.min(opt.width || cw , this.maxWidth),
3463 Math.max(opt.minWidth || this.minWidth, bwidth)
3466 activeTextEl.setWidth(w);
3468 if(dlg.isVisible()){
3469 dlg.fixedcenter = false;
3471 // to big, make it scroll. = But as usual stupid IE does not support
3474 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3475 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3476 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3478 bodyEl.dom.style.height = '';
3479 bodyEl.dom.style.overflowY = '';
3482 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3484 bodyEl.dom.style.overflowX = '';
3487 dlg.setContentSize(w, bodyEl.getHeight());
3488 if(dlg.isVisible()){
3489 dlg.fixedcenter = true;
3495 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3496 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3497 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3498 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3499 * @return {Roo.MessageBox} This message box
3501 updateProgress : function(value, text){
3503 this.updateText(text);
3506 if (pp) { // weird bug on my firefox - for some reason this is not defined
3507 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3508 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3514 * Returns true if the message box is currently displayed
3515 * @return {Boolean} True if the message box is visible, else false
3517 isVisible : function(){
3518 return dlg && dlg.isVisible();
3522 * Hides the message box if it is displayed
3525 if(this.isVisible()){
3531 * Displays a new message box, or reinitializes an existing message box, based on the config options
3532 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3533 * The following config object properties are supported:
3535 Property Type Description
3536 ---------- --------------- ------------------------------------------------------------------------------------
3537 animEl String/Element An id or Element from which the message box should animate as it opens and
3538 closes (defaults to undefined)
3539 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3540 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3541 closable Boolean False to hide the top-right close button (defaults to true). Note that
3542 progress and wait dialogs will ignore this property and always hide the
3543 close button as they can only be closed programmatically.
3544 cls String A custom CSS class to apply to the message box element
3545 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3546 displayed (defaults to 75)
3547 fn Function A callback function to execute after closing the dialog. The arguments to the
3548 function will be btn (the name of the button that was clicked, if applicable,
3549 e.g. "ok"), and text (the value of the active text field, if applicable).
3550 Progress and wait dialogs will ignore this option since they do not respond to
3551 user actions and can only be closed programmatically, so any required function
3552 should be called by the same code after it closes the dialog.
3553 icon String A CSS class that provides a background image to be used as an icon for
3554 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3555 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3556 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3557 modal Boolean False to allow user interaction with the page while the message box is
3558 displayed (defaults to true)
3559 msg String A string that will replace the existing message box body text (defaults
3560 to the XHTML-compliant non-breaking space character ' ')
3561 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3562 progress Boolean True to display a progress bar (defaults to false)
3563 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3564 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3565 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3566 title String The title text
3567 value String The string value to set into the active textbox element if displayed
3568 wait Boolean True to display a progress bar (defaults to false)
3569 width Number The width of the dialog in pixels
3576 msg: 'Please enter your address:',
3578 buttons: Roo.MessageBox.OKCANCEL,
3581 animEl: 'addAddressBtn'
3584 * @param {Object} config Configuration options
3585 * @return {Roo.MessageBox} This message box
3587 show : function(options)
3590 // this causes nightmares if you show one dialog after another
3591 // especially on callbacks..
3593 if(this.isVisible()){
3596 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3597 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3598 Roo.log("New Dialog Message:" + options.msg )
3599 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3600 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3603 var d = this.getDialog();
3605 d.setTitle(opt.title || " ");
3606 d.closeEl.setDisplayed(opt.closable !== false);
3607 activeTextEl = textboxEl;
3608 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3613 textareaEl.setHeight(typeof opt.multiline == "number" ?
3614 opt.multiline : this.defaultTextHeight);
3615 activeTextEl = textareaEl;
3624 progressEl.setDisplayed(opt.progress === true);
3626 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3628 this.updateProgress(0);
3629 activeTextEl.dom.value = opt.value || "";
3631 dlg.setDefaultButton(activeTextEl);
3633 var bs = opt.buttons;
3637 }else if(bs && bs.yes){
3638 db = buttons["yes"];
3640 dlg.setDefaultButton(db);
3642 bwidth = updateButtons(opt.buttons);
3643 this.updateText(opt.msg);
3645 d.el.addClass(opt.cls);
3647 d.proxyDrag = opt.proxyDrag === true;
3648 d.modal = opt.modal !== false;
3649 d.mask = opt.modal !== false ? mask : false;
3651 // force it to the end of the z-index stack so it gets a cursor in FF
3652 document.body.appendChild(dlg.el.dom);
3653 d.animateTarget = null;
3654 d.show(options.animEl);
3660 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3661 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3662 * and closing the message box when the process is complete.
3663 * @param {String} title The title bar text
3664 * @param {String} msg The message box body text
3665 * @return {Roo.MessageBox} This message box
3667 progress : function(title, msg){
3674 minWidth: this.minProgressWidth,
3681 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3682 * If a callback function is passed it will be called after the user clicks the button, and the
3683 * id of the button that was clicked will be passed as the only parameter to the callback
3684 * (could also be the top-right close button).
3685 * @param {String} title The title bar text
3686 * @param {String} msg The message box body text
3687 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3688 * @param {Object} scope (optional) The scope of the callback function
3689 * @return {Roo.MessageBox} This message box
3691 alert : function(title, msg, fn, scope)
3706 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3707 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3708 * You are responsible for closing the message box when the process is complete.
3709 * @param {String} msg The message box body text
3710 * @param {String} title (optional) The title bar text
3711 * @return {Roo.MessageBox} This message box
3713 wait : function(msg, title){
3724 waitTimer = Roo.TaskMgr.start({
3726 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3734 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3735 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3736 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3737 * @param {String} title The title bar text
3738 * @param {String} msg The message box body text
3739 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3740 * @param {Object} scope (optional) The scope of the callback function
3741 * @return {Roo.MessageBox} This message box
3743 confirm : function(title, msg, fn, scope){
3747 buttons: this.YESNO,
3756 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3757 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3758 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3759 * (could also be the top-right close button) and the text that was entered will be passed as the two
3760 * parameters to the callback.
3761 * @param {String} title The title bar text
3762 * @param {String} msg The message box body text
3763 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3764 * @param {Object} scope (optional) The scope of the callback function
3765 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3766 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3767 * @return {Roo.MessageBox} This message box
3769 prompt : function(title, msg, fn, scope, multiline){
3773 buttons: this.OKCANCEL,
3778 multiline: multiline,
3785 * Button config that displays a single OK button
3790 * Button config that displays Yes and No buttons
3793 YESNO : {yes:true, no:true},
3795 * Button config that displays OK and Cancel buttons
3798 OKCANCEL : {ok:true, cancel:true},
3800 * Button config that displays Yes, No and Cancel buttons
3803 YESNOCANCEL : {yes:true, no:true, cancel:true},
3806 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3809 defaultTextHeight : 75,
3811 * The maximum width in pixels of the message box (defaults to 600)
3816 * The minimum width in pixels of the message box (defaults to 100)
3821 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3822 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3825 minProgressWidth : 250,
3827 * An object containing the default button text strings that can be overriden for localized language support.
3828 * Supported properties are: ok, cancel, yes and no.
3829 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3842 * Shorthand for {@link Roo.MessageBox}
3844 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3845 Roo.Msg = Roo.Msg || Roo.MessageBox;
3854 * @class Roo.bootstrap.Navbar
3855 * @extends Roo.bootstrap.Component
3856 * Bootstrap Navbar class
3859 * Create a new Navbar
3860 * @param {Object} config The config object
3864 Roo.bootstrap.Navbar = function(config){
3865 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3869 * @event beforetoggle
3870 * Fire before toggle the menu
3871 * @param {Roo.EventObject} e
3873 "beforetoggle" : true
3877 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3886 getAutoCreate : function(){
3889 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3893 initEvents :function ()
3895 //Roo.log(this.el.select('.navbar-toggle',true));
3896 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3903 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3905 var size = this.el.getSize();
3906 this.maskEl.setSize(size.width, size.height);
3907 this.maskEl.enableDisplayMode("block");
3916 getChildContainer : function()
3918 if (this.el && this.el.select('.collapse').getCount()) {
3919 return this.el.select('.collapse',true).first();
3934 onToggle : function()
3937 if(this.fireEvent('beforetoggle', this) === false){
3940 var ce = this.el.select('.navbar-collapse',true).first();
3942 if (!ce.hasClass('show')) {
3952 * Expand the navbar pulldown
3954 expand : function ()
3957 var ce = this.el.select('.navbar-collapse',true).first();
3958 if (ce.hasClass('collapsing')) {
3961 ce.dom.style.height = '';
3963 ce.addClass('in'); // old...
3964 ce.removeClass('collapse');
3965 ce.addClass('show');
3966 var h = ce.getHeight();
3968 ce.removeClass('show');
3969 // at this point we should be able to see it..
3970 ce.addClass('collapsing');
3972 ce.setHeight(0); // resize it ...
3973 ce.on('transitionend', function() {
3974 //Roo.log('done transition');
3975 ce.removeClass('collapsing');
3976 ce.addClass('show');
3977 ce.removeClass('collapse');
3979 ce.dom.style.height = '';
3980 }, this, { single: true} );
3982 ce.dom.scrollTop = 0;
3985 * Collapse the navbar pulldown
3987 collapse : function()
3989 var ce = this.el.select('.navbar-collapse',true).first();
3991 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
3992 // it's collapsed or collapsing..
3995 ce.removeClass('in'); // old...
3996 ce.setHeight(ce.getHeight());
3997 ce.removeClass('show');
3998 ce.addClass('collapsing');
4000 ce.on('transitionend', function() {
4001 ce.dom.style.height = '';
4002 ce.removeClass('collapsing');
4003 ce.addClass('collapse');
4004 }, this, { single: true} );
4024 * @class Roo.bootstrap.NavSimplebar
4025 * @extends Roo.bootstrap.Navbar
4026 * Bootstrap Sidebar class
4028 * @cfg {Boolean} inverse is inverted color
4030 * @cfg {String} type (nav | pills | tabs)
4031 * @cfg {Boolean} arrangement stacked | justified
4032 * @cfg {String} align (left | right) alignment
4034 * @cfg {Boolean} main (true|false) main nav bar? default false
4035 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4037 * @cfg {String} tag (header|footer|nav|div) default is nav
4039 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4043 * Create a new Sidebar
4044 * @param {Object} config The config object
4048 Roo.bootstrap.NavSimplebar = function(config){
4049 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4052 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4068 getAutoCreate : function(){
4072 tag : this.tag || 'div',
4073 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4075 if (['light','white'].indexOf(this.weight) > -1) {
4076 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4078 cfg.cls += ' bg-' + this.weight;
4081 cfg.cls += ' navbar-inverse';
4085 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4087 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4096 cls: 'nav nav-' + this.xtype,
4102 this.type = this.type || 'nav';
4103 if (['tabs','pills'].indexOf(this.type) != -1) {
4104 cfg.cn[0].cls += ' nav-' + this.type
4108 if (this.type!=='nav') {
4109 Roo.log('nav type must be nav/tabs/pills')
4111 cfg.cn[0].cls += ' navbar-nav'
4117 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4118 cfg.cn[0].cls += ' nav-' + this.arrangement;
4122 if (this.align === 'right') {
4123 cfg.cn[0].cls += ' navbar-right';
4148 * navbar-expand-md fixed-top
4152 * @class Roo.bootstrap.NavHeaderbar
4153 * @extends Roo.bootstrap.NavSimplebar
4154 * Bootstrap Sidebar class
4156 * @cfg {String} brand what is brand
4157 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4158 * @cfg {String} brand_href href of the brand
4159 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4160 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4161 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4162 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4165 * Create a new Sidebar
4166 * @param {Object} config The config object
4170 Roo.bootstrap.NavHeaderbar = function(config){
4171 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4175 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4182 desktopCenter : false,
4185 getAutoCreate : function(){
4188 tag: this.nav || 'nav',
4189 cls: 'navbar navbar-expand-md',
4195 if (this.desktopCenter) {
4196 cn.push({cls : 'container', cn : []});
4204 cls: 'navbar-toggle navbar-toggler',
4205 'data-toggle': 'collapse',
4210 html: 'Toggle navigation'
4214 cls: 'icon-bar navbar-toggler-icon'
4227 cn.push( Roo.bootstrap.version == 4 ? btn : {
4229 cls: 'navbar-header',
4238 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4242 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4244 if (['light','white'].indexOf(this.weight) > -1) {
4245 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4247 cfg.cls += ' bg-' + this.weight;
4250 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4251 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4253 // tag can override this..
4255 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4258 if (this.brand !== '') {
4259 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4260 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4262 href: this.brand_href ? this.brand_href : '#',
4263 cls: 'navbar-brand',
4271 cfg.cls += ' main-nav';
4279 getHeaderChildContainer : function()
4281 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4282 return this.el.select('.navbar-header',true).first();
4285 return this.getChildContainer();
4289 initEvents : function()
4291 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4293 if (this.autohide) {
4298 Roo.get(document).on('scroll',function(e) {
4299 var ns = Roo.get(document).getScroll().top;
4300 var os = prevScroll;
4304 ft.removeClass('slideDown');
4305 ft.addClass('slideUp');
4308 ft.removeClass('slideUp');
4309 ft.addClass('slideDown');
4330 * @class Roo.bootstrap.NavSidebar
4331 * @extends Roo.bootstrap.Navbar
4332 * Bootstrap Sidebar class
4335 * Create a new Sidebar
4336 * @param {Object} config The config object
4340 Roo.bootstrap.NavSidebar = function(config){
4341 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4344 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4346 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4348 getAutoCreate : function(){
4353 cls: 'sidebar sidebar-nav'
4375 * @class Roo.bootstrap.NavGroup
4376 * @extends Roo.bootstrap.Component
4377 * Bootstrap NavGroup class
4378 * @cfg {String} align (left|right)
4379 * @cfg {Boolean} inverse
4380 * @cfg {String} type (nav|pills|tab) default nav
4381 * @cfg {String} navId - reference Id for navbar.
4385 * Create a new nav group
4386 * @param {Object} config The config object
4389 Roo.bootstrap.NavGroup = function(config){
4390 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4393 Roo.bootstrap.NavGroup.register(this);
4397 * Fires when the active item changes
4398 * @param {Roo.bootstrap.NavGroup} this
4399 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4400 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4407 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4418 getAutoCreate : function()
4420 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4426 if (Roo.bootstrap.version == 4) {
4427 if (['tabs','pills'].indexOf(this.type) != -1) {
4428 cfg.cls += ' nav-' + this.type;
4430 // trying to remove so header bar can right align top?
4431 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4432 // do not use on header bar...
4433 cfg.cls += ' navbar-nav';
4438 if (['tabs','pills'].indexOf(this.type) != -1) {
4439 cfg.cls += ' nav-' + this.type
4441 if (this.type !== 'nav') {
4442 Roo.log('nav type must be nav/tabs/pills')
4444 cfg.cls += ' navbar-nav'
4448 if (this.parent() && this.parent().sidebar) {
4451 cls: 'dashboard-menu sidebar-menu'
4457 if (this.form === true) {
4460 cls: 'navbar-form form-inline'
4462 //nav navbar-right ml-md-auto
4463 if (this.align === 'right') {
4464 cfg.cls += ' navbar-right ml-md-auto';
4466 cfg.cls += ' navbar-left';
4470 if (this.align === 'right') {
4471 cfg.cls += ' navbar-right ml-md-auto';
4473 cfg.cls += ' mr-auto';
4477 cfg.cls += ' navbar-inverse';
4485 * sets the active Navigation item
4486 * @param {Roo.bootstrap.NavItem} the new current navitem
4488 setActiveItem : function(item)
4491 Roo.each(this.navItems, function(v){
4496 v.setActive(false, true);
4503 item.setActive(true, true);
4504 this.fireEvent('changed', this, item, prev);
4509 * gets the active Navigation item
4510 * @return {Roo.bootstrap.NavItem} the current navitem
4512 getActive : function()
4516 Roo.each(this.navItems, function(v){
4527 indexOfNav : function()
4531 Roo.each(this.navItems, function(v,i){
4542 * adds a Navigation item
4543 * @param {Roo.bootstrap.NavItem} the navitem to add
4545 addItem : function(cfg)
4547 if (this.form && Roo.bootstrap.version == 4) {
4550 var cn = new Roo.bootstrap.NavItem(cfg);
4552 cn.parentId = this.id;
4553 cn.onRender(this.el, null);
4557 * register a Navigation item
4558 * @param {Roo.bootstrap.NavItem} the navitem to add
4560 register : function(item)
4562 this.navItems.push( item);
4563 item.navId = this.navId;
4568 * clear all the Navigation item
4571 clearAll : function()
4574 this.el.dom.innerHTML = '';
4577 getNavItem: function(tabId)
4580 Roo.each(this.navItems, function(e) {
4581 if (e.tabId == tabId) {
4591 setActiveNext : function()
4593 var i = this.indexOfNav(this.getActive());
4594 if (i > this.navItems.length) {
4597 this.setActiveItem(this.navItems[i+1]);
4599 setActivePrev : function()
4601 var i = this.indexOfNav(this.getActive());
4605 this.setActiveItem(this.navItems[i-1]);
4607 clearWasActive : function(except) {
4608 Roo.each(this.navItems, function(e) {
4609 if (e.tabId != except.tabId && e.was_active) {
4610 e.was_active = false;
4617 getWasActive : function ()
4620 Roo.each(this.navItems, function(e) {
4635 Roo.apply(Roo.bootstrap.NavGroup, {
4639 * register a Navigation Group
4640 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4642 register : function(navgrp)
4644 this.groups[navgrp.navId] = navgrp;
4648 * fetch a Navigation Group based on the navigation ID
4649 * @param {string} the navgroup to add
4650 * @returns {Roo.bootstrap.NavGroup} the navgroup
4652 get: function(navId) {
4653 if (typeof(this.groups[navId]) == 'undefined') {
4655 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4657 return this.groups[navId] ;
4672 * @class Roo.bootstrap.NavItem
4673 * @extends Roo.bootstrap.Component
4674 * Bootstrap Navbar.NavItem class
4675 * @cfg {String} href link to
4676 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4678 * @cfg {String} html content of button
4679 * @cfg {String} badge text inside badge
4680 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4681 * @cfg {String} glyphicon DEPRICATED - use fa
4682 * @cfg {String} icon DEPRICATED - use fa
4683 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4684 * @cfg {Boolean} active Is item active
4685 * @cfg {Boolean} disabled Is item disabled
4687 * @cfg {Boolean} preventDefault (true | false) default false
4688 * @cfg {String} tabId the tab that this item activates.
4689 * @cfg {String} tagtype (a|span) render as a href or span?
4690 * @cfg {Boolean} animateRef (true|false) link to element default false
4693 * Create a new Navbar Item
4694 * @param {Object} config The config object
4696 Roo.bootstrap.NavItem = function(config){
4697 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4702 * The raw click event for the entire grid.
4703 * @param {Roo.EventObject} e
4708 * Fires when the active item active state changes
4709 * @param {Roo.bootstrap.NavItem} this
4710 * @param {boolean} state the new state
4716 * Fires when scroll to element
4717 * @param {Roo.bootstrap.NavItem} this
4718 * @param {Object} options
4719 * @param {Roo.EventObject} e
4727 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4736 preventDefault : false,
4744 button_outline : false,
4748 getAutoCreate : function(){
4756 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4758 if (this.disabled) {
4759 cfg.cls += ' disabled';
4763 if (this.button_weight.length) {
4764 cfg.tag = this.href ? 'a' : 'button';
4765 cfg.html = this.html || '';
4766 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4768 cfg.href = this.href;
4771 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4774 // menu .. should add dropdown-menu class - so no need for carat..
4776 if (this.badge !== '') {
4778 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4783 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4787 href : this.href || "#",
4788 html: this.html || ''
4791 if (this.tagtype == 'a') {
4792 cfg.cn[0].cls = 'nav-link';
4795 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4798 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4800 if(this.glyphicon) {
4801 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4806 cfg.cn[0].html += " <span class='caret'></span>";
4810 if (this.badge !== '') {
4812 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4820 onRender : function(ct, position)
4822 // Roo.log("Call onRender: " + this.xtype);
4823 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4827 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4828 this.navLink = this.el.select('.nav-link',true).first();
4833 initEvents: function()
4835 if (typeof (this.menu) != 'undefined') {
4836 this.menu.parentType = this.xtype;
4837 this.menu.triggerEl = this.el;
4838 this.menu = this.addxtype(Roo.apply({}, this.menu));
4841 this.el.select('a',true).on('click', this.onClick, this);
4843 if(this.tagtype == 'span'){
4844 this.el.select('span',true).on('click', this.onClick, this);
4847 // at this point parent should be available..
4848 this.parent().register(this);
4851 onClick : function(e)
4853 if (e.getTarget('.dropdown-menu-item')) {
4854 // did you click on a menu itemm.... - then don't trigger onclick..
4859 this.preventDefault ||
4862 Roo.log("NavItem - prevent Default?");
4866 if (this.disabled) {
4870 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4871 if (tg && tg.transition) {
4872 Roo.log("waiting for the transitionend");
4878 //Roo.log("fire event clicked");
4879 if(this.fireEvent('click', this, e) === false){
4883 if(this.tagtype == 'span'){
4887 //Roo.log(this.href);
4888 var ael = this.el.select('a',true).first();
4891 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4892 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4893 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4894 return; // ignore... - it's a 'hash' to another page.
4896 Roo.log("NavItem - prevent Default?");
4898 this.scrollToElement(e);
4902 var p = this.parent();
4904 if (['tabs','pills'].indexOf(p.type)!==-1) {
4905 if (typeof(p.setActiveItem) !== 'undefined') {
4906 p.setActiveItem(this);
4910 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4911 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4912 // remove the collapsed menu expand...
4913 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4917 isActive: function () {
4920 setActive : function(state, fire, is_was_active)
4922 if (this.active && !state && this.navId) {
4923 this.was_active = true;
4924 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4926 nv.clearWasActive(this);
4930 this.active = state;
4933 this.el.removeClass('active');
4934 this.navLink ? this.navLink.removeClass('active') : false;
4935 } else if (!this.el.hasClass('active')) {
4937 this.el.addClass('active');
4938 if (Roo.bootstrap.version == 4 && this.navLink ) {
4939 this.navLink.addClass('active');
4944 this.fireEvent('changed', this, state);
4947 // show a panel if it's registered and related..
4949 if (!this.navId || !this.tabId || !state || is_was_active) {
4953 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4957 var pan = tg.getPanelByName(this.tabId);
4961 // if we can not flip to new panel - go back to old nav highlight..
4962 if (false == tg.showPanel(pan)) {
4963 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4965 var onav = nv.getWasActive();
4967 onav.setActive(true, false, true);
4976 // this should not be here...
4977 setDisabled : function(state)
4979 this.disabled = state;
4981 this.el.removeClass('disabled');
4982 } else if (!this.el.hasClass('disabled')) {
4983 this.el.addClass('disabled');
4989 * Fetch the element to display the tooltip on.
4990 * @return {Roo.Element} defaults to this.el
4992 tooltipEl : function()
4994 return this.el.select('' + this.tagtype + '', true).first();
4997 scrollToElement : function(e)
4999 var c = document.body;
5002 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5004 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5005 c = document.documentElement;
5008 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5014 var o = target.calcOffsetsTo(c);
5021 this.fireEvent('scrollto', this, options, e);
5023 Roo.get(c).scrollTo('top', options.value, true);
5036 * <span> icon </span>
5037 * <span> text </span>
5038 * <span>badge </span>
5042 * @class Roo.bootstrap.NavSidebarItem
5043 * @extends Roo.bootstrap.NavItem
5044 * Bootstrap Navbar.NavSidebarItem class
5045 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5046 * {Boolean} open is the menu open
5047 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5048 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5049 * {String} buttonSize (sm|md|lg)the extra classes for the button
5050 * {Boolean} showArrow show arrow next to the text (default true)
5052 * Create a new Navbar Button
5053 * @param {Object} config The config object
5055 Roo.bootstrap.NavSidebarItem = function(config){
5056 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5061 * The raw click event for the entire grid.
5062 * @param {Roo.EventObject} e
5067 * Fires when the active item active state changes
5068 * @param {Roo.bootstrap.NavSidebarItem} this
5069 * @param {boolean} state the new state
5077 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5079 badgeWeight : 'default',
5085 buttonWeight : 'default',
5091 getAutoCreate : function(){
5096 href : this.href || '#',
5102 if(this.buttonView){
5105 href : this.href || '#',
5106 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5119 cfg.cls += ' active';
5122 if (this.disabled) {
5123 cfg.cls += ' disabled';
5126 cfg.cls += ' open x-open';
5129 if (this.glyphicon || this.icon) {
5130 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5131 a.cn.push({ tag : 'i', cls : c }) ;
5134 if(!this.buttonView){
5137 html : this.html || ''
5144 if (this.badge !== '') {
5145 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5151 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5154 a.cls += ' dropdown-toggle treeview' ;
5160 initEvents : function()
5162 if (typeof (this.menu) != 'undefined') {
5163 this.menu.parentType = this.xtype;
5164 this.menu.triggerEl = this.el;
5165 this.menu = this.addxtype(Roo.apply({}, this.menu));
5168 this.el.on('click', this.onClick, this);
5170 if(this.badge !== ''){
5171 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5176 onClick : function(e)
5183 if(this.preventDefault){
5187 this.fireEvent('click', this, e);
5190 disable : function()
5192 this.setDisabled(true);
5197 this.setDisabled(false);
5200 setDisabled : function(state)
5202 if(this.disabled == state){
5206 this.disabled = state;
5209 this.el.addClass('disabled');
5213 this.el.removeClass('disabled');
5218 setActive : function(state)
5220 if(this.active == state){
5224 this.active = state;
5227 this.el.addClass('active');
5231 this.el.removeClass('active');
5236 isActive: function ()
5241 setBadge : function(str)
5247 this.badgeEl.dom.innerHTML = str;
5264 * @class Roo.bootstrap.Row
5265 * @extends Roo.bootstrap.Component
5266 * Bootstrap Row class (contains columns...)
5270 * @param {Object} config The config object
5273 Roo.bootstrap.Row = function(config){
5274 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5277 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5279 getAutoCreate : function(){
5298 * @class Roo.bootstrap.Element
5299 * @extends Roo.bootstrap.Component
5300 * Bootstrap Element class
5301 * @cfg {String} html contents of the element
5302 * @cfg {String} tag tag of the element
5303 * @cfg {String} cls class of the element
5304 * @cfg {Boolean} preventDefault (true|false) default false
5305 * @cfg {Boolean} clickable (true|false) default false
5308 * Create a new Element
5309 * @param {Object} config The config object
5312 Roo.bootstrap.Element = function(config){
5313 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5319 * When a element is chick
5320 * @param {Roo.bootstrap.Element} this
5321 * @param {Roo.EventObject} e
5327 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5332 preventDefault: false,
5335 getAutoCreate : function(){
5339 // cls: this.cls, double assign in parent class Component.js :: onRender
5346 initEvents: function()
5348 Roo.bootstrap.Element.superclass.initEvents.call(this);
5351 this.el.on('click', this.onClick, this);
5356 onClick : function(e)
5358 if(this.preventDefault){
5362 this.fireEvent('click', this, e);
5365 getValue : function()
5367 return this.el.dom.innerHTML;
5370 setValue : function(value)
5372 this.el.dom.innerHTML = value;
5387 * @class Roo.bootstrap.Pagination
5388 * @extends Roo.bootstrap.Component
5389 * Bootstrap Pagination class
5390 * @cfg {String} size xs | sm | md | lg
5391 * @cfg {Boolean} inverse false | true
5394 * Create a new Pagination
5395 * @param {Object} config The config object
5398 Roo.bootstrap.Pagination = function(config){
5399 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5402 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5408 getAutoCreate : function(){
5414 cfg.cls += ' inverse';
5420 cfg.cls += " " + this.cls;
5438 * @class Roo.bootstrap.PaginationItem
5439 * @extends Roo.bootstrap.Component
5440 * Bootstrap PaginationItem class
5441 * @cfg {String} html text
5442 * @cfg {String} href the link
5443 * @cfg {Boolean} preventDefault (true | false) default true
5444 * @cfg {Boolean} active (true | false) default false
5445 * @cfg {Boolean} disabled default false
5449 * Create a new PaginationItem
5450 * @param {Object} config The config object
5454 Roo.bootstrap.PaginationItem = function(config){
5455 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5460 * The raw click event for the entire grid.
5461 * @param {Roo.EventObject} e
5467 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5471 preventDefault: true,
5476 getAutoCreate : function(){
5482 href : this.href ? this.href : '#',
5483 html : this.html ? this.html : ''
5493 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5497 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5503 initEvents: function() {
5505 this.el.on('click', this.onClick, this);
5508 onClick : function(e)
5510 Roo.log('PaginationItem on click ');
5511 if(this.preventDefault){
5519 this.fireEvent('click', this, e);
5535 * @class Roo.bootstrap.Slider
5536 * @extends Roo.bootstrap.Component
5537 * Bootstrap Slider class
5540 * Create a new Slider
5541 * @param {Object} config The config object
5544 Roo.bootstrap.Slider = function(config){
5545 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5548 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5550 getAutoCreate : function(){
5554 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5558 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5570 * Ext JS Library 1.1.1
5571 * Copyright(c) 2006-2007, Ext JS, LLC.
5573 * Originally Released Under LGPL - original licence link has changed is not relivant.
5576 * <script type="text/javascript">
5581 * @class Roo.grid.ColumnModel
5582 * @extends Roo.util.Observable
5583 * This is the default implementation of a ColumnModel used by the Grid. It defines
5584 * the columns in the grid.
5587 var colModel = new Roo.grid.ColumnModel([
5588 {header: "Ticker", width: 60, sortable: true, locked: true},
5589 {header: "Company Name", width: 150, sortable: true},
5590 {header: "Market Cap.", width: 100, sortable: true},
5591 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5592 {header: "Employees", width: 100, sortable: true, resizable: false}
5597 * The config options listed for this class are options which may appear in each
5598 * individual column definition.
5599 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5601 * @param {Object} config An Array of column config objects. See this class's
5602 * config objects for details.
5604 Roo.grid.ColumnModel = function(config){
5606 * The config passed into the constructor
5608 this.config = config;
5611 // if no id, create one
5612 // if the column does not have a dataIndex mapping,
5613 // map it to the order it is in the config
5614 for(var i = 0, len = config.length; i < len; i++){
5616 if(typeof c.dataIndex == "undefined"){
5619 if(typeof c.renderer == "string"){
5620 c.renderer = Roo.util.Format[c.renderer];
5622 if(typeof c.id == "undefined"){
5625 if(c.editor && c.editor.xtype){
5626 c.editor = Roo.factory(c.editor, Roo.grid);
5628 if(c.editor && c.editor.isFormField){
5629 c.editor = new Roo.grid.GridEditor(c.editor);
5631 this.lookup[c.id] = c;
5635 * The width of columns which have no width specified (defaults to 100)
5638 this.defaultWidth = 100;
5641 * Default sortable of columns which have no sortable specified (defaults to false)
5644 this.defaultSortable = false;
5648 * @event widthchange
5649 * Fires when the width of a column changes.
5650 * @param {ColumnModel} this
5651 * @param {Number} columnIndex The column index
5652 * @param {Number} newWidth The new width
5654 "widthchange": true,
5656 * @event headerchange
5657 * Fires when the text of a header changes.
5658 * @param {ColumnModel} this
5659 * @param {Number} columnIndex The column index
5660 * @param {Number} newText The new header text
5662 "headerchange": true,
5664 * @event hiddenchange
5665 * Fires when a column is hidden or "unhidden".
5666 * @param {ColumnModel} this
5667 * @param {Number} columnIndex The column index
5668 * @param {Boolean} hidden true if hidden, false otherwise
5670 "hiddenchange": true,
5672 * @event columnmoved
5673 * Fires when a column is moved.
5674 * @param {ColumnModel} this
5675 * @param {Number} oldIndex
5676 * @param {Number} newIndex
5678 "columnmoved" : true,
5680 * @event columlockchange
5681 * Fires when a column's locked state is changed
5682 * @param {ColumnModel} this
5683 * @param {Number} colIndex
5684 * @param {Boolean} locked true if locked
5686 "columnlockchange" : true
5688 Roo.grid.ColumnModel.superclass.constructor.call(this);
5690 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5692 * @cfg {String} header The header text to display in the Grid view.
5695 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5696 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5697 * specified, the column's index is used as an index into the Record's data Array.
5700 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5701 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5704 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5705 * Defaults to the value of the {@link #defaultSortable} property.
5706 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5709 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5712 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5715 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5718 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5721 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5722 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5723 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5724 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5727 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5730 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5733 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5736 * @cfg {String} cursor (Optional)
5739 * @cfg {String} tooltip (Optional)
5742 * @cfg {Number} xs (Optional)
5745 * @cfg {Number} sm (Optional)
5748 * @cfg {Number} md (Optional)
5751 * @cfg {Number} lg (Optional)
5754 * Returns the id of the column at the specified index.
5755 * @param {Number} index The column index
5756 * @return {String} the id
5758 getColumnId : function(index){
5759 return this.config[index].id;
5763 * Returns the column for a specified id.
5764 * @param {String} id The column id
5765 * @return {Object} the column
5767 getColumnById : function(id){
5768 return this.lookup[id];
5773 * Returns the column for a specified dataIndex.
5774 * @param {String} dataIndex The column dataIndex
5775 * @return {Object|Boolean} the column or false if not found
5777 getColumnByDataIndex: function(dataIndex){
5778 var index = this.findColumnIndex(dataIndex);
5779 return index > -1 ? this.config[index] : false;
5783 * Returns the index for a specified column id.
5784 * @param {String} id The column id
5785 * @return {Number} the index, or -1 if not found
5787 getIndexById : function(id){
5788 for(var i = 0, len = this.config.length; i < len; i++){
5789 if(this.config[i].id == id){
5797 * Returns the index for a specified column dataIndex.
5798 * @param {String} dataIndex The column dataIndex
5799 * @return {Number} the index, or -1 if not found
5802 findColumnIndex : function(dataIndex){
5803 for(var i = 0, len = this.config.length; i < len; i++){
5804 if(this.config[i].dataIndex == dataIndex){
5812 moveColumn : function(oldIndex, newIndex){
5813 var c = this.config[oldIndex];
5814 this.config.splice(oldIndex, 1);
5815 this.config.splice(newIndex, 0, c);
5816 this.dataMap = null;
5817 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5820 isLocked : function(colIndex){
5821 return this.config[colIndex].locked === true;
5824 setLocked : function(colIndex, value, suppressEvent){
5825 if(this.isLocked(colIndex) == value){
5828 this.config[colIndex].locked = value;
5830 this.fireEvent("columnlockchange", this, colIndex, value);
5834 getTotalLockedWidth : function(){
5836 for(var i = 0; i < this.config.length; i++){
5837 if(this.isLocked(i) && !this.isHidden(i)){
5838 this.totalWidth += this.getColumnWidth(i);
5844 getLockedCount : function(){
5845 for(var i = 0, len = this.config.length; i < len; i++){
5846 if(!this.isLocked(i)){
5851 return this.config.length;
5855 * Returns the number of columns.
5858 getColumnCount : function(visibleOnly){
5859 if(visibleOnly === true){
5861 for(var i = 0, len = this.config.length; i < len; i++){
5862 if(!this.isHidden(i)){
5868 return this.config.length;
5872 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5873 * @param {Function} fn
5874 * @param {Object} scope (optional)
5875 * @return {Array} result
5877 getColumnsBy : function(fn, scope){
5879 for(var i = 0, len = this.config.length; i < len; i++){
5880 var c = this.config[i];
5881 if(fn.call(scope||this, c, i) === true){
5889 * Returns true if the specified column is sortable.
5890 * @param {Number} col The column index
5893 isSortable : function(col){
5894 if(typeof this.config[col].sortable == "undefined"){
5895 return this.defaultSortable;
5897 return this.config[col].sortable;
5901 * Returns the rendering (formatting) function defined for the column.
5902 * @param {Number} col The column index.
5903 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5905 getRenderer : function(col){
5906 if(!this.config[col].renderer){
5907 return Roo.grid.ColumnModel.defaultRenderer;
5909 return this.config[col].renderer;
5913 * Sets the rendering (formatting) function for a column.
5914 * @param {Number} col The column index
5915 * @param {Function} fn The function to use to process the cell's raw data
5916 * to return HTML markup for the grid view. The render function is called with
5917 * the following parameters:<ul>
5918 * <li>Data value.</li>
5919 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5920 * <li>css A CSS style string to apply to the table cell.</li>
5921 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5922 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5923 * <li>Row index</li>
5924 * <li>Column index</li>
5925 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5927 setRenderer : function(col, fn){
5928 this.config[col].renderer = fn;
5932 * Returns the width for the specified column.
5933 * @param {Number} col The column index
5936 getColumnWidth : function(col){
5937 return this.config[col].width * 1 || this.defaultWidth;
5941 * Sets the width for a column.
5942 * @param {Number} col The column index
5943 * @param {Number} width The new width
5945 setColumnWidth : function(col, width, suppressEvent){
5946 this.config[col].width = width;
5947 this.totalWidth = null;
5949 this.fireEvent("widthchange", this, col, width);
5954 * Returns the total width of all columns.
5955 * @param {Boolean} includeHidden True to include hidden column widths
5958 getTotalWidth : function(includeHidden){
5959 if(!this.totalWidth){
5960 this.totalWidth = 0;
5961 for(var i = 0, len = this.config.length; i < len; i++){
5962 if(includeHidden || !this.isHidden(i)){
5963 this.totalWidth += this.getColumnWidth(i);
5967 return this.totalWidth;
5971 * Returns the header for the specified column.
5972 * @param {Number} col The column index
5975 getColumnHeader : function(col){
5976 return this.config[col].header;
5980 * Sets the header for a column.
5981 * @param {Number} col The column index
5982 * @param {String} header The new header
5984 setColumnHeader : function(col, header){
5985 this.config[col].header = header;
5986 this.fireEvent("headerchange", this, col, header);
5990 * Returns the tooltip for the specified column.
5991 * @param {Number} col The column index
5994 getColumnTooltip : function(col){
5995 return this.config[col].tooltip;
5998 * Sets the tooltip for a column.
5999 * @param {Number} col The column index
6000 * @param {String} tooltip The new tooltip
6002 setColumnTooltip : function(col, tooltip){
6003 this.config[col].tooltip = tooltip;
6007 * Returns the dataIndex for the specified column.
6008 * @param {Number} col The column index
6011 getDataIndex : function(col){
6012 return this.config[col].dataIndex;
6016 * Sets the dataIndex for a column.
6017 * @param {Number} col The column index
6018 * @param {Number} dataIndex The new dataIndex
6020 setDataIndex : function(col, dataIndex){
6021 this.config[col].dataIndex = dataIndex;
6027 * Returns true if the cell is editable.
6028 * @param {Number} colIndex The column index
6029 * @param {Number} rowIndex The row index - this is nto actually used..?
6032 isCellEditable : function(colIndex, rowIndex){
6033 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6037 * Returns the editor defined for the cell/column.
6038 * return false or null to disable editing.
6039 * @param {Number} colIndex The column index
6040 * @param {Number} rowIndex The row index
6043 getCellEditor : function(colIndex, rowIndex){
6044 return this.config[colIndex].editor;
6048 * Sets if a column is editable.
6049 * @param {Number} col The column index
6050 * @param {Boolean} editable True if the column is editable
6052 setEditable : function(col, editable){
6053 this.config[col].editable = editable;
6058 * Returns true if the column is hidden.
6059 * @param {Number} colIndex The column index
6062 isHidden : function(colIndex){
6063 return this.config[colIndex].hidden;
6068 * Returns true if the column width cannot be changed
6070 isFixed : function(colIndex){
6071 return this.config[colIndex].fixed;
6075 * Returns true if the column can be resized
6078 isResizable : function(colIndex){
6079 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6082 * Sets if a column is hidden.
6083 * @param {Number} colIndex The column index
6084 * @param {Boolean} hidden True if the column is hidden
6086 setHidden : function(colIndex, hidden){
6087 this.config[colIndex].hidden = hidden;
6088 this.totalWidth = null;
6089 this.fireEvent("hiddenchange", this, colIndex, hidden);
6093 * Sets the editor for a column.
6094 * @param {Number} col The column index
6095 * @param {Object} editor The editor object
6097 setEditor : function(col, editor){
6098 this.config[col].editor = editor;
6102 Roo.grid.ColumnModel.defaultRenderer = function(value)
6104 if(typeof value == "object") {
6107 if(typeof value == "string" && value.length < 1){
6111 return String.format("{0}", value);
6114 // Alias for backwards compatibility
6115 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6118 * Ext JS Library 1.1.1
6119 * Copyright(c) 2006-2007, Ext JS, LLC.
6121 * Originally Released Under LGPL - original licence link has changed is not relivant.
6124 * <script type="text/javascript">
6128 * @class Roo.LoadMask
6129 * A simple utility class for generically masking elements while loading data. If the element being masked has
6130 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6131 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6132 * element's UpdateManager load indicator and will be destroyed after the initial load.
6134 * Create a new LoadMask
6135 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6136 * @param {Object} config The config object
6138 Roo.LoadMask = function(el, config){
6139 this.el = Roo.get(el);
6140 Roo.apply(this, config);
6142 this.store.on('beforeload', this.onBeforeLoad, this);
6143 this.store.on('load', this.onLoad, this);
6144 this.store.on('loadexception', this.onLoadException, this);
6145 this.removeMask = false;
6147 var um = this.el.getUpdateManager();
6148 um.showLoadIndicator = false; // disable the default indicator
6149 um.on('beforeupdate', this.onBeforeLoad, this);
6150 um.on('update', this.onLoad, this);
6151 um.on('failure', this.onLoad, this);
6152 this.removeMask = true;
6156 Roo.LoadMask.prototype = {
6158 * @cfg {Boolean} removeMask
6159 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6160 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6164 * The text to display in a centered loading message box (defaults to 'Loading...')
6168 * @cfg {String} msgCls
6169 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6171 msgCls : 'x-mask-loading',
6174 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6180 * Disables the mask to prevent it from being displayed
6182 disable : function(){
6183 this.disabled = true;
6187 * Enables the mask so that it can be displayed
6189 enable : function(){
6190 this.disabled = false;
6193 onLoadException : function()
6197 if (typeof(arguments[3]) != 'undefined') {
6198 Roo.MessageBox.alert("Error loading",arguments[3]);
6202 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6203 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6210 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6215 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6219 onBeforeLoad : function(){
6221 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6226 destroy : function(){
6228 this.store.un('beforeload', this.onBeforeLoad, this);
6229 this.store.un('load', this.onLoad, this);
6230 this.store.un('loadexception', this.onLoadException, this);
6232 var um = this.el.getUpdateManager();
6233 um.un('beforeupdate', this.onBeforeLoad, this);
6234 um.un('update', this.onLoad, this);
6235 um.un('failure', this.onLoad, this);
6246 * @class Roo.bootstrap.Table
6247 * @extends Roo.bootstrap.Component
6248 * Bootstrap Table class
6249 * @cfg {String} cls table class
6250 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6251 * @cfg {String} bgcolor Specifies the background color for a table
6252 * @cfg {Number} border Specifies whether the table cells should have borders or not
6253 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6254 * @cfg {Number} cellspacing Specifies the space between cells
6255 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6256 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6257 * @cfg {String} sortable Specifies that the table should be sortable
6258 * @cfg {String} summary Specifies a summary of the content of a table
6259 * @cfg {Number} width Specifies the width of a table
6260 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6262 * @cfg {boolean} striped Should the rows be alternative striped
6263 * @cfg {boolean} bordered Add borders to the table
6264 * @cfg {boolean} hover Add hover highlighting
6265 * @cfg {boolean} condensed Format condensed
6266 * @cfg {boolean} responsive Format condensed
6267 * @cfg {Boolean} loadMask (true|false) default false
6268 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6269 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6270 * @cfg {Boolean} rowSelection (true|false) default false
6271 * @cfg {Boolean} cellSelection (true|false) default false
6272 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6273 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6274 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6275 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6279 * Create a new Table
6280 * @param {Object} config The config object
6283 Roo.bootstrap.Table = function(config){
6284 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6289 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6290 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6291 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6292 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6294 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6296 this.sm.grid = this;
6297 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6298 this.sm = this.selModel;
6299 this.sm.xmodule = this.xmodule || false;
6302 if (this.cm && typeof(this.cm.config) == 'undefined') {
6303 this.colModel = new Roo.grid.ColumnModel(this.cm);
6304 this.cm = this.colModel;
6305 this.cm.xmodule = this.xmodule || false;
6308 this.store= Roo.factory(this.store, Roo.data);
6309 this.ds = this.store;
6310 this.ds.xmodule = this.xmodule || false;
6313 if (this.footer && this.store) {
6314 this.footer.dataSource = this.ds;
6315 this.footer = Roo.factory(this.footer);
6322 * Fires when a cell is clicked
6323 * @param {Roo.bootstrap.Table} this
6324 * @param {Roo.Element} el
6325 * @param {Number} rowIndex
6326 * @param {Number} columnIndex
6327 * @param {Roo.EventObject} e
6331 * @event celldblclick
6332 * Fires when a cell is double clicked
6333 * @param {Roo.bootstrap.Table} this
6334 * @param {Roo.Element} el
6335 * @param {Number} rowIndex
6336 * @param {Number} columnIndex
6337 * @param {Roo.EventObject} e
6339 "celldblclick" : true,
6342 * Fires when a row is clicked
6343 * @param {Roo.bootstrap.Table} this
6344 * @param {Roo.Element} el
6345 * @param {Number} rowIndex
6346 * @param {Roo.EventObject} e
6350 * @event rowdblclick
6351 * Fires when a row is double clicked
6352 * @param {Roo.bootstrap.Table} this
6353 * @param {Roo.Element} el
6354 * @param {Number} rowIndex
6355 * @param {Roo.EventObject} e
6357 "rowdblclick" : true,
6360 * Fires when a mouseover occur
6361 * @param {Roo.bootstrap.Table} this
6362 * @param {Roo.Element} el
6363 * @param {Number} rowIndex
6364 * @param {Number} columnIndex
6365 * @param {Roo.EventObject} e
6370 * Fires when a mouseout occur
6371 * @param {Roo.bootstrap.Table} this
6372 * @param {Roo.Element} el
6373 * @param {Number} rowIndex
6374 * @param {Number} columnIndex
6375 * @param {Roo.EventObject} e
6380 * Fires when a row is rendered, so you can change add a style to it.
6381 * @param {Roo.bootstrap.Table} this
6382 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6386 * @event rowsrendered
6387 * Fires when all the rows have been rendered
6388 * @param {Roo.bootstrap.Table} this
6390 'rowsrendered' : true,
6392 * @event contextmenu
6393 * The raw contextmenu event for the entire grid.
6394 * @param {Roo.EventObject} e
6396 "contextmenu" : true,
6398 * @event rowcontextmenu
6399 * Fires when a row is right clicked
6400 * @param {Roo.bootstrap.Table} this
6401 * @param {Number} rowIndex
6402 * @param {Roo.EventObject} e
6404 "rowcontextmenu" : true,
6406 * @event cellcontextmenu
6407 * Fires when a cell is right clicked
6408 * @param {Roo.bootstrap.Table} this
6409 * @param {Number} rowIndex
6410 * @param {Number} cellIndex
6411 * @param {Roo.EventObject} e
6413 "cellcontextmenu" : true,
6415 * @event headercontextmenu
6416 * Fires when a header is right clicked
6417 * @param {Roo.bootstrap.Table} this
6418 * @param {Number} columnIndex
6419 * @param {Roo.EventObject} e
6421 "headercontextmenu" : true
6425 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6451 rowSelection : false,
6452 cellSelection : false,
6455 // Roo.Element - the tbody
6457 // Roo.Element - thead element
6460 container: false, // used by gridpanel...
6466 auto_hide_footer : false,
6468 getAutoCreate : function()
6470 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6477 if (this.scrollBody) {
6478 cfg.cls += ' table-body-fixed';
6481 cfg.cls += ' table-striped';
6485 cfg.cls += ' table-hover';
6487 if (this.bordered) {
6488 cfg.cls += ' table-bordered';
6490 if (this.condensed) {
6491 cfg.cls += ' table-condensed';
6493 if (this.responsive) {
6494 cfg.cls += ' table-responsive';
6498 cfg.cls+= ' ' +this.cls;
6501 // this lot should be simplifed...
6514 ].forEach(function(k) {
6522 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6525 if(this.store || this.cm){
6526 if(this.headerShow){
6527 cfg.cn.push(this.renderHeader());
6530 cfg.cn.push(this.renderBody());
6532 if(this.footerShow){
6533 cfg.cn.push(this.renderFooter());
6535 // where does this come from?
6536 //cfg.cls+= ' TableGrid';
6539 return { cn : [ cfg ] };
6542 initEvents : function()
6544 if(!this.store || !this.cm){
6547 if (this.selModel) {
6548 this.selModel.initEvents();
6552 //Roo.log('initEvents with ds!!!!');
6554 this.mainBody = this.el.select('tbody', true).first();
6555 this.mainHead = this.el.select('thead', true).first();
6556 this.mainFoot = this.el.select('tfoot', true).first();
6562 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6563 e.on('click', _this.sort, _this);
6566 this.mainBody.on("click", this.onClick, this);
6567 this.mainBody.on("dblclick", this.onDblClick, this);
6569 // why is this done????? = it breaks dialogs??
6570 //this.parent().el.setStyle('position', 'relative');
6574 this.footer.parentId = this.id;
6575 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6578 this.el.select('tfoot tr td').first().addClass('hide');
6583 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6586 this.store.on('load', this.onLoad, this);
6587 this.store.on('beforeload', this.onBeforeLoad, this);
6588 this.store.on('update', this.onUpdate, this);
6589 this.store.on('add', this.onAdd, this);
6590 this.store.on("clear", this.clear, this);
6592 this.el.on("contextmenu", this.onContextMenu, this);
6594 this.mainBody.on('scroll', this.onBodyScroll, this);
6596 this.cm.on("headerchange", this.onHeaderChange, this);
6598 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6602 onContextMenu : function(e, t)
6604 this.processEvent("contextmenu", e);
6607 processEvent : function(name, e)
6609 if (name != 'touchstart' ) {
6610 this.fireEvent(name, e);
6613 var t = e.getTarget();
6615 var cell = Roo.get(t);
6621 if(cell.findParent('tfoot', false, true)){
6625 if(cell.findParent('thead', false, true)){
6627 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6628 cell = Roo.get(t).findParent('th', false, true);
6630 Roo.log("failed to find th in thead?");
6631 Roo.log(e.getTarget());
6636 var cellIndex = cell.dom.cellIndex;
6638 var ename = name == 'touchstart' ? 'click' : name;
6639 this.fireEvent("header" + ename, this, cellIndex, e);
6644 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6645 cell = Roo.get(t).findParent('td', false, true);
6647 Roo.log("failed to find th in tbody?");
6648 Roo.log(e.getTarget());
6653 var row = cell.findParent('tr', false, true);
6654 var cellIndex = cell.dom.cellIndex;
6655 var rowIndex = row.dom.rowIndex - 1;
6659 this.fireEvent("row" + name, this, rowIndex, e);
6663 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6669 onMouseover : function(e, el)
6671 var cell = Roo.get(el);
6677 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6678 cell = cell.findParent('td', false, true);
6681 var row = cell.findParent('tr', false, true);
6682 var cellIndex = cell.dom.cellIndex;
6683 var rowIndex = row.dom.rowIndex - 1; // start from 0
6685 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6689 onMouseout : function(e, el)
6691 var cell = Roo.get(el);
6697 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6698 cell = cell.findParent('td', false, true);
6701 var row = cell.findParent('tr', false, true);
6702 var cellIndex = cell.dom.cellIndex;
6703 var rowIndex = row.dom.rowIndex - 1; // start from 0
6705 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6709 onClick : function(e, el)
6711 var cell = Roo.get(el);
6713 if(!cell || (!this.cellSelection && !this.rowSelection)){
6717 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6718 cell = cell.findParent('td', false, true);
6721 if(!cell || typeof(cell) == 'undefined'){
6725 var row = cell.findParent('tr', false, true);
6727 if(!row || typeof(row) == 'undefined'){
6731 var cellIndex = cell.dom.cellIndex;
6732 var rowIndex = this.getRowIndex(row);
6734 // why??? - should these not be based on SelectionModel?
6735 if(this.cellSelection){
6736 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6739 if(this.rowSelection){
6740 this.fireEvent('rowclick', this, row, rowIndex, e);
6746 onDblClick : function(e,el)
6748 var cell = Roo.get(el);
6750 if(!cell || (!this.cellSelection && !this.rowSelection)){
6754 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6755 cell = cell.findParent('td', false, true);
6758 if(!cell || typeof(cell) == 'undefined'){
6762 var row = cell.findParent('tr', false, true);
6764 if(!row || typeof(row) == 'undefined'){
6768 var cellIndex = cell.dom.cellIndex;
6769 var rowIndex = this.getRowIndex(row);
6771 if(this.cellSelection){
6772 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6775 if(this.rowSelection){
6776 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6780 sort : function(e,el)
6782 var col = Roo.get(el);
6784 if(!col.hasClass('sortable')){
6788 var sort = col.attr('sort');
6791 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6795 this.store.sortInfo = {field : sort, direction : dir};
6798 Roo.log("calling footer first");
6799 this.footer.onClick('first');
6802 this.store.load({ params : { start : 0 } });
6806 renderHeader : function()
6814 this.totalWidth = 0;
6816 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6818 var config = cm.config[i];
6822 cls : 'x-hcol-' + i,
6824 html: cm.getColumnHeader(i)
6829 if(typeof(config.sortable) != 'undefined' && config.sortable){
6831 c.html = '<i class="glyphicon"></i>' + c.html;
6834 // could use BS4 hidden-..-down
6836 if(typeof(config.lgHeader) != 'undefined'){
6837 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6840 if(typeof(config.mdHeader) != 'undefined'){
6841 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6844 if(typeof(config.smHeader) != 'undefined'){
6845 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6848 if(typeof(config.xsHeader) != 'undefined'){
6849 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6856 if(typeof(config.tooltip) != 'undefined'){
6857 c.tooltip = config.tooltip;
6860 if(typeof(config.colspan) != 'undefined'){
6861 c.colspan = config.colspan;
6864 if(typeof(config.hidden) != 'undefined' && config.hidden){
6865 c.style += ' display:none;';
6868 if(typeof(config.dataIndex) != 'undefined'){
6869 c.sort = config.dataIndex;
6874 if(typeof(config.align) != 'undefined' && config.align.length){
6875 c.style += ' text-align:' + config.align + ';';
6878 if(typeof(config.width) != 'undefined'){
6879 c.style += ' width:' + config.width + 'px;';
6880 this.totalWidth += config.width;
6882 this.totalWidth += 100; // assume minimum of 100 per column?
6885 if(typeof(config.cls) != 'undefined'){
6886 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6889 ['xs','sm','md','lg'].map(function(size){
6891 if(typeof(config[size]) == 'undefined'){
6895 if (!config[size]) { // 0 = hidden
6896 // BS 4 '0' is treated as hide that column and below.
6897 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6901 c.cls += ' col-' + size + '-' + config[size] + (
6902 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6914 renderBody : function()
6924 colspan : this.cm.getColumnCount()
6934 renderFooter : function()
6944 colspan : this.cm.getColumnCount()
6958 // Roo.log('ds onload');
6963 var ds = this.store;
6965 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6966 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6967 if (_this.store.sortInfo) {
6969 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6970 e.select('i', true).addClass(['glyphicon-arrow-up']);
6973 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6974 e.select('i', true).addClass(['glyphicon-arrow-down']);
6979 var tbody = this.mainBody;
6981 if(ds.getCount() > 0){
6982 ds.data.each(function(d,rowIndex){
6983 var row = this.renderRow(cm, ds, rowIndex);
6985 tbody.createChild(row);
6989 if(row.cellObjects.length){
6990 Roo.each(row.cellObjects, function(r){
6991 _this.renderCellObject(r);
6998 var tfoot = this.el.select('tfoot', true).first();
7000 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7002 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7004 var total = this.ds.getTotalCount();
7006 if(this.footer.pageSize < total){
7007 this.mainFoot.show();
7011 Roo.each(this.el.select('tbody td', true).elements, function(e){
7012 e.on('mouseover', _this.onMouseover, _this);
7015 Roo.each(this.el.select('tbody td', true).elements, function(e){
7016 e.on('mouseout', _this.onMouseout, _this);
7018 this.fireEvent('rowsrendered', this);
7024 onUpdate : function(ds,record)
7026 this.refreshRow(record);
7030 onRemove : function(ds, record, index, isUpdate){
7031 if(isUpdate !== true){
7032 this.fireEvent("beforerowremoved", this, index, record);
7034 var bt = this.mainBody.dom;
7036 var rows = this.el.select('tbody > tr', true).elements;
7038 if(typeof(rows[index]) != 'undefined'){
7039 bt.removeChild(rows[index].dom);
7042 // if(bt.rows[index]){
7043 // bt.removeChild(bt.rows[index]);
7046 if(isUpdate !== true){
7047 //this.stripeRows(index);
7048 //this.syncRowHeights(index, index);
7050 this.fireEvent("rowremoved", this, index, record);
7054 onAdd : function(ds, records, rowIndex)
7056 //Roo.log('on Add called');
7057 // - note this does not handle multiple adding very well..
7058 var bt = this.mainBody.dom;
7059 for (var i =0 ; i < records.length;i++) {
7060 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7061 //Roo.log(records[i]);
7062 //Roo.log(this.store.getAt(rowIndex+i));
7063 this.insertRow(this.store, rowIndex + i, false);
7070 refreshRow : function(record){
7071 var ds = this.store, index;
7072 if(typeof record == 'number'){
7074 record = ds.getAt(index);
7076 index = ds.indexOf(record);
7078 this.insertRow(ds, index, true);
7080 this.onRemove(ds, record, index+1, true);
7082 //this.syncRowHeights(index, index);
7084 this.fireEvent("rowupdated", this, index, record);
7087 insertRow : function(dm, rowIndex, isUpdate){
7090 this.fireEvent("beforerowsinserted", this, rowIndex);
7092 //var s = this.getScrollState();
7093 var row = this.renderRow(this.cm, this.store, rowIndex);
7094 // insert before rowIndex..
7095 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7099 if(row.cellObjects.length){
7100 Roo.each(row.cellObjects, function(r){
7101 _this.renderCellObject(r);
7106 this.fireEvent("rowsinserted", this, rowIndex);
7107 //this.syncRowHeights(firstRow, lastRow);
7108 //this.stripeRows(firstRow);
7115 getRowDom : function(rowIndex)
7117 var rows = this.el.select('tbody > tr', true).elements;
7119 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7122 // returns the object tree for a tr..
7125 renderRow : function(cm, ds, rowIndex)
7127 var d = ds.getAt(rowIndex);
7131 cls : 'x-row-' + rowIndex,
7135 var cellObjects = [];
7137 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7138 var config = cm.config[i];
7140 var renderer = cm.getRenderer(i);
7144 if(typeof(renderer) !== 'undefined'){
7145 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7147 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7148 // and are rendered into the cells after the row is rendered - using the id for the element.
7150 if(typeof(value) === 'object'){
7160 rowIndex : rowIndex,
7165 this.fireEvent('rowclass', this, rowcfg);
7169 cls : rowcfg.rowClass + ' x-col-' + i,
7171 html: (typeof(value) === 'object') ? '' : value
7178 if(typeof(config.colspan) != 'undefined'){
7179 td.colspan = config.colspan;
7182 if(typeof(config.hidden) != 'undefined' && config.hidden){
7183 td.style += ' display:none;';
7186 if(typeof(config.align) != 'undefined' && config.align.length){
7187 td.style += ' text-align:' + config.align + ';';
7189 if(typeof(config.valign) != 'undefined' && config.valign.length){
7190 td.style += ' vertical-align:' + config.valign + ';';
7193 if(typeof(config.width) != 'undefined'){
7194 td.style += ' width:' + config.width + 'px;';
7197 if(typeof(config.cursor) != 'undefined'){
7198 td.style += ' cursor:' + config.cursor + ';';
7201 if(typeof(config.cls) != 'undefined'){
7202 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7205 ['xs','sm','md','lg'].map(function(size){
7207 if(typeof(config[size]) == 'undefined'){
7213 if (!config[size]) { // 0 = hidden
7214 // BS 4 '0' is treated as hide that column and below.
7215 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7219 td.cls += ' col-' + size + '-' + config[size] + (
7220 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7230 row.cellObjects = cellObjects;
7238 onBeforeLoad : function()
7247 this.el.select('tbody', true).first().dom.innerHTML = '';
7250 * Show or hide a row.
7251 * @param {Number} rowIndex to show or hide
7252 * @param {Boolean} state hide
7254 setRowVisibility : function(rowIndex, state)
7256 var bt = this.mainBody.dom;
7258 var rows = this.el.select('tbody > tr', true).elements;
7260 if(typeof(rows[rowIndex]) == 'undefined'){
7263 rows[rowIndex].dom.style.display = state ? '' : 'none';
7267 getSelectionModel : function(){
7269 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7271 return this.selModel;
7274 * Render the Roo.bootstrap object from renderder
7276 renderCellObject : function(r)
7280 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7282 var t = r.cfg.render(r.container);
7285 Roo.each(r.cfg.cn, function(c){
7287 container: t.getChildContainer(),
7290 _this.renderCellObject(child);
7295 getRowIndex : function(row)
7299 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7310 * Returns the grid's underlying element = used by panel.Grid
7311 * @return {Element} The element
7313 getGridEl : function(){
7317 * Forces a resize - used by panel.Grid
7318 * @return {Element} The element
7320 autoSize : function()
7322 //var ctr = Roo.get(this.container.dom.parentElement);
7323 var ctr = Roo.get(this.el.dom);
7325 var thd = this.getGridEl().select('thead',true).first();
7326 var tbd = this.getGridEl().select('tbody', true).first();
7327 var tfd = this.getGridEl().select('tfoot', true).first();
7329 var cw = ctr.getWidth();
7333 tbd.setSize(ctr.getWidth(),
7334 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7336 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7339 cw = Math.max(cw, this.totalWidth);
7340 this.getGridEl().select('tr',true).setWidth(cw);
7341 // resize 'expandable coloumn?
7343 return; // we doe not have a view in this design..
7346 onBodyScroll: function()
7348 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7350 this.mainHead.setStyle({
7351 'position' : 'relative',
7352 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7358 var scrollHeight = this.mainBody.dom.scrollHeight;
7360 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7362 var height = this.mainBody.getHeight();
7364 if(scrollHeight - height == scrollTop) {
7366 var total = this.ds.getTotalCount();
7368 if(this.footer.cursor + this.footer.pageSize < total){
7370 this.footer.ds.load({
7372 start : this.footer.cursor + this.footer.pageSize,
7373 limit : this.footer.pageSize
7383 onHeaderChange : function()
7385 var header = this.renderHeader();
7386 var table = this.el.select('table', true).first();
7388 this.mainHead.remove();
7389 this.mainHead = table.createChild(header, this.mainBody, false);
7392 onHiddenChange : function(colModel, colIndex, hidden)
7394 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7395 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7397 this.CSS.updateRule(thSelector, "display", "");
7398 this.CSS.updateRule(tdSelector, "display", "");
7401 this.CSS.updateRule(thSelector, "display", "none");
7402 this.CSS.updateRule(tdSelector, "display", "none");
7405 this.onHeaderChange();
7409 setColumnWidth: function(col_index, width)
7411 // width = "md-2 xs-2..."
7412 if(!this.colModel.config[col_index]) {
7416 var w = width.split(" ");
7418 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7420 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7423 for(var j = 0; j < w.length; j++) {
7429 var size_cls = w[j].split("-");
7431 if(!Number.isInteger(size_cls[1] * 1)) {
7435 if(!this.colModel.config[col_index][size_cls[0]]) {
7439 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7443 h_row[0].classList.replace(
7444 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7445 "col-"+size_cls[0]+"-"+size_cls[1]
7448 for(var i = 0; i < rows.length; i++) {
7450 var size_cls = w[j].split("-");
7452 if(!Number.isInteger(size_cls[1] * 1)) {
7456 if(!this.colModel.config[col_index][size_cls[0]]) {
7460 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7464 rows[i].classList.replace(
7465 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7466 "col-"+size_cls[0]+"-"+size_cls[1]
7470 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7485 * @class Roo.bootstrap.TableCell
7486 * @extends Roo.bootstrap.Component
7487 * Bootstrap TableCell class
7488 * @cfg {String} html cell contain text
7489 * @cfg {String} cls cell class
7490 * @cfg {String} tag cell tag (td|th) default td
7491 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7492 * @cfg {String} align Aligns the content in a cell
7493 * @cfg {String} axis Categorizes cells
7494 * @cfg {String} bgcolor Specifies the background color of a cell
7495 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7496 * @cfg {Number} colspan Specifies the number of columns a cell should span
7497 * @cfg {String} headers Specifies one or more header cells a cell is related to
7498 * @cfg {Number} height Sets the height of a cell
7499 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7500 * @cfg {Number} rowspan Sets the number of rows a cell should span
7501 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7502 * @cfg {String} valign Vertical aligns the content in a cell
7503 * @cfg {Number} width Specifies the width of a cell
7506 * Create a new TableCell
7507 * @param {Object} config The config object
7510 Roo.bootstrap.TableCell = function(config){
7511 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7514 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7534 getAutoCreate : function(){
7535 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7555 cfg.align=this.align
7561 cfg.bgcolor=this.bgcolor
7564 cfg.charoff=this.charoff
7567 cfg.colspan=this.colspan
7570 cfg.headers=this.headers
7573 cfg.height=this.height
7576 cfg.nowrap=this.nowrap
7579 cfg.rowspan=this.rowspan
7582 cfg.scope=this.scope
7585 cfg.valign=this.valign
7588 cfg.width=this.width
7607 * @class Roo.bootstrap.TableRow
7608 * @extends Roo.bootstrap.Component
7609 * Bootstrap TableRow class
7610 * @cfg {String} cls row class
7611 * @cfg {String} align Aligns the content in a table row
7612 * @cfg {String} bgcolor Specifies a background color for a table row
7613 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7614 * @cfg {String} valign Vertical aligns the content in a table row
7617 * Create a new TableRow
7618 * @param {Object} config The config object
7621 Roo.bootstrap.TableRow = function(config){
7622 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7625 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7633 getAutoCreate : function(){
7634 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7644 cfg.align = this.align;
7647 cfg.bgcolor = this.bgcolor;
7650 cfg.charoff = this.charoff;
7653 cfg.valign = this.valign;
7671 * @class Roo.bootstrap.TableBody
7672 * @extends Roo.bootstrap.Component
7673 * Bootstrap TableBody class
7674 * @cfg {String} cls element class
7675 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7676 * @cfg {String} align Aligns the content inside the element
7677 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7678 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7681 * Create a new TableBody
7682 * @param {Object} config The config object
7685 Roo.bootstrap.TableBody = function(config){
7686 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7689 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7697 getAutoCreate : function(){
7698 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7712 cfg.align = this.align;
7715 cfg.charoff = this.charoff;
7718 cfg.valign = this.valign;
7725 // initEvents : function()
7732 // this.store = Roo.factory(this.store, Roo.data);
7733 // this.store.on('load', this.onLoad, this);
7735 // this.store.load();
7739 // onLoad: function ()
7741 // this.fireEvent('load', this);
7751 * Ext JS Library 1.1.1
7752 * Copyright(c) 2006-2007, Ext JS, LLC.
7754 * Originally Released Under LGPL - original licence link has changed is not relivant.
7757 * <script type="text/javascript">
7760 // as we use this in bootstrap.
7761 Roo.namespace('Roo.form');
7763 * @class Roo.form.Action
7764 * Internal Class used to handle form actions
7766 * @param {Roo.form.BasicForm} el The form element or its id
7767 * @param {Object} config Configuration options
7772 // define the action interface
7773 Roo.form.Action = function(form, options){
7775 this.options = options || {};
7778 * Client Validation Failed
7781 Roo.form.Action.CLIENT_INVALID = 'client';
7783 * Server Validation Failed
7786 Roo.form.Action.SERVER_INVALID = 'server';
7788 * Connect to Server Failed
7791 Roo.form.Action.CONNECT_FAILURE = 'connect';
7793 * Reading Data from Server Failed
7796 Roo.form.Action.LOAD_FAILURE = 'load';
7798 Roo.form.Action.prototype = {
7800 failureType : undefined,
7801 response : undefined,
7805 run : function(options){
7810 success : function(response){
7815 handleResponse : function(response){
7819 // default connection failure
7820 failure : function(response){
7822 this.response = response;
7823 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7824 this.form.afterAction(this, false);
7827 processResponse : function(response){
7828 this.response = response;
7829 if(!response.responseText){
7832 this.result = this.handleResponse(response);
7836 // utility functions used internally
7837 getUrl : function(appendParams){
7838 var url = this.options.url || this.form.url || this.form.el.dom.action;
7840 var p = this.getParams();
7842 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7848 getMethod : function(){
7849 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7852 getParams : function(){
7853 var bp = this.form.baseParams;
7854 var p = this.options.params;
7856 if(typeof p == "object"){
7857 p = Roo.urlEncode(Roo.applyIf(p, bp));
7858 }else if(typeof p == 'string' && bp){
7859 p += '&' + Roo.urlEncode(bp);
7862 p = Roo.urlEncode(bp);
7867 createCallback : function(){
7869 success: this.success,
7870 failure: this.failure,
7872 timeout: (this.form.timeout*1000),
7873 upload: this.form.fileUpload ? this.success : undefined
7878 Roo.form.Action.Submit = function(form, options){
7879 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7882 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7885 haveProgress : false,
7886 uploadComplete : false,
7888 // uploadProgress indicator.
7889 uploadProgress : function()
7891 if (!this.form.progressUrl) {
7895 if (!this.haveProgress) {
7896 Roo.MessageBox.progress("Uploading", "Uploading");
7898 if (this.uploadComplete) {
7899 Roo.MessageBox.hide();
7903 this.haveProgress = true;
7905 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7907 var c = new Roo.data.Connection();
7909 url : this.form.progressUrl,
7914 success : function(req){
7915 //console.log(data);
7919 rdata = Roo.decode(req.responseText)
7921 Roo.log("Invalid data from server..");
7925 if (!rdata || !rdata.success) {
7927 Roo.MessageBox.alert(Roo.encode(rdata));
7930 var data = rdata.data;
7932 if (this.uploadComplete) {
7933 Roo.MessageBox.hide();
7938 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7939 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7942 this.uploadProgress.defer(2000,this);
7945 failure: function(data) {
7946 Roo.log('progress url failed ');
7957 // run get Values on the form, so it syncs any secondary forms.
7958 this.form.getValues();
7960 var o = this.options;
7961 var method = this.getMethod();
7962 var isPost = method == 'POST';
7963 if(o.clientValidation === false || this.form.isValid()){
7965 if (this.form.progressUrl) {
7966 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7967 (new Date() * 1) + '' + Math.random());
7972 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7973 form:this.form.el.dom,
7974 url:this.getUrl(!isPost),
7976 params:isPost ? this.getParams() : null,
7977 isUpload: this.form.fileUpload,
7978 formData : this.form.formData
7981 this.uploadProgress();
7983 }else if (o.clientValidation !== false){ // client validation failed
7984 this.failureType = Roo.form.Action.CLIENT_INVALID;
7985 this.form.afterAction(this, false);
7989 success : function(response)
7991 this.uploadComplete= true;
7992 if (this.haveProgress) {
7993 Roo.MessageBox.hide();
7997 var result = this.processResponse(response);
7998 if(result === true || result.success){
7999 this.form.afterAction(this, true);
8003 this.form.markInvalid(result.errors);
8004 this.failureType = Roo.form.Action.SERVER_INVALID;
8006 this.form.afterAction(this, false);
8008 failure : function(response)
8010 this.uploadComplete= true;
8011 if (this.haveProgress) {
8012 Roo.MessageBox.hide();
8015 this.response = response;
8016 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8017 this.form.afterAction(this, false);
8020 handleResponse : function(response){
8021 if(this.form.errorReader){
8022 var rs = this.form.errorReader.read(response);
8025 for(var i = 0, len = rs.records.length; i < len; i++) {
8026 var r = rs.records[i];
8030 if(errors.length < 1){
8034 success : rs.success,
8040 ret = Roo.decode(response.responseText);
8044 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8054 Roo.form.Action.Load = function(form, options){
8055 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8056 this.reader = this.form.reader;
8059 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8064 Roo.Ajax.request(Roo.apply(
8065 this.createCallback(), {
8066 method:this.getMethod(),
8067 url:this.getUrl(false),
8068 params:this.getParams()
8072 success : function(response){
8074 var result = this.processResponse(response);
8075 if(result === true || !result.success || !result.data){
8076 this.failureType = Roo.form.Action.LOAD_FAILURE;
8077 this.form.afterAction(this, false);
8080 this.form.clearInvalid();
8081 this.form.setValues(result.data);
8082 this.form.afterAction(this, true);
8085 handleResponse : function(response){
8086 if(this.form.reader){
8087 var rs = this.form.reader.read(response);
8088 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8090 success : rs.success,
8094 return Roo.decode(response.responseText);
8098 Roo.form.Action.ACTION_TYPES = {
8099 'load' : Roo.form.Action.Load,
8100 'submit' : Roo.form.Action.Submit
8109 * @class Roo.bootstrap.Form
8110 * @extends Roo.bootstrap.Component
8111 * Bootstrap Form class
8112 * @cfg {String} method GET | POST (default POST)
8113 * @cfg {String} labelAlign top | left (default top)
8114 * @cfg {String} align left | right - for navbars
8115 * @cfg {Boolean} loadMask load mask when submit (default true)
8120 * @param {Object} config The config object
8124 Roo.bootstrap.Form = function(config){
8126 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8128 Roo.bootstrap.Form.popover.apply();
8132 * @event clientvalidation
8133 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8134 * @param {Form} this
8135 * @param {Boolean} valid true if the form has passed client-side validation
8137 clientvalidation: true,
8139 * @event beforeaction
8140 * Fires before any action is performed. Return false to cancel the action.
8141 * @param {Form} this
8142 * @param {Action} action The action to be performed
8146 * @event actionfailed
8147 * Fires when an action fails.
8148 * @param {Form} this
8149 * @param {Action} action The action that failed
8151 actionfailed : true,
8153 * @event actioncomplete
8154 * Fires when an action is completed.
8155 * @param {Form} this
8156 * @param {Action} action The action that completed
8158 actioncomplete : true
8162 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8165 * @cfg {String} method
8166 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8171 * The URL to use for form actions if one isn't supplied in the action options.
8174 * @cfg {Boolean} fileUpload
8175 * Set to true if this form is a file upload.
8179 * @cfg {Object} baseParams
8180 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8184 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8188 * @cfg {Sting} align (left|right) for navbar forms
8193 activeAction : null,
8196 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8197 * element by passing it or its id or mask the form itself by passing in true.
8200 waitMsgTarget : false,
8205 * @cfg {Boolean} errorMask (true|false) default false
8210 * @cfg {Number} maskOffset Default 100
8215 * @cfg {Boolean} maskBody
8219 getAutoCreate : function(){
8223 method : this.method || 'POST',
8224 id : this.id || Roo.id(),
8227 if (this.parent().xtype.match(/^Nav/)) {
8228 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8232 if (this.labelAlign == 'left' ) {
8233 cfg.cls += ' form-horizontal';
8239 initEvents : function()
8241 this.el.on('submit', this.onSubmit, this);
8242 // this was added as random key presses on the form where triggering form submit.
8243 this.el.on('keypress', function(e) {
8244 if (e.getCharCode() != 13) {
8247 // we might need to allow it for textareas.. and some other items.
8248 // check e.getTarget().
8250 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8254 Roo.log("keypress blocked");
8262 onSubmit : function(e){
8267 * Returns true if client-side validation on the form is successful.
8270 isValid : function(){
8271 var items = this.getItems();
8275 items.each(function(f){
8281 Roo.log('invalid field: ' + f.name);
8285 if(!target && f.el.isVisible(true)){
8291 if(this.errorMask && !valid){
8292 Roo.bootstrap.Form.popover.mask(this, target);
8299 * Returns true if any fields in this form have changed since their original load.
8302 isDirty : function(){
8304 var items = this.getItems();
8305 items.each(function(f){
8315 * Performs a predefined action (submit or load) or custom actions you define on this form.
8316 * @param {String} actionName The name of the action type
8317 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8318 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8319 * accept other config options):
8321 Property Type Description
8322 ---------------- --------------- ----------------------------------------------------------------------------------
8323 url String The url for the action (defaults to the form's url)
8324 method String The form method to use (defaults to the form's method, or POST if not defined)
8325 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8326 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8327 validate the form on the client (defaults to false)
8329 * @return {BasicForm} this
8331 doAction : function(action, options){
8332 if(typeof action == 'string'){
8333 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8335 if(this.fireEvent('beforeaction', this, action) !== false){
8336 this.beforeAction(action);
8337 action.run.defer(100, action);
8343 beforeAction : function(action){
8344 var o = action.options;
8349 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8351 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8354 // not really supported yet.. ??
8356 //if(this.waitMsgTarget === true){
8357 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8358 //}else if(this.waitMsgTarget){
8359 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8360 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8362 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8368 afterAction : function(action, success){
8369 this.activeAction = null;
8370 var o = action.options;
8375 Roo.get(document.body).unmask();
8381 //if(this.waitMsgTarget === true){
8382 // this.el.unmask();
8383 //}else if(this.waitMsgTarget){
8384 // this.waitMsgTarget.unmask();
8386 // Roo.MessageBox.updateProgress(1);
8387 // Roo.MessageBox.hide();
8394 Roo.callback(o.success, o.scope, [this, action]);
8395 this.fireEvent('actioncomplete', this, action);
8399 // failure condition..
8400 // we have a scenario where updates need confirming.
8401 // eg. if a locking scenario exists..
8402 // we look for { errors : { needs_confirm : true }} in the response.
8404 (typeof(action.result) != 'undefined') &&
8405 (typeof(action.result.errors) != 'undefined') &&
8406 (typeof(action.result.errors.needs_confirm) != 'undefined')
8409 Roo.log("not supported yet");
8412 Roo.MessageBox.confirm(
8413 "Change requires confirmation",
8414 action.result.errorMsg,
8419 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8429 Roo.callback(o.failure, o.scope, [this, action]);
8430 // show an error message if no failed handler is set..
8431 if (!this.hasListener('actionfailed')) {
8432 Roo.log("need to add dialog support");
8434 Roo.MessageBox.alert("Error",
8435 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8436 action.result.errorMsg :
8437 "Saving Failed, please check your entries or try again"
8442 this.fireEvent('actionfailed', this, action);
8447 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8448 * @param {String} id The value to search for
8451 findField : function(id){
8452 var items = this.getItems();
8453 var field = items.get(id);
8455 items.each(function(f){
8456 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8463 return field || null;
8466 * Mark fields in this form invalid in bulk.
8467 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8468 * @return {BasicForm} this
8470 markInvalid : function(errors){
8471 if(errors instanceof Array){
8472 for(var i = 0, len = errors.length; i < len; i++){
8473 var fieldError = errors[i];
8474 var f = this.findField(fieldError.id);
8476 f.markInvalid(fieldError.msg);
8482 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8483 field.markInvalid(errors[id]);
8487 //Roo.each(this.childForms || [], function (f) {
8488 // f.markInvalid(errors);
8495 * Set values for fields in this form in bulk.
8496 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8497 * @return {BasicForm} this
8499 setValues : function(values){
8500 if(values instanceof Array){ // array of objects
8501 for(var i = 0, len = values.length; i < len; i++){
8503 var f = this.findField(v.id);
8505 f.setValue(v.value);
8506 if(this.trackResetOnLoad){
8507 f.originalValue = f.getValue();
8511 }else{ // object hash
8514 if(typeof values[id] != 'function' && (field = this.findField(id))){
8516 if (field.setFromData &&
8518 field.displayField &&
8519 // combos' with local stores can
8520 // be queried via setValue()
8521 // to set their value..
8522 (field.store && !field.store.isLocal)
8526 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8527 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8528 field.setFromData(sd);
8530 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8532 field.setFromData(values);
8535 field.setValue(values[id]);
8539 if(this.trackResetOnLoad){
8540 field.originalValue = field.getValue();
8546 //Roo.each(this.childForms || [], function (f) {
8547 // f.setValues(values);
8554 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8555 * they are returned as an array.
8556 * @param {Boolean} asString
8559 getValues : function(asString){
8560 //if (this.childForms) {
8561 // copy values from the child forms
8562 // Roo.each(this.childForms, function (f) {
8563 // this.setValues(f.getValues());
8569 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8570 if(asString === true){
8573 return Roo.urlDecode(fs);
8577 * Returns the fields in this form as an object with key/value pairs.
8578 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8581 getFieldValues : function(with_hidden)
8583 var items = this.getItems();
8585 items.each(function(f){
8591 var v = f.getValue();
8593 if (f.inputType =='radio') {
8594 if (typeof(ret[f.getName()]) == 'undefined') {
8595 ret[f.getName()] = ''; // empty..
8598 if (!f.el.dom.checked) {
8606 if(f.xtype == 'MoneyField'){
8607 ret[f.currencyName] = f.getCurrency();
8610 // not sure if this supported any more..
8611 if ((typeof(v) == 'object') && f.getRawValue) {
8612 v = f.getRawValue() ; // dates..
8614 // combo boxes where name != hiddenName...
8615 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8616 ret[f.name] = f.getRawValue();
8618 ret[f.getName()] = v;
8625 * Clears all invalid messages in this form.
8626 * @return {BasicForm} this
8628 clearInvalid : function(){
8629 var items = this.getItems();
8631 items.each(function(f){
8640 * @return {BasicForm} this
8643 var items = this.getItems();
8644 items.each(function(f){
8648 Roo.each(this.childForms || [], function (f) {
8656 getItems : function()
8658 var r=new Roo.util.MixedCollection(false, function(o){
8659 return o.id || (o.id = Roo.id());
8661 var iter = function(el) {
8668 Roo.each(el.items,function(e) {
8677 hideFields : function(items)
8679 Roo.each(items, function(i){
8681 var f = this.findField(i);
8692 showFields : function(items)
8694 Roo.each(items, function(i){
8696 var f = this.findField(i);
8709 Roo.apply(Roo.bootstrap.Form, {
8736 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8737 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8738 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8739 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8742 this.maskEl.top.enableDisplayMode("block");
8743 this.maskEl.left.enableDisplayMode("block");
8744 this.maskEl.bottom.enableDisplayMode("block");
8745 this.maskEl.right.enableDisplayMode("block");
8747 this.toolTip = new Roo.bootstrap.Tooltip({
8748 cls : 'roo-form-error-popover',
8750 'left' : ['r-l', [-2,0], 'right'],
8751 'right' : ['l-r', [2,0], 'left'],
8752 'bottom' : ['tl-bl', [0,2], 'top'],
8753 'top' : [ 'bl-tl', [0,-2], 'bottom']
8757 this.toolTip.render(Roo.get(document.body));
8759 this.toolTip.el.enableDisplayMode("block");
8761 Roo.get(document.body).on('click', function(){
8765 Roo.get(document.body).on('touchstart', function(){
8769 this.isApplied = true
8772 mask : function(form, target)
8776 this.target = target;
8778 if(!this.form.errorMask || !target.el){
8782 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8784 Roo.log(scrollable);
8786 var ot = this.target.el.calcOffsetsTo(scrollable);
8788 var scrollTo = ot[1] - this.form.maskOffset;
8790 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8792 scrollable.scrollTo('top', scrollTo);
8794 var box = this.target.el.getBox();
8796 var zIndex = Roo.bootstrap.Modal.zIndex++;
8799 this.maskEl.top.setStyle('position', 'absolute');
8800 this.maskEl.top.setStyle('z-index', zIndex);
8801 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8802 this.maskEl.top.setLeft(0);
8803 this.maskEl.top.setTop(0);
8804 this.maskEl.top.show();
8806 this.maskEl.left.setStyle('position', 'absolute');
8807 this.maskEl.left.setStyle('z-index', zIndex);
8808 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8809 this.maskEl.left.setLeft(0);
8810 this.maskEl.left.setTop(box.y - this.padding);
8811 this.maskEl.left.show();
8813 this.maskEl.bottom.setStyle('position', 'absolute');
8814 this.maskEl.bottom.setStyle('z-index', zIndex);
8815 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8816 this.maskEl.bottom.setLeft(0);
8817 this.maskEl.bottom.setTop(box.bottom + this.padding);
8818 this.maskEl.bottom.show();
8820 this.maskEl.right.setStyle('position', 'absolute');
8821 this.maskEl.right.setStyle('z-index', zIndex);
8822 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8823 this.maskEl.right.setLeft(box.right + this.padding);
8824 this.maskEl.right.setTop(box.y - this.padding);
8825 this.maskEl.right.show();
8827 this.toolTip.bindEl = this.target.el;
8829 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8831 var tip = this.target.blankText;
8833 if(this.target.getValue() !== '' ) {
8835 if (this.target.invalidText.length) {
8836 tip = this.target.invalidText;
8837 } else if (this.target.regexText.length){
8838 tip = this.target.regexText;
8842 this.toolTip.show(tip);
8844 this.intervalID = window.setInterval(function() {
8845 Roo.bootstrap.Form.popover.unmask();
8848 window.onwheel = function(){ return false;};
8850 (function(){ this.isMasked = true; }).defer(500, this);
8856 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8860 this.maskEl.top.setStyle('position', 'absolute');
8861 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8862 this.maskEl.top.hide();
8864 this.maskEl.left.setStyle('position', 'absolute');
8865 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8866 this.maskEl.left.hide();
8868 this.maskEl.bottom.setStyle('position', 'absolute');
8869 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8870 this.maskEl.bottom.hide();
8872 this.maskEl.right.setStyle('position', 'absolute');
8873 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8874 this.maskEl.right.hide();
8876 this.toolTip.hide();
8878 this.toolTip.el.hide();
8880 window.onwheel = function(){ return true;};
8882 if(this.intervalID){
8883 window.clearInterval(this.intervalID);
8884 this.intervalID = false;
8887 this.isMasked = false;
8897 * Ext JS Library 1.1.1
8898 * Copyright(c) 2006-2007, Ext JS, LLC.
8900 * Originally Released Under LGPL - original licence link has changed is not relivant.
8903 * <script type="text/javascript">
8906 * @class Roo.form.VTypes
8907 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8910 Roo.form.VTypes = function(){
8911 // closure these in so they are only created once.
8912 var alpha = /^[a-zA-Z_]+$/;
8913 var alphanum = /^[a-zA-Z0-9_]+$/;
8914 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8915 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8917 // All these messages and functions are configurable
8920 * The function used to validate email addresses
8921 * @param {String} value The email address
8923 'email' : function(v){
8924 return email.test(v);
8927 * The error text to display when the email validation function returns false
8930 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8932 * The keystroke filter mask to be applied on email input
8935 'emailMask' : /[a-z0-9_\.\-@]/i,
8938 * The function used to validate URLs
8939 * @param {String} value The URL
8941 'url' : function(v){
8945 * The error text to display when the url validation function returns false
8948 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8951 * The function used to validate alpha values
8952 * @param {String} value The value
8954 'alpha' : function(v){
8955 return alpha.test(v);
8958 * The error text to display when the alpha validation function returns false
8961 'alphaText' : 'This field should only contain letters and _',
8963 * The keystroke filter mask to be applied on alpha input
8966 'alphaMask' : /[a-z_]/i,
8969 * The function used to validate alphanumeric values
8970 * @param {String} value The value
8972 'alphanum' : function(v){
8973 return alphanum.test(v);
8976 * The error text to display when the alphanumeric validation function returns false
8979 'alphanumText' : 'This field should only contain letters, numbers and _',
8981 * The keystroke filter mask to be applied on alphanumeric input
8984 'alphanumMask' : /[a-z0-9_]/i
8994 * @class Roo.bootstrap.Input
8995 * @extends Roo.bootstrap.Component
8996 * Bootstrap Input class
8997 * @cfg {Boolean} disabled is it disabled
8998 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8999 * @cfg {String} name name of the input
9000 * @cfg {string} fieldLabel - the label associated
9001 * @cfg {string} placeholder - placeholder to put in text.
9002 * @cfg {string} before - input group add on before
9003 * @cfg {string} after - input group add on after
9004 * @cfg {string} size - (lg|sm) or leave empty..
9005 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9006 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9007 * @cfg {Number} md colspan out of 12 for computer-sized screens
9008 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9009 * @cfg {string} value default value of the input
9010 * @cfg {Number} labelWidth set the width of label
9011 * @cfg {Number} labellg set the width of label (1-12)
9012 * @cfg {Number} labelmd set the width of label (1-12)
9013 * @cfg {Number} labelsm set the width of label (1-12)
9014 * @cfg {Number} labelxs set the width of label (1-12)
9015 * @cfg {String} labelAlign (top|left)
9016 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9017 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9018 * @cfg {String} indicatorpos (left|right) default left
9019 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9020 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9022 * @cfg {String} align (left|center|right) Default left
9023 * @cfg {Boolean} forceFeedback (true|false) Default false
9026 * Create a new Input
9027 * @param {Object} config The config object
9030 Roo.bootstrap.Input = function(config){
9032 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9037 * Fires when this field receives input focus.
9038 * @param {Roo.form.Field} this
9043 * Fires when this field loses input focus.
9044 * @param {Roo.form.Field} this
9049 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9050 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9051 * @param {Roo.form.Field} this
9052 * @param {Roo.EventObject} e The event object
9057 * Fires just before the field blurs if the field value has changed.
9058 * @param {Roo.form.Field} this
9059 * @param {Mixed} newValue The new value
9060 * @param {Mixed} oldValue The original value
9065 * Fires after the field has been marked as invalid.
9066 * @param {Roo.form.Field} this
9067 * @param {String} msg The validation message
9072 * Fires after the field has been validated with no errors.
9073 * @param {Roo.form.Field} this
9078 * Fires after the key up
9079 * @param {Roo.form.Field} this
9080 * @param {Roo.EventObject} e The event Object
9086 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9088 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9089 automatic validation (defaults to "keyup").
9091 validationEvent : "keyup",
9093 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9095 validateOnBlur : true,
9097 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9099 validationDelay : 250,
9101 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9103 focusClass : "x-form-focus", // not needed???
9107 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9109 invalidClass : "has-warning",
9112 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9114 validClass : "has-success",
9117 * @cfg {Boolean} hasFeedback (true|false) default true
9122 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9124 invalidFeedbackClass : "glyphicon-warning-sign",
9127 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9129 validFeedbackClass : "glyphicon-ok",
9132 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9134 selectOnFocus : false,
9137 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9141 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9146 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9148 disableKeyFilter : false,
9151 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9155 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9159 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9161 blankText : "Please complete this mandatory field",
9164 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9168 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9170 maxLength : Number.MAX_VALUE,
9172 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9174 minLengthText : "The minimum length for this field is {0}",
9176 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9178 maxLengthText : "The maximum length for this field is {0}",
9182 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9183 * If available, this function will be called only after the basic validators all return true, and will be passed the
9184 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9188 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9189 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9190 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9194 * @cfg {String} regexText -- Depricated - use Invalid Text
9199 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9205 autocomplete: false,
9224 formatedValue : false,
9225 forceFeedback : false,
9227 indicatorpos : 'left',
9237 parentLabelAlign : function()
9240 while (parent.parent()) {
9241 parent = parent.parent();
9242 if (typeof(parent.labelAlign) !='undefined') {
9243 return parent.labelAlign;
9250 getAutoCreate : function()
9252 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9258 if(this.inputType != 'hidden'){
9259 cfg.cls = 'form-group' //input-group
9265 type : this.inputType,
9267 cls : 'form-control',
9268 placeholder : this.placeholder || '',
9269 autocomplete : this.autocomplete || 'new-password'
9272 if(this.capture.length){
9273 input.capture = this.capture;
9276 if(this.accept.length){
9277 input.accept = this.accept + "/*";
9281 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9284 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9285 input.maxLength = this.maxLength;
9288 if (this.disabled) {
9289 input.disabled=true;
9292 if (this.readOnly) {
9293 input.readonly=true;
9297 input.name = this.name;
9301 input.cls += ' input-' + this.size;
9305 ['xs','sm','md','lg'].map(function(size){
9306 if (settings[size]) {
9307 cfg.cls += ' col-' + size + '-' + settings[size];
9311 var inputblock = input;
9315 cls: 'glyphicon form-control-feedback'
9318 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9321 cls : 'has-feedback',
9329 if (this.before || this.after) {
9332 cls : 'input-group',
9336 if (this.before && typeof(this.before) == 'string') {
9338 inputblock.cn.push({
9340 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9344 if (this.before && typeof(this.before) == 'object') {
9345 this.before = Roo.factory(this.before);
9347 inputblock.cn.push({
9349 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9350 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9354 inputblock.cn.push(input);
9356 if (this.after && typeof(this.after) == 'string') {
9357 inputblock.cn.push({
9359 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9363 if (this.after && typeof(this.after) == 'object') {
9364 this.after = Roo.factory(this.after);
9366 inputblock.cn.push({
9368 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9369 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9373 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9374 inputblock.cls += ' has-feedback';
9375 inputblock.cn.push(feedback);
9380 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9381 tooltip : 'This field is required'
9383 if (Roo.bootstrap.version == 4) {
9386 style : 'display-none'
9389 if (align ==='left' && this.fieldLabel.length) {
9391 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9398 cls : 'control-label col-form-label',
9399 html : this.fieldLabel
9410 var labelCfg = cfg.cn[1];
9411 var contentCfg = cfg.cn[2];
9413 if(this.indicatorpos == 'right'){
9418 cls : 'control-label col-form-label',
9422 html : this.fieldLabel
9436 labelCfg = cfg.cn[0];
9437 contentCfg = cfg.cn[1];
9441 if(this.labelWidth > 12){
9442 labelCfg.style = "width: " + this.labelWidth + 'px';
9445 if(this.labelWidth < 13 && this.labelmd == 0){
9446 this.labelmd = this.labelWidth;
9449 if(this.labellg > 0){
9450 labelCfg.cls += ' col-lg-' + this.labellg;
9451 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9454 if(this.labelmd > 0){
9455 labelCfg.cls += ' col-md-' + this.labelmd;
9456 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9459 if(this.labelsm > 0){
9460 labelCfg.cls += ' col-sm-' + this.labelsm;
9461 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9464 if(this.labelxs > 0){
9465 labelCfg.cls += ' col-xs-' + this.labelxs;
9466 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9470 } else if ( this.fieldLabel.length) {
9475 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9476 tooltip : 'This field is required'
9480 //cls : 'input-group-addon',
9481 html : this.fieldLabel
9489 if(this.indicatorpos == 'right'){
9494 //cls : 'input-group-addon',
9495 html : this.fieldLabel
9500 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9501 tooltip : 'This field is required'
9521 if (this.parentType === 'Navbar' && this.parent().bar) {
9522 cfg.cls += ' navbar-form';
9525 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9526 // on BS4 we do this only if not form
9527 cfg.cls += ' navbar-form';
9535 * return the real input element.
9537 inputEl: function ()
9539 return this.el.select('input.form-control',true).first();
9542 tooltipEl : function()
9544 return this.inputEl();
9547 indicatorEl : function()
9549 if (Roo.bootstrap.version == 4) {
9550 return false; // not enabled in v4 yet.
9553 var indicator = this.el.select('i.roo-required-indicator',true).first();
9563 setDisabled : function(v)
9565 var i = this.inputEl().dom;
9567 i.removeAttribute('disabled');
9571 i.setAttribute('disabled','true');
9573 initEvents : function()
9576 this.inputEl().on("keydown" , this.fireKey, this);
9577 this.inputEl().on("focus", this.onFocus, this);
9578 this.inputEl().on("blur", this.onBlur, this);
9580 this.inputEl().relayEvent('keyup', this);
9582 this.indicator = this.indicatorEl();
9585 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9588 // reference to original value for reset
9589 this.originalValue = this.getValue();
9590 //Roo.form.TextField.superclass.initEvents.call(this);
9591 if(this.validationEvent == 'keyup'){
9592 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9593 this.inputEl().on('keyup', this.filterValidation, this);
9595 else if(this.validationEvent !== false){
9596 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9599 if(this.selectOnFocus){
9600 this.on("focus", this.preFocus, this);
9603 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9604 this.inputEl().on("keypress", this.filterKeys, this);
9606 this.inputEl().relayEvent('keypress', this);
9609 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9610 this.el.on("click", this.autoSize, this);
9613 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9614 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9617 if (typeof(this.before) == 'object') {
9618 this.before.render(this.el.select('.roo-input-before',true).first());
9620 if (typeof(this.after) == 'object') {
9621 this.after.render(this.el.select('.roo-input-after',true).first());
9624 this.inputEl().on('change', this.onChange, this);
9627 filterValidation : function(e){
9628 if(!e.isNavKeyPress()){
9629 this.validationTask.delay(this.validationDelay);
9633 * Validates the field value
9634 * @return {Boolean} True if the value is valid, else false
9636 validate : function(){
9637 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9638 if(this.disabled || this.validateValue(this.getRawValue())){
9649 * Validates a value according to the field's validation rules and marks the field as invalid
9650 * if the validation fails
9651 * @param {Mixed} value The value to validate
9652 * @return {Boolean} True if the value is valid, else false
9654 validateValue : function(value)
9656 if(this.getVisibilityEl().hasClass('hidden')){
9660 if(value.length < 1) { // if it's blank
9661 if(this.allowBlank){
9667 if(value.length < this.minLength){
9670 if(value.length > this.maxLength){
9674 var vt = Roo.form.VTypes;
9675 if(!vt[this.vtype](value, this)){
9679 if(typeof this.validator == "function"){
9680 var msg = this.validator(value);
9684 if (typeof(msg) == 'string') {
9685 this.invalidText = msg;
9689 if(this.regex && !this.regex.test(value)){
9697 fireKey : function(e){
9698 //Roo.log('field ' + e.getKey());
9699 if(e.isNavKeyPress()){
9700 this.fireEvent("specialkey", this, e);
9703 focus : function (selectText){
9705 this.inputEl().focus();
9706 if(selectText === true){
9707 this.inputEl().dom.select();
9713 onFocus : function(){
9714 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9715 // this.el.addClass(this.focusClass);
9718 this.hasFocus = true;
9719 this.startValue = this.getValue();
9720 this.fireEvent("focus", this);
9724 beforeBlur : Roo.emptyFn,
9728 onBlur : function(){
9730 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9731 //this.el.removeClass(this.focusClass);
9733 this.hasFocus = false;
9734 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9737 var v = this.getValue();
9738 if(String(v) !== String(this.startValue)){
9739 this.fireEvent('change', this, v, this.startValue);
9741 this.fireEvent("blur", this);
9744 onChange : function(e)
9746 var v = this.getValue();
9747 if(String(v) !== String(this.startValue)){
9748 this.fireEvent('change', this, v, this.startValue);
9754 * Resets the current field value to the originally loaded value and clears any validation messages
9757 this.setValue(this.originalValue);
9761 * Returns the name of the field
9762 * @return {Mixed} name The name field
9764 getName: function(){
9768 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9769 * @return {Mixed} value The field value
9771 getValue : function(){
9773 var v = this.inputEl().getValue();
9778 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9779 * @return {Mixed} value The field value
9781 getRawValue : function(){
9782 var v = this.inputEl().getValue();
9788 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9789 * @param {Mixed} value The value to set
9791 setRawValue : function(v){
9792 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9795 selectText : function(start, end){
9796 var v = this.getRawValue();
9798 start = start === undefined ? 0 : start;
9799 end = end === undefined ? v.length : end;
9800 var d = this.inputEl().dom;
9801 if(d.setSelectionRange){
9802 d.setSelectionRange(start, end);
9803 }else if(d.createTextRange){
9804 var range = d.createTextRange();
9805 range.moveStart("character", start);
9806 range.moveEnd("character", v.length-end);
9813 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9814 * @param {Mixed} value The value to set
9816 setValue : function(v){
9819 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9825 processValue : function(value){
9826 if(this.stripCharsRe){
9827 var newValue = value.replace(this.stripCharsRe, '');
9828 if(newValue !== value){
9829 this.setRawValue(newValue);
9836 preFocus : function(){
9838 if(this.selectOnFocus){
9839 this.inputEl().dom.select();
9842 filterKeys : function(e){
9844 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9847 var c = e.getCharCode(), cc = String.fromCharCode(c);
9848 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9851 if(!this.maskRe.test(cc)){
9856 * Clear any invalid styles/messages for this field
9858 clearInvalid : function(){
9860 if(!this.el || this.preventMark){ // not rendered
9865 this.el.removeClass([this.invalidClass, 'is-invalid']);
9867 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9869 var feedback = this.el.select('.form-control-feedback', true).first();
9872 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9878 this.indicator.removeClass('visible');
9879 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9882 this.fireEvent('valid', this);
9886 * Mark this field as valid
9888 markValid : function()
9890 if(!this.el || this.preventMark){ // not rendered...
9894 this.el.removeClass([this.invalidClass, this.validClass]);
9895 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9897 var feedback = this.el.select('.form-control-feedback', true).first();
9900 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9904 this.indicator.removeClass('visible');
9905 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9912 if(this.allowBlank && !this.getRawValue().length){
9915 if (Roo.bootstrap.version == 3) {
9916 this.el.addClass(this.validClass);
9918 this.inputEl().addClass('is-valid');
9921 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9923 var feedback = this.el.select('.form-control-feedback', true).first();
9926 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9927 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9932 this.fireEvent('valid', this);
9936 * Mark this field as invalid
9937 * @param {String} msg The validation message
9939 markInvalid : function(msg)
9941 if(!this.el || this.preventMark){ // not rendered
9945 this.el.removeClass([this.invalidClass, this.validClass]);
9946 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9948 var feedback = this.el.select('.form-control-feedback', true).first();
9951 this.el.select('.form-control-feedback', true).first().removeClass(
9952 [this.invalidFeedbackClass, this.validFeedbackClass]);
9959 if(this.allowBlank && !this.getRawValue().length){
9964 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9965 this.indicator.addClass('visible');
9967 if (Roo.bootstrap.version == 3) {
9968 this.el.addClass(this.invalidClass);
9970 this.inputEl().addClass('is-invalid');
9975 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9977 var feedback = this.el.select('.form-control-feedback', true).first();
9980 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9982 if(this.getValue().length || this.forceFeedback){
9983 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9990 this.fireEvent('invalid', this, msg);
9993 SafariOnKeyDown : function(event)
9995 // this is a workaround for a password hang bug on chrome/ webkit.
9996 if (this.inputEl().dom.type != 'password') {
10000 var isSelectAll = false;
10002 if(this.inputEl().dom.selectionEnd > 0){
10003 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10005 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10006 event.preventDefault();
10011 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10013 event.preventDefault();
10014 // this is very hacky as keydown always get's upper case.
10016 var cc = String.fromCharCode(event.getCharCode());
10017 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10021 adjustWidth : function(tag, w){
10022 tag = tag.toLowerCase();
10023 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10024 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10025 if(tag == 'input'){
10028 if(tag == 'textarea'){
10031 }else if(Roo.isOpera){
10032 if(tag == 'input'){
10035 if(tag == 'textarea'){
10043 setFieldLabel : function(v)
10045 if(!this.rendered){
10049 if(this.indicatorEl()){
10050 var ar = this.el.select('label > span',true);
10052 if (ar.elements.length) {
10053 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10054 this.fieldLabel = v;
10058 var br = this.el.select('label',true);
10060 if(br.elements.length) {
10061 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10062 this.fieldLabel = v;
10066 Roo.log('Cannot Found any of label > span || label in input');
10070 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10071 this.fieldLabel = v;
10086 * @class Roo.bootstrap.TextArea
10087 * @extends Roo.bootstrap.Input
10088 * Bootstrap TextArea class
10089 * @cfg {Number} cols Specifies the visible width of a text area
10090 * @cfg {Number} rows Specifies the visible number of lines in a text area
10091 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10092 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10093 * @cfg {string} html text
10096 * Create a new TextArea
10097 * @param {Object} config The config object
10100 Roo.bootstrap.TextArea = function(config){
10101 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10105 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10115 getAutoCreate : function(){
10117 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10123 if(this.inputType != 'hidden'){
10124 cfg.cls = 'form-group' //input-group
10132 value : this.value || '',
10133 html: this.html || '',
10134 cls : 'form-control',
10135 placeholder : this.placeholder || ''
10139 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10140 input.maxLength = this.maxLength;
10144 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10148 input.cols = this.cols;
10151 if (this.readOnly) {
10152 input.readonly = true;
10156 input.name = this.name;
10160 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10164 ['xs','sm','md','lg'].map(function(size){
10165 if (settings[size]) {
10166 cfg.cls += ' col-' + size + '-' + settings[size];
10170 var inputblock = input;
10172 if(this.hasFeedback && !this.allowBlank){
10176 cls: 'glyphicon form-control-feedback'
10180 cls : 'has-feedback',
10189 if (this.before || this.after) {
10192 cls : 'input-group',
10196 inputblock.cn.push({
10198 cls : 'input-group-addon',
10203 inputblock.cn.push(input);
10205 if(this.hasFeedback && !this.allowBlank){
10206 inputblock.cls += ' has-feedback';
10207 inputblock.cn.push(feedback);
10211 inputblock.cn.push({
10213 cls : 'input-group-addon',
10220 if (align ==='left' && this.fieldLabel.length) {
10225 cls : 'control-label',
10226 html : this.fieldLabel
10237 if(this.labelWidth > 12){
10238 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10241 if(this.labelWidth < 13 && this.labelmd == 0){
10242 this.labelmd = this.labelWidth;
10245 if(this.labellg > 0){
10246 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10247 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10250 if(this.labelmd > 0){
10251 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10252 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10255 if(this.labelsm > 0){
10256 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10257 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10260 if(this.labelxs > 0){
10261 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10262 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10265 } else if ( this.fieldLabel.length) {
10270 //cls : 'input-group-addon',
10271 html : this.fieldLabel
10289 if (this.disabled) {
10290 input.disabled=true;
10297 * return the real textarea element.
10299 inputEl: function ()
10301 return this.el.select('textarea.form-control',true).first();
10305 * Clear any invalid styles/messages for this field
10307 clearInvalid : function()
10310 if(!this.el || this.preventMark){ // not rendered
10314 var label = this.el.select('label', true).first();
10315 var icon = this.el.select('i.fa-star', true).first();
10320 this.el.removeClass( this.validClass);
10321 this.inputEl().removeClass('is-invalid');
10323 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10325 var feedback = this.el.select('.form-control-feedback', true).first();
10328 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10333 this.fireEvent('valid', this);
10337 * Mark this field as valid
10339 markValid : function()
10341 if(!this.el || this.preventMark){ // not rendered
10345 this.el.removeClass([this.invalidClass, this.validClass]);
10346 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10348 var feedback = this.el.select('.form-control-feedback', true).first();
10351 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10354 if(this.disabled || this.allowBlank){
10358 var label = this.el.select('label', true).first();
10359 var icon = this.el.select('i.fa-star', true).first();
10364 if (Roo.bootstrap.version == 3) {
10365 this.el.addClass(this.validClass);
10367 this.inputEl().addClass('is-valid');
10371 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10373 var feedback = this.el.select('.form-control-feedback', true).first();
10376 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10377 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10382 this.fireEvent('valid', this);
10386 * Mark this field as invalid
10387 * @param {String} msg The validation message
10389 markInvalid : function(msg)
10391 if(!this.el || this.preventMark){ // not rendered
10395 this.el.removeClass([this.invalidClass, this.validClass]);
10396 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10398 var feedback = this.el.select('.form-control-feedback', true).first();
10401 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10404 if(this.disabled || this.allowBlank){
10408 var label = this.el.select('label', true).first();
10409 var icon = this.el.select('i.fa-star', true).first();
10411 if(!this.getValue().length && label && !icon){
10412 this.el.createChild({
10414 cls : 'text-danger fa fa-lg fa-star',
10415 tooltip : 'This field is required',
10416 style : 'margin-right:5px;'
10420 if (Roo.bootstrap.version == 3) {
10421 this.el.addClass(this.invalidClass);
10423 this.inputEl().addClass('is-invalid');
10426 // fixme ... this may be depricated need to test..
10427 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10429 var feedback = this.el.select('.form-control-feedback', true).first();
10432 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10434 if(this.getValue().length || this.forceFeedback){
10435 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10442 this.fireEvent('invalid', this, msg);
10450 * trigger field - base class for combo..
10455 * @class Roo.bootstrap.TriggerField
10456 * @extends Roo.bootstrap.Input
10457 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10458 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10459 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10460 * for which you can provide a custom implementation. For example:
10462 var trigger = new Roo.bootstrap.TriggerField();
10463 trigger.onTriggerClick = myTriggerFn;
10464 trigger.applyTo('my-field');
10467 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10468 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10469 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10470 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10471 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10474 * Create a new TriggerField.
10475 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10476 * to the base TextField)
10478 Roo.bootstrap.TriggerField = function(config){
10479 this.mimicing = false;
10480 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10483 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10485 * @cfg {String} triggerClass A CSS class to apply to the trigger
10488 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10493 * @cfg {Boolean} removable (true|false) special filter default false
10497 /** @cfg {Boolean} grow @hide */
10498 /** @cfg {Number} growMin @hide */
10499 /** @cfg {Number} growMax @hide */
10505 autoSize: Roo.emptyFn,
10509 deferHeight : true,
10512 actionMode : 'wrap',
10517 getAutoCreate : function(){
10519 var align = this.labelAlign || this.parentLabelAlign();
10524 cls: 'form-group' //input-group
10531 type : this.inputType,
10532 cls : 'form-control',
10533 autocomplete: 'new-password',
10534 placeholder : this.placeholder || ''
10538 input.name = this.name;
10541 input.cls += ' input-' + this.size;
10544 if (this.disabled) {
10545 input.disabled=true;
10548 var inputblock = input;
10550 if(this.hasFeedback && !this.allowBlank){
10554 cls: 'glyphicon form-control-feedback'
10557 if(this.removable && !this.editable && !this.tickable){
10559 cls : 'has-feedback',
10565 cls : 'roo-combo-removable-btn close'
10572 cls : 'has-feedback',
10581 if(this.removable && !this.editable && !this.tickable){
10583 cls : 'roo-removable',
10589 cls : 'roo-combo-removable-btn close'
10596 if (this.before || this.after) {
10599 cls : 'input-group',
10603 inputblock.cn.push({
10605 cls : 'input-group-addon input-group-prepend input-group-text',
10610 inputblock.cn.push(input);
10612 if(this.hasFeedback && !this.allowBlank){
10613 inputblock.cls += ' has-feedback';
10614 inputblock.cn.push(feedback);
10618 inputblock.cn.push({
10620 cls : 'input-group-addon input-group-append input-group-text',
10629 var ibwrap = inputblock;
10634 cls: 'roo-select2-choices',
10638 cls: 'roo-select2-search-field',
10650 cls: 'roo-select2-container input-group',
10655 cls: 'form-hidden-field'
10661 if(!this.multiple && this.showToggleBtn){
10667 if (this.caret != false) {
10670 cls: 'fa fa-' + this.caret
10677 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10679 Roo.bootstrap.version == 3 ? caret : '',
10682 cls: 'combobox-clear',
10696 combobox.cls += ' roo-select2-container-multi';
10700 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10701 tooltip : 'This field is required'
10703 if (Roo.bootstrap.version == 4) {
10706 style : 'display:none'
10711 if (align ==='left' && this.fieldLabel.length) {
10713 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10720 cls : 'control-label',
10721 html : this.fieldLabel
10733 var labelCfg = cfg.cn[1];
10734 var contentCfg = cfg.cn[2];
10736 if(this.indicatorpos == 'right'){
10741 cls : 'control-label',
10745 html : this.fieldLabel
10759 labelCfg = cfg.cn[0];
10760 contentCfg = cfg.cn[1];
10763 if(this.labelWidth > 12){
10764 labelCfg.style = "width: " + this.labelWidth + 'px';
10767 if(this.labelWidth < 13 && this.labelmd == 0){
10768 this.labelmd = this.labelWidth;
10771 if(this.labellg > 0){
10772 labelCfg.cls += ' col-lg-' + this.labellg;
10773 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10776 if(this.labelmd > 0){
10777 labelCfg.cls += ' col-md-' + this.labelmd;
10778 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10781 if(this.labelsm > 0){
10782 labelCfg.cls += ' col-sm-' + this.labelsm;
10783 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10786 if(this.labelxs > 0){
10787 labelCfg.cls += ' col-xs-' + this.labelxs;
10788 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10791 } else if ( this.fieldLabel.length) {
10792 // Roo.log(" label");
10797 //cls : 'input-group-addon',
10798 html : this.fieldLabel
10806 if(this.indicatorpos == 'right'){
10814 html : this.fieldLabel
10828 // Roo.log(" no label && no align");
10835 ['xs','sm','md','lg'].map(function(size){
10836 if (settings[size]) {
10837 cfg.cls += ' col-' + size + '-' + settings[size];
10848 onResize : function(w, h){
10849 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10850 // if(typeof w == 'number'){
10851 // var x = w - this.trigger.getWidth();
10852 // this.inputEl().setWidth(this.adjustWidth('input', x));
10853 // this.trigger.setStyle('left', x+'px');
10858 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10861 getResizeEl : function(){
10862 return this.inputEl();
10866 getPositionEl : function(){
10867 return this.inputEl();
10871 alignErrorIcon : function(){
10872 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10876 initEvents : function(){
10880 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10881 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10882 if(!this.multiple && this.showToggleBtn){
10883 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10884 if(this.hideTrigger){
10885 this.trigger.setDisplayed(false);
10887 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10891 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10894 if(this.removable && !this.editable && !this.tickable){
10895 var close = this.closeTriggerEl();
10898 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10899 close.on('click', this.removeBtnClick, this, close);
10903 //this.trigger.addClassOnOver('x-form-trigger-over');
10904 //this.trigger.addClassOnClick('x-form-trigger-click');
10907 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10911 closeTriggerEl : function()
10913 var close = this.el.select('.roo-combo-removable-btn', true).first();
10914 return close ? close : false;
10917 removeBtnClick : function(e, h, el)
10919 e.preventDefault();
10921 if(this.fireEvent("remove", this) !== false){
10923 this.fireEvent("afterremove", this)
10927 createList : function()
10929 this.list = Roo.get(document.body).createChild({
10930 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10931 cls: 'typeahead typeahead-long dropdown-menu',
10932 style: 'display:none'
10935 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10940 initTrigger : function(){
10945 onDestroy : function(){
10947 this.trigger.removeAllListeners();
10948 // this.trigger.remove();
10951 // this.wrap.remove();
10953 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10957 onFocus : function(){
10958 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10960 if(!this.mimicing){
10961 this.wrap.addClass('x-trigger-wrap-focus');
10962 this.mimicing = true;
10963 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10964 if(this.monitorTab){
10965 this.el.on("keydown", this.checkTab, this);
10972 checkTab : function(e){
10973 if(e.getKey() == e.TAB){
10974 this.triggerBlur();
10979 onBlur : function(){
10984 mimicBlur : function(e, t){
10986 if(!this.wrap.contains(t) && this.validateBlur()){
10987 this.triggerBlur();
10993 triggerBlur : function(){
10994 this.mimicing = false;
10995 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10996 if(this.monitorTab){
10997 this.el.un("keydown", this.checkTab, this);
10999 //this.wrap.removeClass('x-trigger-wrap-focus');
11000 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11004 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11005 validateBlur : function(e, t){
11010 onDisable : function(){
11011 this.inputEl().dom.disabled = true;
11012 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11014 // this.wrap.addClass('x-item-disabled');
11019 onEnable : function(){
11020 this.inputEl().dom.disabled = false;
11021 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11023 // this.el.removeClass('x-item-disabled');
11028 onShow : function(){
11029 var ae = this.getActionEl();
11032 ae.dom.style.display = '';
11033 ae.dom.style.visibility = 'visible';
11039 onHide : function(){
11040 var ae = this.getActionEl();
11041 ae.dom.style.display = 'none';
11045 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11046 * by an implementing function.
11048 * @param {EventObject} e
11050 onTriggerClick : Roo.emptyFn
11054 * Ext JS Library 1.1.1
11055 * Copyright(c) 2006-2007, Ext JS, LLC.
11057 * Originally Released Under LGPL - original licence link has changed is not relivant.
11060 * <script type="text/javascript">
11065 * @class Roo.data.SortTypes
11067 * Defines the default sorting (casting?) comparison functions used when sorting data.
11069 Roo.data.SortTypes = {
11071 * Default sort that does nothing
11072 * @param {Mixed} s The value being converted
11073 * @return {Mixed} The comparison value
11075 none : function(s){
11080 * The regular expression used to strip tags
11084 stripTagsRE : /<\/?[^>]+>/gi,
11087 * Strips all HTML tags to sort on text only
11088 * @param {Mixed} s The value being converted
11089 * @return {String} The comparison value
11091 asText : function(s){
11092 return String(s).replace(this.stripTagsRE, "");
11096 * Strips all HTML tags to sort on text only - Case insensitive
11097 * @param {Mixed} s The value being converted
11098 * @return {String} The comparison value
11100 asUCText : function(s){
11101 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11105 * Case insensitive string
11106 * @param {Mixed} s The value being converted
11107 * @return {String} The comparison value
11109 asUCString : function(s) {
11110 return String(s).toUpperCase();
11115 * @param {Mixed} s The value being converted
11116 * @return {Number} The comparison value
11118 asDate : function(s) {
11122 if(s instanceof Date){
11123 return s.getTime();
11125 return Date.parse(String(s));
11130 * @param {Mixed} s The value being converted
11131 * @return {Float} The comparison value
11133 asFloat : function(s) {
11134 var val = parseFloat(String(s).replace(/,/g, ""));
11143 * @param {Mixed} s The value being converted
11144 * @return {Number} The comparison value
11146 asInt : function(s) {
11147 var val = parseInt(String(s).replace(/,/g, ""));
11155 * Ext JS Library 1.1.1
11156 * Copyright(c) 2006-2007, Ext JS, LLC.
11158 * Originally Released Under LGPL - original licence link has changed is not relivant.
11161 * <script type="text/javascript">
11165 * @class Roo.data.Record
11166 * Instances of this class encapsulate both record <em>definition</em> information, and record
11167 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11168 * to access Records cached in an {@link Roo.data.Store} object.<br>
11170 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11171 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11174 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11176 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11177 * {@link #create}. The parameters are the same.
11178 * @param {Array} data An associative Array of data values keyed by the field name.
11179 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11180 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11181 * not specified an integer id is generated.
11183 Roo.data.Record = function(data, id){
11184 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11189 * Generate a constructor for a specific record layout.
11190 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11191 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11192 * Each field definition object may contain the following properties: <ul>
11193 * <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,
11194 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11195 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11196 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11197 * is being used, then this is a string containing the javascript expression to reference the data relative to
11198 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11199 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11200 * this may be omitted.</p></li>
11201 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11202 * <ul><li>auto (Default, implies no conversion)</li>
11207 * <li>date</li></ul></p></li>
11208 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11209 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11210 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11211 * by the Reader into an object that will be stored in the Record. It is passed the
11212 * following parameters:<ul>
11213 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11215 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11217 * <br>usage:<br><pre><code>
11218 var TopicRecord = Roo.data.Record.create(
11219 {name: 'title', mapping: 'topic_title'},
11220 {name: 'author', mapping: 'username'},
11221 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11222 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11223 {name: 'lastPoster', mapping: 'user2'},
11224 {name: 'excerpt', mapping: 'post_text'}
11227 var myNewRecord = new TopicRecord({
11228 title: 'Do my job please',
11231 lastPost: new Date(),
11232 lastPoster: 'Animal',
11233 excerpt: 'No way dude!'
11235 myStore.add(myNewRecord);
11240 Roo.data.Record.create = function(o){
11241 var f = function(){
11242 f.superclass.constructor.apply(this, arguments);
11244 Roo.extend(f, Roo.data.Record);
11245 var p = f.prototype;
11246 p.fields = new Roo.util.MixedCollection(false, function(field){
11249 for(var i = 0, len = o.length; i < len; i++){
11250 p.fields.add(new Roo.data.Field(o[i]));
11252 f.getField = function(name){
11253 return p.fields.get(name);
11258 Roo.data.Record.AUTO_ID = 1000;
11259 Roo.data.Record.EDIT = 'edit';
11260 Roo.data.Record.REJECT = 'reject';
11261 Roo.data.Record.COMMIT = 'commit';
11263 Roo.data.Record.prototype = {
11265 * Readonly flag - true if this record has been modified.
11274 join : function(store){
11275 this.store = store;
11279 * Set the named field to the specified value.
11280 * @param {String} name The name of the field to set.
11281 * @param {Object} value The value to set the field to.
11283 set : function(name, value){
11284 if(this.data[name] == value){
11288 if(!this.modified){
11289 this.modified = {};
11291 if(typeof this.modified[name] == 'undefined'){
11292 this.modified[name] = this.data[name];
11294 this.data[name] = value;
11295 if(!this.editing && this.store){
11296 this.store.afterEdit(this);
11301 * Get the value of the named field.
11302 * @param {String} name The name of the field to get the value of.
11303 * @return {Object} The value of the field.
11305 get : function(name){
11306 return this.data[name];
11310 beginEdit : function(){
11311 this.editing = true;
11312 this.modified = {};
11316 cancelEdit : function(){
11317 this.editing = false;
11318 delete this.modified;
11322 endEdit : function(){
11323 this.editing = false;
11324 if(this.dirty && this.store){
11325 this.store.afterEdit(this);
11330 * Usually called by the {@link Roo.data.Store} which owns the Record.
11331 * Rejects all changes made to the Record since either creation, or the last commit operation.
11332 * Modified fields are reverted to their original values.
11334 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11335 * of reject operations.
11337 reject : function(){
11338 var m = this.modified;
11340 if(typeof m[n] != "function"){
11341 this.data[n] = m[n];
11344 this.dirty = false;
11345 delete this.modified;
11346 this.editing = false;
11348 this.store.afterReject(this);
11353 * Usually called by the {@link Roo.data.Store} which owns the Record.
11354 * Commits all changes made to the Record since either creation, or the last commit operation.
11356 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11357 * of commit operations.
11359 commit : function(){
11360 this.dirty = false;
11361 delete this.modified;
11362 this.editing = false;
11364 this.store.afterCommit(this);
11369 hasError : function(){
11370 return this.error != null;
11374 clearError : function(){
11379 * Creates a copy of this record.
11380 * @param {String} id (optional) A new record id if you don't want to use this record's id
11383 copy : function(newId) {
11384 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11388 * Ext JS Library 1.1.1
11389 * Copyright(c) 2006-2007, Ext JS, LLC.
11391 * Originally Released Under LGPL - original licence link has changed is not relivant.
11394 * <script type="text/javascript">
11400 * @class Roo.data.Store
11401 * @extends Roo.util.Observable
11402 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11403 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11405 * 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
11406 * has no knowledge of the format of the data returned by the Proxy.<br>
11408 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11409 * instances from the data object. These records are cached and made available through accessor functions.
11411 * Creates a new Store.
11412 * @param {Object} config A config object containing the objects needed for the Store to access data,
11413 * and read the data into Records.
11415 Roo.data.Store = function(config){
11416 this.data = new Roo.util.MixedCollection(false);
11417 this.data.getKey = function(o){
11420 this.baseParams = {};
11422 this.paramNames = {
11427 "multisort" : "_multisort"
11430 if(config && config.data){
11431 this.inlineData = config.data;
11432 delete config.data;
11435 Roo.apply(this, config);
11437 if(this.reader){ // reader passed
11438 this.reader = Roo.factory(this.reader, Roo.data);
11439 this.reader.xmodule = this.xmodule || false;
11440 if(!this.recordType){
11441 this.recordType = this.reader.recordType;
11443 if(this.reader.onMetaChange){
11444 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11448 if(this.recordType){
11449 this.fields = this.recordType.prototype.fields;
11451 this.modified = [];
11455 * @event datachanged
11456 * Fires when the data cache has changed, and a widget which is using this Store
11457 * as a Record cache should refresh its view.
11458 * @param {Store} this
11460 datachanged : true,
11462 * @event metachange
11463 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11464 * @param {Store} this
11465 * @param {Object} meta The JSON metadata
11470 * Fires when Records have been added to the Store
11471 * @param {Store} this
11472 * @param {Roo.data.Record[]} records The array of Records added
11473 * @param {Number} index The index at which the record(s) were added
11478 * Fires when a Record has been removed from the Store
11479 * @param {Store} this
11480 * @param {Roo.data.Record} record The Record that was removed
11481 * @param {Number} index The index at which the record was removed
11486 * Fires when a Record has been updated
11487 * @param {Store} this
11488 * @param {Roo.data.Record} record The Record that was updated
11489 * @param {String} operation The update operation being performed. Value may be one of:
11491 Roo.data.Record.EDIT
11492 Roo.data.Record.REJECT
11493 Roo.data.Record.COMMIT
11499 * Fires when the data cache has been cleared.
11500 * @param {Store} this
11504 * @event beforeload
11505 * Fires before a request is made for a new data object. If the beforeload handler returns false
11506 * the load action will be canceled.
11507 * @param {Store} this
11508 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11512 * @event beforeloadadd
11513 * Fires after a new set of Records has been loaded.
11514 * @param {Store} this
11515 * @param {Roo.data.Record[]} records The Records that were loaded
11516 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11518 beforeloadadd : true,
11521 * Fires after a new set of Records has been loaded, before they are added to the store.
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)
11525 * @params {Object} return from reader
11529 * @event loadexception
11530 * Fires if an exception occurs in the Proxy during loading.
11531 * Called with the signature of the Proxy's "loadexception" event.
11532 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11535 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11536 * @param {Object} load options
11537 * @param {Object} jsonData from your request (normally this contains the Exception)
11539 loadexception : true
11543 this.proxy = Roo.factory(this.proxy, Roo.data);
11544 this.proxy.xmodule = this.xmodule || false;
11545 this.relayEvents(this.proxy, ["loadexception"]);
11547 this.sortToggle = {};
11548 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11550 Roo.data.Store.superclass.constructor.call(this);
11552 if(this.inlineData){
11553 this.loadData(this.inlineData);
11554 delete this.inlineData;
11558 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11560 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11561 * without a remote query - used by combo/forms at present.
11565 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11568 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11571 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11572 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11575 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11576 * on any HTTP request
11579 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11582 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11586 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11587 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11589 remoteSort : false,
11592 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11593 * loaded or when a record is removed. (defaults to false).
11595 pruneModifiedRecords : false,
11598 lastOptions : null,
11601 * Add Records to the Store and fires the add event.
11602 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11604 add : function(records){
11605 records = [].concat(records);
11606 for(var i = 0, len = records.length; i < len; i++){
11607 records[i].join(this);
11609 var index = this.data.length;
11610 this.data.addAll(records);
11611 this.fireEvent("add", this, records, index);
11615 * Remove a Record from the Store and fires the remove event.
11616 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11618 remove : function(record){
11619 var index = this.data.indexOf(record);
11620 this.data.removeAt(index);
11622 if(this.pruneModifiedRecords){
11623 this.modified.remove(record);
11625 this.fireEvent("remove", this, record, index);
11629 * Remove all Records from the Store and fires the clear event.
11631 removeAll : function(){
11633 if(this.pruneModifiedRecords){
11634 this.modified = [];
11636 this.fireEvent("clear", this);
11640 * Inserts Records to the Store at the given index and fires the add event.
11641 * @param {Number} index The start index at which to insert the passed Records.
11642 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11644 insert : function(index, records){
11645 records = [].concat(records);
11646 for(var i = 0, len = records.length; i < len; i++){
11647 this.data.insert(index, records[i]);
11648 records[i].join(this);
11650 this.fireEvent("add", this, records, index);
11654 * Get the index within the cache of the passed Record.
11655 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11656 * @return {Number} The index of the passed Record. Returns -1 if not found.
11658 indexOf : function(record){
11659 return this.data.indexOf(record);
11663 * Get the index within the cache of the Record with the passed id.
11664 * @param {String} id The id of the Record to find.
11665 * @return {Number} The index of the Record. Returns -1 if not found.
11667 indexOfId : function(id){
11668 return this.data.indexOfKey(id);
11672 * Get the Record with the specified id.
11673 * @param {String} id The id of the Record to find.
11674 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11676 getById : function(id){
11677 return this.data.key(id);
11681 * Get the Record at the specified index.
11682 * @param {Number} index The index of the Record to find.
11683 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11685 getAt : function(index){
11686 return this.data.itemAt(index);
11690 * Returns a range of Records between specified indices.
11691 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11692 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11693 * @return {Roo.data.Record[]} An array of Records
11695 getRange : function(start, end){
11696 return this.data.getRange(start, end);
11700 storeOptions : function(o){
11701 o = Roo.apply({}, o);
11704 this.lastOptions = o;
11708 * Loads the Record cache from the configured Proxy using the configured Reader.
11710 * If using remote paging, then the first load call must specify the <em>start</em>
11711 * and <em>limit</em> properties in the options.params property to establish the initial
11712 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11714 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11715 * and this call will return before the new data has been loaded. Perform any post-processing
11716 * in a callback function, or in a "load" event handler.</strong>
11718 * @param {Object} options An object containing properties which control loading options:<ul>
11719 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11720 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11721 * passed the following arguments:<ul>
11722 * <li>r : Roo.data.Record[]</li>
11723 * <li>options: Options object from the load call</li>
11724 * <li>success: Boolean success indicator</li></ul></li>
11725 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11726 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11729 load : function(options){
11730 options = options || {};
11731 if(this.fireEvent("beforeload", this, options) !== false){
11732 this.storeOptions(options);
11733 var p = Roo.apply(options.params || {}, this.baseParams);
11734 // if meta was not loaded from remote source.. try requesting it.
11735 if (!this.reader.metaFromRemote) {
11736 p._requestMeta = 1;
11738 if(this.sortInfo && this.remoteSort){
11739 var pn = this.paramNames;
11740 p[pn["sort"]] = this.sortInfo.field;
11741 p[pn["dir"]] = this.sortInfo.direction;
11743 if (this.multiSort) {
11744 var pn = this.paramNames;
11745 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11748 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11753 * Reloads the Record cache from the configured Proxy using the configured Reader and
11754 * the options from the last load operation performed.
11755 * @param {Object} options (optional) An object containing properties which may override the options
11756 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11757 * the most recently used options are reused).
11759 reload : function(options){
11760 this.load(Roo.applyIf(options||{}, this.lastOptions));
11764 // Called as a callback by the Reader during a load operation.
11765 loadRecords : function(o, options, success){
11766 if(!o || success === false){
11767 if(success !== false){
11768 this.fireEvent("load", this, [], options, o);
11770 if(options.callback){
11771 options.callback.call(options.scope || this, [], options, false);
11775 // if data returned failure - throw an exception.
11776 if (o.success === false) {
11777 // show a message if no listener is registered.
11778 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11779 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11781 // loadmask wil be hooked into this..
11782 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11785 var r = o.records, t = o.totalRecords || r.length;
11787 this.fireEvent("beforeloadadd", this, r, options, o);
11789 if(!options || options.add !== true){
11790 if(this.pruneModifiedRecords){
11791 this.modified = [];
11793 for(var i = 0, len = r.length; i < len; i++){
11797 this.data = this.snapshot;
11798 delete this.snapshot;
11801 this.data.addAll(r);
11802 this.totalLength = t;
11804 this.fireEvent("datachanged", this);
11806 this.totalLength = Math.max(t, this.data.length+r.length);
11810 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11812 var e = new Roo.data.Record({});
11814 e.set(this.parent.displayField, this.parent.emptyTitle);
11815 e.set(this.parent.valueField, '');
11820 this.fireEvent("load", this, r, options, o);
11821 if(options.callback){
11822 options.callback.call(options.scope || this, r, options, true);
11828 * Loads data from a passed data block. A Reader which understands the format of the data
11829 * must have been configured in the constructor.
11830 * @param {Object} data The data block from which to read the Records. The format of the data expected
11831 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11832 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11834 loadData : function(o, append){
11835 var r = this.reader.readRecords(o);
11836 this.loadRecords(r, {add: append}, true);
11840 * Gets the number of cached records.
11842 * <em>If using paging, this may not be the total size of the dataset. If the data object
11843 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11844 * the data set size</em>
11846 getCount : function(){
11847 return this.data.length || 0;
11851 * Gets the total number of records in the dataset as returned by the server.
11853 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11854 * the dataset size</em>
11856 getTotalCount : function(){
11857 return this.totalLength || 0;
11861 * Returns the sort state of the Store as an object with two properties:
11863 field {String} The name of the field by which the Records are sorted
11864 direction {String} The sort order, "ASC" or "DESC"
11867 getSortState : function(){
11868 return this.sortInfo;
11872 applySort : function(){
11873 if(this.sortInfo && !this.remoteSort){
11874 var s = this.sortInfo, f = s.field;
11875 var st = this.fields.get(f).sortType;
11876 var fn = function(r1, r2){
11877 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11878 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11880 this.data.sort(s.direction, fn);
11881 if(this.snapshot && this.snapshot != this.data){
11882 this.snapshot.sort(s.direction, fn);
11888 * Sets the default sort column and order to be used by the next load operation.
11889 * @param {String} fieldName The name of the field to sort by.
11890 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11892 setDefaultSort : function(field, dir){
11893 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11897 * Sort the Records.
11898 * If remote sorting is used, the sort is performed on the server, and the cache is
11899 * reloaded. If local sorting is used, the cache is sorted internally.
11900 * @param {String} fieldName The name of the field to sort by.
11901 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11903 sort : function(fieldName, dir){
11904 var f = this.fields.get(fieldName);
11906 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11908 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11909 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11914 this.sortToggle[f.name] = dir;
11915 this.sortInfo = {field: f.name, direction: dir};
11916 if(!this.remoteSort){
11918 this.fireEvent("datachanged", this);
11920 this.load(this.lastOptions);
11925 * Calls the specified function for each of the Records in the cache.
11926 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11927 * Returning <em>false</em> aborts and exits the iteration.
11928 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11930 each : function(fn, scope){
11931 this.data.each(fn, scope);
11935 * Gets all records modified since the last commit. Modified records are persisted across load operations
11936 * (e.g., during paging).
11937 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11939 getModifiedRecords : function(){
11940 return this.modified;
11944 createFilterFn : function(property, value, anyMatch){
11945 if(!value.exec){ // not a regex
11946 value = String(value);
11947 if(value.length == 0){
11950 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11952 return function(r){
11953 return value.test(r.data[property]);
11958 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11959 * @param {String} property A field on your records
11960 * @param {Number} start The record index to start at (defaults to 0)
11961 * @param {Number} end The last record index to include (defaults to length - 1)
11962 * @return {Number} The sum
11964 sum : function(property, start, end){
11965 var rs = this.data.items, v = 0;
11966 start = start || 0;
11967 end = (end || end === 0) ? end : rs.length-1;
11969 for(var i = start; i <= end; i++){
11970 v += (rs[i].data[property] || 0);
11976 * Filter the records by a specified property.
11977 * @param {String} field A field on your records
11978 * @param {String/RegExp} value Either a string that the field
11979 * should start with or a RegExp to test against the field
11980 * @param {Boolean} anyMatch True to match any part not just the beginning
11982 filter : function(property, value, anyMatch){
11983 var fn = this.createFilterFn(property, value, anyMatch);
11984 return fn ? this.filterBy(fn) : this.clearFilter();
11988 * Filter by a function. The specified function will be called with each
11989 * record in this data source. If the function returns true the record is included,
11990 * otherwise it is filtered.
11991 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11992 * @param {Object} scope (optional) The scope of the function (defaults to this)
11994 filterBy : function(fn, scope){
11995 this.snapshot = this.snapshot || this.data;
11996 this.data = this.queryBy(fn, scope||this);
11997 this.fireEvent("datachanged", this);
12001 * Query the records by a specified property.
12002 * @param {String} field A field on your records
12003 * @param {String/RegExp} value Either a string that the field
12004 * should start with or a RegExp to test against the field
12005 * @param {Boolean} anyMatch True to match any part not just the beginning
12006 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12008 query : function(property, value, anyMatch){
12009 var fn = this.createFilterFn(property, value, anyMatch);
12010 return fn ? this.queryBy(fn) : this.data.clone();
12014 * Query by a function. The specified function will be called with each
12015 * record in this data source. If the function returns true the record is included
12017 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12018 * @param {Object} scope (optional) The scope of the function (defaults to this)
12019 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12021 queryBy : function(fn, scope){
12022 var data = this.snapshot || this.data;
12023 return data.filterBy(fn, scope||this);
12027 * Collects unique values for a particular dataIndex from this store.
12028 * @param {String} dataIndex The property to collect
12029 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12030 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12031 * @return {Array} An array of the unique values
12033 collect : function(dataIndex, allowNull, bypassFilter){
12034 var d = (bypassFilter === true && this.snapshot) ?
12035 this.snapshot.items : this.data.items;
12036 var v, sv, r = [], l = {};
12037 for(var i = 0, len = d.length; i < len; i++){
12038 v = d[i].data[dataIndex];
12040 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12049 * Revert to a view of the Record cache with no filtering applied.
12050 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12052 clearFilter : function(suppressEvent){
12053 if(this.snapshot && this.snapshot != this.data){
12054 this.data = this.snapshot;
12055 delete this.snapshot;
12056 if(suppressEvent !== true){
12057 this.fireEvent("datachanged", this);
12063 afterEdit : function(record){
12064 if(this.modified.indexOf(record) == -1){
12065 this.modified.push(record);
12067 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12071 afterReject : function(record){
12072 this.modified.remove(record);
12073 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12077 afterCommit : function(record){
12078 this.modified.remove(record);
12079 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12083 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12084 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12086 commitChanges : function(){
12087 var m = this.modified.slice(0);
12088 this.modified = [];
12089 for(var i = 0, len = m.length; i < len; i++){
12095 * Cancel outstanding changes on all changed records.
12097 rejectChanges : function(){
12098 var m = this.modified.slice(0);
12099 this.modified = [];
12100 for(var i = 0, len = m.length; i < len; i++){
12105 onMetaChange : function(meta, rtype, o){
12106 this.recordType = rtype;
12107 this.fields = rtype.prototype.fields;
12108 delete this.snapshot;
12109 this.sortInfo = meta.sortInfo || this.sortInfo;
12110 this.modified = [];
12111 this.fireEvent('metachange', this, this.reader.meta);
12114 moveIndex : function(data, type)
12116 var index = this.indexOf(data);
12118 var newIndex = index + type;
12122 this.insert(newIndex, data);
12127 * Ext JS Library 1.1.1
12128 * Copyright(c) 2006-2007, Ext JS, LLC.
12130 * Originally Released Under LGPL - original licence link has changed is not relivant.
12133 * <script type="text/javascript">
12137 * @class Roo.data.SimpleStore
12138 * @extends Roo.data.Store
12139 * Small helper class to make creating Stores from Array data easier.
12140 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12141 * @cfg {Array} fields An array of field definition objects, or field name strings.
12142 * @cfg {Array} data The multi-dimensional array of data
12144 * @param {Object} config
12146 Roo.data.SimpleStore = function(config){
12147 Roo.data.SimpleStore.superclass.constructor.call(this, {
12149 reader: new Roo.data.ArrayReader({
12152 Roo.data.Record.create(config.fields)
12154 proxy : new Roo.data.MemoryProxy(config.data)
12158 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12160 * Ext JS Library 1.1.1
12161 * Copyright(c) 2006-2007, Ext JS, LLC.
12163 * Originally Released Under LGPL - original licence link has changed is not relivant.
12166 * <script type="text/javascript">
12171 * @extends Roo.data.Store
12172 * @class Roo.data.JsonStore
12173 * Small helper class to make creating Stores for JSON data easier. <br/>
12175 var store = new Roo.data.JsonStore({
12176 url: 'get-images.php',
12178 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12181 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12182 * JsonReader and HttpProxy (unless inline data is provided).</b>
12183 * @cfg {Array} fields An array of field definition objects, or field name strings.
12185 * @param {Object} config
12187 Roo.data.JsonStore = function(c){
12188 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12189 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12190 reader: new Roo.data.JsonReader(c, c.fields)
12193 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12195 * Ext JS Library 1.1.1
12196 * Copyright(c) 2006-2007, Ext JS, LLC.
12198 * Originally Released Under LGPL - original licence link has changed is not relivant.
12201 * <script type="text/javascript">
12205 Roo.data.Field = function(config){
12206 if(typeof config == "string"){
12207 config = {name: config};
12209 Roo.apply(this, config);
12212 this.type = "auto";
12215 var st = Roo.data.SortTypes;
12216 // named sortTypes are supported, here we look them up
12217 if(typeof this.sortType == "string"){
12218 this.sortType = st[this.sortType];
12221 // set default sortType for strings and dates
12222 if(!this.sortType){
12225 this.sortType = st.asUCString;
12228 this.sortType = st.asDate;
12231 this.sortType = st.none;
12236 var stripRe = /[\$,%]/g;
12238 // prebuilt conversion function for this field, instead of
12239 // switching every time we're reading a value
12241 var cv, dateFormat = this.dateFormat;
12246 cv = function(v){ return v; };
12249 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12253 return v !== undefined && v !== null && v !== '' ?
12254 parseInt(String(v).replace(stripRe, ""), 10) : '';
12259 return v !== undefined && v !== null && v !== '' ?
12260 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12265 cv = function(v){ return v === true || v === "true" || v == 1; };
12272 if(v instanceof Date){
12276 if(dateFormat == "timestamp"){
12277 return new Date(v*1000);
12279 return Date.parseDate(v, dateFormat);
12281 var parsed = Date.parse(v);
12282 return parsed ? new Date(parsed) : null;
12291 Roo.data.Field.prototype = {
12299 * Ext JS Library 1.1.1
12300 * Copyright(c) 2006-2007, Ext JS, LLC.
12302 * Originally Released Under LGPL - original licence link has changed is not relivant.
12305 * <script type="text/javascript">
12308 // Base class for reading structured data from a data source. This class is intended to be
12309 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12312 * @class Roo.data.DataReader
12313 * Base class for reading structured data from a data source. This class is intended to be
12314 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12317 Roo.data.DataReader = function(meta, recordType){
12321 this.recordType = recordType instanceof Array ?
12322 Roo.data.Record.create(recordType) : recordType;
12325 Roo.data.DataReader.prototype = {
12327 * Create an empty record
12328 * @param {Object} data (optional) - overlay some values
12329 * @return {Roo.data.Record} record created.
12331 newRow : function(d) {
12333 this.recordType.prototype.fields.each(function(c) {
12335 case 'int' : da[c.name] = 0; break;
12336 case 'date' : da[c.name] = new Date(); break;
12337 case 'float' : da[c.name] = 0.0; break;
12338 case 'boolean' : da[c.name] = false; break;
12339 default : da[c.name] = ""; break;
12343 return new this.recordType(Roo.apply(da, d));
12348 * Ext JS Library 1.1.1
12349 * Copyright(c) 2006-2007, Ext JS, LLC.
12351 * Originally Released Under LGPL - original licence link has changed is not relivant.
12354 * <script type="text/javascript">
12358 * @class Roo.data.DataProxy
12359 * @extends Roo.data.Observable
12360 * This class is an abstract base class for implementations which provide retrieval of
12361 * unformatted data objects.<br>
12363 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12364 * (of the appropriate type which knows how to parse the data object) to provide a block of
12365 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12367 * Custom implementations must implement the load method as described in
12368 * {@link Roo.data.HttpProxy#load}.
12370 Roo.data.DataProxy = function(){
12373 * @event beforeload
12374 * Fires before a network request is made to retrieve a data object.
12375 * @param {Object} This DataProxy object.
12376 * @param {Object} params The params parameter to the load function.
12381 * Fires before the load method's callback is called.
12382 * @param {Object} This DataProxy object.
12383 * @param {Object} o The data object.
12384 * @param {Object} arg The callback argument object passed to the load function.
12388 * @event loadexception
12389 * Fires if an Exception occurs during data retrieval.
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.
12393 * @param {Object} e The Exception.
12395 loadexception : true
12397 Roo.data.DataProxy.superclass.constructor.call(this);
12400 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12403 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12407 * Ext JS Library 1.1.1
12408 * Copyright(c) 2006-2007, Ext JS, LLC.
12410 * Originally Released Under LGPL - original licence link has changed is not relivant.
12413 * <script type="text/javascript">
12416 * @class Roo.data.MemoryProxy
12417 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12418 * to the Reader when its load method is called.
12420 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12422 Roo.data.MemoryProxy = function(data){
12426 Roo.data.MemoryProxy.superclass.constructor.call(this);
12430 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12433 * Load data from the requested source (in this case an in-memory
12434 * data object passed to the constructor), read the data object into
12435 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12436 * process that block using the passed callback.
12437 * @param {Object} params This parameter is not used by the MemoryProxy class.
12438 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12439 * object into a block of Roo.data.Records.
12440 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12441 * The function must be passed <ul>
12442 * <li>The Record block object</li>
12443 * <li>The "arg" argument from the load function</li>
12444 * <li>A boolean success indicator</li>
12446 * @param {Object} scope The scope in which to call the callback
12447 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12449 load : function(params, reader, callback, scope, arg){
12450 params = params || {};
12453 result = reader.readRecords(params.data ? params.data :this.data);
12455 this.fireEvent("loadexception", this, arg, null, e);
12456 callback.call(scope, null, arg, false);
12459 callback.call(scope, result, arg, true);
12463 update : function(params, records){
12468 * Ext JS Library 1.1.1
12469 * Copyright(c) 2006-2007, Ext JS, LLC.
12471 * Originally Released Under LGPL - original licence link has changed is not relivant.
12474 * <script type="text/javascript">
12477 * @class Roo.data.HttpProxy
12478 * @extends Roo.data.DataProxy
12479 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12480 * configured to reference a certain URL.<br><br>
12482 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12483 * from which the running page was served.<br><br>
12485 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12487 * Be aware that to enable the browser to parse an XML document, the server must set
12488 * the Content-Type header in the HTTP response to "text/xml".
12490 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12491 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12492 * will be used to make the request.
12494 Roo.data.HttpProxy = function(conn){
12495 Roo.data.HttpProxy.superclass.constructor.call(this);
12496 // is conn a conn config or a real conn?
12498 this.useAjax = !conn || !conn.events;
12502 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12503 // thse are take from connection...
12506 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12509 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12510 * extra parameters to each request made by this object. (defaults to undefined)
12513 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12514 * to each request made by this object. (defaults to undefined)
12517 * @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)
12520 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12523 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12529 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12533 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12534 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12535 * a finer-grained basis than the DataProxy events.
12537 getConnection : function(){
12538 return this.useAjax ? Roo.Ajax : this.conn;
12542 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12543 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12544 * process that block using the passed callback.
12545 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12546 * for the request to the remote server.
12547 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12548 * object into a block of Roo.data.Records.
12549 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12550 * The function must be passed <ul>
12551 * <li>The Record block object</li>
12552 * <li>The "arg" argument from the load function</li>
12553 * <li>A boolean success indicator</li>
12555 * @param {Object} scope The scope in which to call the callback
12556 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12558 load : function(params, reader, callback, scope, arg){
12559 if(this.fireEvent("beforeload", this, params) !== false){
12561 params : params || {},
12563 callback : callback,
12568 callback : this.loadResponse,
12572 Roo.applyIf(o, this.conn);
12573 if(this.activeRequest){
12574 Roo.Ajax.abort(this.activeRequest);
12576 this.activeRequest = Roo.Ajax.request(o);
12578 this.conn.request(o);
12581 callback.call(scope||this, null, arg, false);
12586 loadResponse : function(o, success, response){
12587 delete this.activeRequest;
12589 this.fireEvent("loadexception", this, o, response);
12590 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12595 result = o.reader.read(response);
12597 this.fireEvent("loadexception", this, o, response, e);
12598 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12602 this.fireEvent("load", this, o, o.request.arg);
12603 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12607 update : function(dataSet){
12612 updateResponse : function(dataSet){
12617 * Ext JS Library 1.1.1
12618 * Copyright(c) 2006-2007, Ext JS, LLC.
12620 * Originally Released Under LGPL - original licence link has changed is not relivant.
12623 * <script type="text/javascript">
12627 * @class Roo.data.ScriptTagProxy
12628 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12629 * other than the originating domain of the running page.<br><br>
12631 * <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
12632 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12634 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12635 * source code that is used as the source inside a <script> tag.<br><br>
12637 * In order for the browser to process the returned data, the server must wrap the data object
12638 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12639 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12640 * depending on whether the callback name was passed:
12643 boolean scriptTag = false;
12644 String cb = request.getParameter("callback");
12647 response.setContentType("text/javascript");
12649 response.setContentType("application/x-json");
12651 Writer out = response.getWriter();
12653 out.write(cb + "(");
12655 out.print(dataBlock.toJsonString());
12662 * @param {Object} config A configuration object.
12664 Roo.data.ScriptTagProxy = function(config){
12665 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12666 Roo.apply(this, config);
12667 this.head = document.getElementsByTagName("head")[0];
12670 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12672 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12674 * @cfg {String} url The URL from which to request the data object.
12677 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12681 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12682 * the server the name of the callback function set up by the load call to process the returned data object.
12683 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12684 * javascript output which calls this named function passing the data object as its only parameter.
12686 callbackParam : "callback",
12688 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12689 * name to the request.
12694 * Load data from the configured URL, read the data object into
12695 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12696 * process that block using the passed callback.
12697 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12698 * for the request to the remote server.
12699 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12700 * object into a block of Roo.data.Records.
12701 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12702 * The function must be passed <ul>
12703 * <li>The Record block object</li>
12704 * <li>The "arg" argument from the load function</li>
12705 * <li>A boolean success indicator</li>
12707 * @param {Object} scope The scope in which to call the callback
12708 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12710 load : function(params, reader, callback, scope, arg){
12711 if(this.fireEvent("beforeload", this, params) !== false){
12713 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12715 var url = this.url;
12716 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12718 url += "&_dc=" + (new Date().getTime());
12720 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12723 cb : "stcCallback"+transId,
12724 scriptId : "stcScript"+transId,
12728 callback : callback,
12734 window[trans.cb] = function(o){
12735 conn.handleResponse(o, trans);
12738 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12740 if(this.autoAbort !== false){
12744 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12746 var script = document.createElement("script");
12747 script.setAttribute("src", url);
12748 script.setAttribute("type", "text/javascript");
12749 script.setAttribute("id", trans.scriptId);
12750 this.head.appendChild(script);
12752 this.trans = trans;
12754 callback.call(scope||this, null, arg, false);
12759 isLoading : function(){
12760 return this.trans ? true : false;
12764 * Abort the current server request.
12766 abort : function(){
12767 if(this.isLoading()){
12768 this.destroyTrans(this.trans);
12773 destroyTrans : function(trans, isLoaded){
12774 this.head.removeChild(document.getElementById(trans.scriptId));
12775 clearTimeout(trans.timeoutId);
12777 window[trans.cb] = undefined;
12779 delete window[trans.cb];
12782 // if hasn't been loaded, wait for load to remove it to prevent script error
12783 window[trans.cb] = function(){
12784 window[trans.cb] = undefined;
12786 delete window[trans.cb];
12793 handleResponse : function(o, trans){
12794 this.trans = false;
12795 this.destroyTrans(trans, true);
12798 result = trans.reader.readRecords(o);
12800 this.fireEvent("loadexception", this, o, trans.arg, e);
12801 trans.callback.call(trans.scope||window, null, trans.arg, false);
12804 this.fireEvent("load", this, o, trans.arg);
12805 trans.callback.call(trans.scope||window, result, trans.arg, true);
12809 handleFailure : function(trans){
12810 this.trans = false;
12811 this.destroyTrans(trans, false);
12812 this.fireEvent("loadexception", this, null, trans.arg);
12813 trans.callback.call(trans.scope||window, null, trans.arg, false);
12817 * Ext JS Library 1.1.1
12818 * Copyright(c) 2006-2007, Ext JS, LLC.
12820 * Originally Released Under LGPL - original licence link has changed is not relivant.
12823 * <script type="text/javascript">
12827 * @class Roo.data.JsonReader
12828 * @extends Roo.data.DataReader
12829 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12830 * based on mappings in a provided Roo.data.Record constructor.
12832 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12833 * in the reply previously.
12838 var RecordDef = Roo.data.Record.create([
12839 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12840 {name: 'occupation'} // This field will use "occupation" as the mapping.
12842 var myReader = new Roo.data.JsonReader({
12843 totalProperty: "results", // The property which contains the total dataset size (optional)
12844 root: "rows", // The property which contains an Array of row objects
12845 id: "id" // The property within each row object that provides an ID for the record (optional)
12849 * This would consume a JSON file like this:
12851 { 'results': 2, 'rows': [
12852 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12853 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12856 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12857 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12858 * paged from the remote server.
12859 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12860 * @cfg {String} root name of the property which contains the Array of row objects.
12861 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12862 * @cfg {Array} fields Array of field definition objects
12864 * Create a new JsonReader
12865 * @param {Object} meta Metadata configuration options
12866 * @param {Object} recordType Either an Array of field definition objects,
12867 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12869 Roo.data.JsonReader = function(meta, recordType){
12872 // set some defaults:
12873 Roo.applyIf(meta, {
12874 totalProperty: 'total',
12875 successProperty : 'success',
12880 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12882 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12885 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12886 * Used by Store query builder to append _requestMeta to params.
12889 metaFromRemote : false,
12891 * This method is only used by a DataProxy which has retrieved data from a remote server.
12892 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12893 * @return {Object} data A data block which is used by an Roo.data.Store object as
12894 * a cache of Roo.data.Records.
12896 read : function(response){
12897 var json = response.responseText;
12899 var o = /* eval:var:o */ eval("("+json+")");
12901 throw {message: "JsonReader.read: Json object not found"};
12907 this.metaFromRemote = true;
12908 this.meta = o.metaData;
12909 this.recordType = Roo.data.Record.create(o.metaData.fields);
12910 this.onMetaChange(this.meta, this.recordType, o);
12912 return this.readRecords(o);
12915 // private function a store will implement
12916 onMetaChange : function(meta, recordType, o){
12923 simpleAccess: function(obj, subsc) {
12930 getJsonAccessor: function(){
12932 return function(expr) {
12934 return(re.test(expr))
12935 ? new Function("obj", "return obj." + expr)
12940 return Roo.emptyFn;
12945 * Create a data block containing Roo.data.Records from an XML document.
12946 * @param {Object} o An object which contains an Array of row objects in the property specified
12947 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12948 * which contains the total size of the dataset.
12949 * @return {Object} data A data block which is used by an Roo.data.Store object as
12950 * a cache of Roo.data.Records.
12952 readRecords : function(o){
12954 * After any data loads, the raw JSON data is available for further custom processing.
12958 var s = this.meta, Record = this.recordType,
12959 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12961 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12963 if(s.totalProperty) {
12964 this.getTotal = this.getJsonAccessor(s.totalProperty);
12966 if(s.successProperty) {
12967 this.getSuccess = this.getJsonAccessor(s.successProperty);
12969 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12971 var g = this.getJsonAccessor(s.id);
12972 this.getId = function(rec) {
12974 return (r === undefined || r === "") ? null : r;
12977 this.getId = function(){return null;};
12980 for(var jj = 0; jj < fl; jj++){
12982 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12983 this.ef[jj] = this.getJsonAccessor(map);
12987 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12988 if(s.totalProperty){
12989 var vt = parseInt(this.getTotal(o), 10);
12994 if(s.successProperty){
12995 var vs = this.getSuccess(o);
12996 if(vs === false || vs === 'false'){
13001 for(var i = 0; i < c; i++){
13004 var id = this.getId(n);
13005 for(var j = 0; j < fl; j++){
13007 var v = this.ef[j](n);
13009 Roo.log('missing convert for ' + f.name);
13013 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13015 var record = new Record(values, id);
13017 records[i] = record;
13023 totalRecords : totalRecords
13028 * Ext JS Library 1.1.1
13029 * Copyright(c) 2006-2007, Ext JS, LLC.
13031 * Originally Released Under LGPL - original licence link has changed is not relivant.
13034 * <script type="text/javascript">
13038 * @class Roo.data.ArrayReader
13039 * @extends Roo.data.DataReader
13040 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13041 * Each element of that Array represents a row of data fields. The
13042 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13043 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13047 var RecordDef = Roo.data.Record.create([
13048 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13049 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13051 var myReader = new Roo.data.ArrayReader({
13052 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13056 * This would consume an Array like this:
13058 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13062 * Create a new JsonReader
13063 * @param {Object} meta Metadata configuration options.
13064 * @param {Object|Array} recordType Either an Array of field definition objects
13066 * @cfg {Array} fields Array of field definition objects
13067 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13068 * as specified to {@link Roo.data.Record#create},
13069 * or an {@link Roo.data.Record} object
13072 * created using {@link Roo.data.Record#create}.
13074 Roo.data.ArrayReader = function(meta, recordType){
13077 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13080 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13082 * Create a data block containing Roo.data.Records from an XML document.
13083 * @param {Object} o An Array of row objects which represents the dataset.
13084 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13085 * a cache of Roo.data.Records.
13087 readRecords : function(o){
13088 var sid = this.meta ? this.meta.id : null;
13089 var recordType = this.recordType, fields = recordType.prototype.fields;
13092 for(var i = 0; i < root.length; i++){
13095 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13096 for(var j = 0, jlen = fields.length; j < jlen; j++){
13097 var f = fields.items[j];
13098 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13099 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13101 values[f.name] = v;
13103 var record = new recordType(values, id);
13105 records[records.length] = record;
13109 totalRecords : records.length
13118 * @class Roo.bootstrap.ComboBox
13119 * @extends Roo.bootstrap.TriggerField
13120 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13121 * @cfg {Boolean} append (true|false) default false
13122 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13123 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13124 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13125 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13126 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13127 * @cfg {Boolean} animate default true
13128 * @cfg {Boolean} emptyResultText only for touch device
13129 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13130 * @cfg {String} emptyTitle default ''
13132 * Create a new ComboBox.
13133 * @param {Object} config Configuration options
13135 Roo.bootstrap.ComboBox = function(config){
13136 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13140 * Fires when the dropdown list is expanded
13141 * @param {Roo.bootstrap.ComboBox} combo This combo box
13146 * Fires when the dropdown list is collapsed
13147 * @param {Roo.bootstrap.ComboBox} combo This combo box
13151 * @event beforeselect
13152 * Fires before a list item is selected. Return false to cancel the selection.
13153 * @param {Roo.bootstrap.ComboBox} combo This combo box
13154 * @param {Roo.data.Record} record The data record returned from the underlying store
13155 * @param {Number} index The index of the selected item in the dropdown list
13157 'beforeselect' : true,
13160 * Fires when a list item is selected
13161 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13163 * @param {Number} index The index of the selected item in the dropdown list
13167 * @event beforequery
13168 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13169 * The event object passed has these properties:
13170 * @param {Roo.bootstrap.ComboBox} combo This combo box
13171 * @param {String} query The query
13172 * @param {Boolean} forceAll true to force "all" query
13173 * @param {Boolean} cancel true to cancel the query
13174 * @param {Object} e The query event object
13176 'beforequery': true,
13179 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13180 * @param {Roo.bootstrap.ComboBox} combo This combo box
13185 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13186 * @param {Roo.bootstrap.ComboBox} combo This combo box
13187 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13192 * Fires when the remove value from the combobox array
13193 * @param {Roo.bootstrap.ComboBox} combo This combo box
13197 * @event afterremove
13198 * Fires when the remove value from the combobox array
13199 * @param {Roo.bootstrap.ComboBox} combo This combo box
13201 'afterremove' : true,
13203 * @event specialfilter
13204 * Fires when specialfilter
13205 * @param {Roo.bootstrap.ComboBox} combo This combo box
13207 'specialfilter' : true,
13210 * Fires when tick the element
13211 * @param {Roo.bootstrap.ComboBox} combo This combo box
13215 * @event touchviewdisplay
13216 * Fires when touch view require special display (default is using displayField)
13217 * @param {Roo.bootstrap.ComboBox} combo This combo box
13218 * @param {Object} cfg set html .
13220 'touchviewdisplay' : true
13225 this.tickItems = [];
13227 this.selectedIndex = -1;
13228 if(this.mode == 'local'){
13229 if(config.queryDelay === undefined){
13230 this.queryDelay = 10;
13232 if(config.minChars === undefined){
13238 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13241 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13242 * rendering into an Roo.Editor, defaults to false)
13245 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13246 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13249 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13252 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13253 * the dropdown list (defaults to undefined, with no header element)
13257 * @cfg {String/Roo.Template} tpl The template to use to render the output
13261 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13263 listWidth: undefined,
13265 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13266 * mode = 'remote' or 'text' if mode = 'local')
13268 displayField: undefined,
13271 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13272 * mode = 'remote' or 'value' if mode = 'local').
13273 * Note: use of a valueField requires the user make a selection
13274 * in order for a value to be mapped.
13276 valueField: undefined,
13278 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13283 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13284 * field's data value (defaults to the underlying DOM element's name)
13286 hiddenName: undefined,
13288 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13292 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13294 selectedClass: 'active',
13297 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13301 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13302 * anchor positions (defaults to 'tl-bl')
13304 listAlign: 'tl-bl?',
13306 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13310 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13311 * query specified by the allQuery config option (defaults to 'query')
13313 triggerAction: 'query',
13315 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13316 * (defaults to 4, does not apply if editable = false)
13320 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13321 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13325 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13326 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13330 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13331 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13335 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13336 * when editable = true (defaults to false)
13338 selectOnFocus:false,
13340 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13342 queryParam: 'query',
13344 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13345 * when mode = 'remote' (defaults to 'Loading...')
13347 loadingText: 'Loading...',
13349 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13353 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13357 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13358 * traditional select (defaults to true)
13362 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13366 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13370 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13371 * listWidth has a higher value)
13375 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13376 * allow the user to set arbitrary text into the field (defaults to false)
13378 forceSelection:false,
13380 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13381 * if typeAhead = true (defaults to 250)
13383 typeAheadDelay : 250,
13385 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13386 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13388 valueNotFoundText : undefined,
13390 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13392 blockFocus : false,
13395 * @cfg {Boolean} disableClear Disable showing of clear button.
13397 disableClear : false,
13399 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13401 alwaysQuery : false,
13404 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13409 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13411 invalidClass : "has-warning",
13414 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13416 validClass : "has-success",
13419 * @cfg {Boolean} specialFilter (true|false) special filter default false
13421 specialFilter : false,
13424 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13426 mobileTouchView : true,
13429 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13431 useNativeIOS : false,
13434 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13436 mobile_restrict_height : false,
13438 ios_options : false,
13450 btnPosition : 'right',
13451 triggerList : true,
13452 showToggleBtn : true,
13454 emptyResultText: 'Empty',
13455 triggerText : 'Select',
13458 // element that contains real text value.. (when hidden is used..)
13460 getAutoCreate : function()
13465 * Render classic select for iso
13468 if(Roo.isIOS && this.useNativeIOS){
13469 cfg = this.getAutoCreateNativeIOS();
13477 if(Roo.isTouch && this.mobileTouchView){
13478 cfg = this.getAutoCreateTouchView();
13485 if(!this.tickable){
13486 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13491 * ComboBox with tickable selections
13494 var align = this.labelAlign || this.parentLabelAlign();
13497 cls : 'form-group roo-combobox-tickable' //input-group
13500 var btn_text_select = '';
13501 var btn_text_done = '';
13502 var btn_text_cancel = '';
13504 if (this.btn_text_show) {
13505 btn_text_select = 'Select';
13506 btn_text_done = 'Done';
13507 btn_text_cancel = 'Cancel';
13512 cls : 'tickable-buttons',
13517 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13518 //html : this.triggerText
13519 html: btn_text_select
13525 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13527 html: btn_text_done
13533 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13535 html: btn_text_cancel
13541 buttons.cn.unshift({
13543 cls: 'roo-select2-search-field-input'
13549 Roo.each(buttons.cn, function(c){
13551 c.cls += ' btn-' + _this.size;
13554 if (_this.disabled) {
13561 style : 'display: contents',
13566 cls: 'form-hidden-field'
13570 cls: 'roo-select2-choices',
13574 cls: 'roo-select2-search-field',
13585 cls: 'roo-select2-container input-group roo-select2-container-multi',
13591 // cls: 'typeahead typeahead-long dropdown-menu',
13592 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13597 if(this.hasFeedback && !this.allowBlank){
13601 cls: 'glyphicon form-control-feedback'
13604 combobox.cn.push(feedback);
13609 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13610 tooltip : 'This field is required'
13612 if (Roo.bootstrap.version == 4) {
13615 style : 'display:none'
13618 if (align ==='left' && this.fieldLabel.length) {
13620 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13627 cls : 'control-label col-form-label',
13628 html : this.fieldLabel
13640 var labelCfg = cfg.cn[1];
13641 var contentCfg = cfg.cn[2];
13644 if(this.indicatorpos == 'right'){
13650 cls : 'control-label col-form-label',
13654 html : this.fieldLabel
13670 labelCfg = cfg.cn[0];
13671 contentCfg = cfg.cn[1];
13675 if(this.labelWidth > 12){
13676 labelCfg.style = "width: " + this.labelWidth + 'px';
13679 if(this.labelWidth < 13 && this.labelmd == 0){
13680 this.labelmd = this.labelWidth;
13683 if(this.labellg > 0){
13684 labelCfg.cls += ' col-lg-' + this.labellg;
13685 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13688 if(this.labelmd > 0){
13689 labelCfg.cls += ' col-md-' + this.labelmd;
13690 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13693 if(this.labelsm > 0){
13694 labelCfg.cls += ' col-sm-' + this.labelsm;
13695 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13698 if(this.labelxs > 0){
13699 labelCfg.cls += ' col-xs-' + this.labelxs;
13700 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13704 } else if ( this.fieldLabel.length) {
13705 // Roo.log(" label");
13710 //cls : 'input-group-addon',
13711 html : this.fieldLabel
13716 if(this.indicatorpos == 'right'){
13720 //cls : 'input-group-addon',
13721 html : this.fieldLabel
13731 // Roo.log(" no label && no align");
13738 ['xs','sm','md','lg'].map(function(size){
13739 if (settings[size]) {
13740 cfg.cls += ' col-' + size + '-' + settings[size];
13748 _initEventsCalled : false,
13751 initEvents: function()
13753 if (this._initEventsCalled) { // as we call render... prevent looping...
13756 this._initEventsCalled = true;
13759 throw "can not find store for combo";
13762 this.indicator = this.indicatorEl();
13764 this.store = Roo.factory(this.store, Roo.data);
13765 this.store.parent = this;
13767 // if we are building from html. then this element is so complex, that we can not really
13768 // use the rendered HTML.
13769 // so we have to trash and replace the previous code.
13770 if (Roo.XComponent.build_from_html) {
13771 // remove this element....
13772 var e = this.el.dom, k=0;
13773 while (e ) { e = e.previousSibling; ++k;}
13778 this.rendered = false;
13780 this.render(this.parent().getChildContainer(true), k);
13783 if(Roo.isIOS && this.useNativeIOS){
13784 this.initIOSView();
13792 if(Roo.isTouch && this.mobileTouchView){
13793 this.initTouchView();
13798 this.initTickableEvents();
13802 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13804 if(this.hiddenName){
13806 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13808 this.hiddenField.dom.value =
13809 this.hiddenValue !== undefined ? this.hiddenValue :
13810 this.value !== undefined ? this.value : '';
13812 // prevent input submission
13813 this.el.dom.removeAttribute('name');
13814 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13819 // this.el.dom.setAttribute('autocomplete', 'off');
13822 var cls = 'x-combo-list';
13824 //this.list = new Roo.Layer({
13825 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13831 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13832 _this.list.setWidth(lw);
13835 this.list.on('mouseover', this.onViewOver, this);
13836 this.list.on('mousemove', this.onViewMove, this);
13837 this.list.on('scroll', this.onViewScroll, this);
13840 this.list.swallowEvent('mousewheel');
13841 this.assetHeight = 0;
13844 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13845 this.assetHeight += this.header.getHeight();
13848 this.innerList = this.list.createChild({cls:cls+'-inner'});
13849 this.innerList.on('mouseover', this.onViewOver, this);
13850 this.innerList.on('mousemove', this.onViewMove, this);
13851 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13853 if(this.allowBlank && !this.pageSize && !this.disableClear){
13854 this.footer = this.list.createChild({cls:cls+'-ft'});
13855 this.pageTb = new Roo.Toolbar(this.footer);
13859 this.footer = this.list.createChild({cls:cls+'-ft'});
13860 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13861 {pageSize: this.pageSize});
13865 if (this.pageTb && this.allowBlank && !this.disableClear) {
13867 this.pageTb.add(new Roo.Toolbar.Fill(), {
13868 cls: 'x-btn-icon x-btn-clear',
13870 handler: function()
13873 _this.clearValue();
13874 _this.onSelect(false, -1);
13879 this.assetHeight += this.footer.getHeight();
13884 this.tpl = Roo.bootstrap.version == 4 ?
13885 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13886 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13889 this.view = new Roo.View(this.list, this.tpl, {
13890 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13892 //this.view.wrapEl.setDisplayed(false);
13893 this.view.on('click', this.onViewClick, this);
13896 this.store.on('beforeload', this.onBeforeLoad, this);
13897 this.store.on('load', this.onLoad, this);
13898 this.store.on('loadexception', this.onLoadException, this);
13900 if(this.resizable){
13901 this.resizer = new Roo.Resizable(this.list, {
13902 pinned:true, handles:'se'
13904 this.resizer.on('resize', function(r, w, h){
13905 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13906 this.listWidth = w;
13907 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13908 this.restrictHeight();
13910 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13913 if(!this.editable){
13914 this.editable = true;
13915 this.setEditable(false);
13920 if (typeof(this.events.add.listeners) != 'undefined') {
13922 this.addicon = this.wrap.createChild(
13923 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13925 this.addicon.on('click', function(e) {
13926 this.fireEvent('add', this);
13929 if (typeof(this.events.edit.listeners) != 'undefined') {
13931 this.editicon = this.wrap.createChild(
13932 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13933 if (this.addicon) {
13934 this.editicon.setStyle('margin-left', '40px');
13936 this.editicon.on('click', function(e) {
13938 // we fire even if inothing is selected..
13939 this.fireEvent('edit', this, this.lastData );
13945 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13946 "up" : function(e){
13947 this.inKeyMode = true;
13951 "down" : function(e){
13952 if(!this.isExpanded()){
13953 this.onTriggerClick();
13955 this.inKeyMode = true;
13960 "enter" : function(e){
13961 // this.onViewClick();
13965 if(this.fireEvent("specialkey", this, e)){
13966 this.onViewClick(false);
13972 "esc" : function(e){
13976 "tab" : function(e){
13979 if(this.fireEvent("specialkey", this, e)){
13980 this.onViewClick(false);
13988 doRelay : function(foo, bar, hname){
13989 if(hname == 'down' || this.scope.isExpanded()){
13990 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13999 this.queryDelay = Math.max(this.queryDelay || 10,
14000 this.mode == 'local' ? 10 : 250);
14003 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14005 if(this.typeAhead){
14006 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14008 if(this.editable !== false){
14009 this.inputEl().on("keyup", this.onKeyUp, this);
14011 if(this.forceSelection){
14012 this.inputEl().on('blur', this.doForce, this);
14016 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14017 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14021 initTickableEvents: function()
14025 if(this.hiddenName){
14027 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14029 this.hiddenField.dom.value =
14030 this.hiddenValue !== undefined ? this.hiddenValue :
14031 this.value !== undefined ? this.value : '';
14033 // prevent input submission
14034 this.el.dom.removeAttribute('name');
14035 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14040 // this.list = this.el.select('ul.dropdown-menu',true).first();
14042 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14043 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14044 if(this.triggerList){
14045 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14048 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14049 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14051 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14052 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14054 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14055 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14057 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14058 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14059 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14062 this.cancelBtn.hide();
14067 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14068 _this.list.setWidth(lw);
14071 this.list.on('mouseover', this.onViewOver, this);
14072 this.list.on('mousemove', this.onViewMove, this);
14074 this.list.on('scroll', this.onViewScroll, this);
14077 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14078 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14081 this.view = new Roo.View(this.list, this.tpl, {
14086 selectedClass: this.selectedClass
14089 //this.view.wrapEl.setDisplayed(false);
14090 this.view.on('click', this.onViewClick, this);
14094 this.store.on('beforeload', this.onBeforeLoad, this);
14095 this.store.on('load', this.onLoad, this);
14096 this.store.on('loadexception', this.onLoadException, this);
14099 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14100 "up" : function(e){
14101 this.inKeyMode = true;
14105 "down" : function(e){
14106 this.inKeyMode = true;
14110 "enter" : function(e){
14111 if(this.fireEvent("specialkey", this, e)){
14112 this.onViewClick(false);
14118 "esc" : function(e){
14119 this.onTickableFooterButtonClick(e, false, false);
14122 "tab" : function(e){
14123 this.fireEvent("specialkey", this, e);
14125 this.onTickableFooterButtonClick(e, false, false);
14132 doRelay : function(e, fn, key){
14133 if(this.scope.isExpanded()){
14134 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14143 this.queryDelay = Math.max(this.queryDelay || 10,
14144 this.mode == 'local' ? 10 : 250);
14147 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14149 if(this.typeAhead){
14150 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14153 if(this.editable !== false){
14154 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14157 this.indicator = this.indicatorEl();
14159 if(this.indicator){
14160 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14161 this.indicator.hide();
14166 onDestroy : function(){
14168 this.view.setStore(null);
14169 this.view.el.removeAllListeners();
14170 this.view.el.remove();
14171 this.view.purgeListeners();
14174 this.list.dom.innerHTML = '';
14178 this.store.un('beforeload', this.onBeforeLoad, this);
14179 this.store.un('load', this.onLoad, this);
14180 this.store.un('loadexception', this.onLoadException, this);
14182 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14186 fireKey : function(e){
14187 if(e.isNavKeyPress() && !this.list.isVisible()){
14188 this.fireEvent("specialkey", this, e);
14193 onResize: function(w, h){
14194 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14196 // if(typeof w != 'number'){
14197 // // we do not handle it!?!?
14200 // var tw = this.trigger.getWidth();
14201 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14202 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14204 // this.inputEl().setWidth( this.adjustWidth('input', x));
14206 // //this.trigger.setStyle('left', x+'px');
14208 // if(this.list && this.listWidth === undefined){
14209 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14210 // this.list.setWidth(lw);
14211 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14219 * Allow or prevent the user from directly editing the field text. If false is passed,
14220 * the user will only be able to select from the items defined in the dropdown list. This method
14221 * is the runtime equivalent of setting the 'editable' config option at config time.
14222 * @param {Boolean} value True to allow the user to directly edit the field text
14224 setEditable : function(value){
14225 if(value == this.editable){
14228 this.editable = value;
14230 this.inputEl().dom.setAttribute('readOnly', true);
14231 this.inputEl().on('mousedown', this.onTriggerClick, this);
14232 this.inputEl().addClass('x-combo-noedit');
14234 this.inputEl().dom.setAttribute('readOnly', false);
14235 this.inputEl().un('mousedown', this.onTriggerClick, this);
14236 this.inputEl().removeClass('x-combo-noedit');
14242 onBeforeLoad : function(combo,opts){
14243 if(!this.hasFocus){
14247 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14249 this.restrictHeight();
14250 this.selectedIndex = -1;
14254 onLoad : function(){
14256 this.hasQuery = false;
14258 if(!this.hasFocus){
14262 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14263 this.loading.hide();
14266 if(this.store.getCount() > 0){
14269 this.restrictHeight();
14270 if(this.lastQuery == this.allQuery){
14271 if(this.editable && !this.tickable){
14272 this.inputEl().dom.select();
14276 !this.selectByValue(this.value, true) &&
14279 !this.store.lastOptions ||
14280 typeof(this.store.lastOptions.add) == 'undefined' ||
14281 this.store.lastOptions.add != true
14284 this.select(0, true);
14287 if(this.autoFocus){
14290 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14291 this.taTask.delay(this.typeAheadDelay);
14295 this.onEmptyResults();
14301 onLoadException : function()
14303 this.hasQuery = false;
14305 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14306 this.loading.hide();
14309 if(this.tickable && this.editable){
14314 // only causes errors at present
14315 //Roo.log(this.store.reader.jsonData);
14316 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14318 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14324 onTypeAhead : function(){
14325 if(this.store.getCount() > 0){
14326 var r = this.store.getAt(0);
14327 var newValue = r.data[this.displayField];
14328 var len = newValue.length;
14329 var selStart = this.getRawValue().length;
14331 if(selStart != len){
14332 this.setRawValue(newValue);
14333 this.selectText(selStart, newValue.length);
14339 onSelect : function(record, index){
14341 if(this.fireEvent('beforeselect', this, record, index) !== false){
14343 this.setFromData(index > -1 ? record.data : false);
14346 this.fireEvent('select', this, record, index);
14351 * Returns the currently selected field value or empty string if no value is set.
14352 * @return {String} value The selected value
14354 getValue : function()
14356 if(Roo.isIOS && this.useNativeIOS){
14357 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14361 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14364 if(this.valueField){
14365 return typeof this.value != 'undefined' ? this.value : '';
14367 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14371 getRawValue : function()
14373 if(Roo.isIOS && this.useNativeIOS){
14374 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14377 var v = this.inputEl().getValue();
14383 * Clears any text/value currently set in the field
14385 clearValue : function(){
14387 if(this.hiddenField){
14388 this.hiddenField.dom.value = '';
14391 this.setRawValue('');
14392 this.lastSelectionText = '';
14393 this.lastData = false;
14395 var close = this.closeTriggerEl();
14406 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14407 * will be displayed in the field. If the value does not match the data value of an existing item,
14408 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14409 * Otherwise the field will be blank (although the value will still be set).
14410 * @param {String} value The value to match
14412 setValue : function(v)
14414 if(Roo.isIOS && this.useNativeIOS){
14415 this.setIOSValue(v);
14425 if(this.valueField){
14426 var r = this.findRecord(this.valueField, v);
14428 text = r.data[this.displayField];
14429 }else if(this.valueNotFoundText !== undefined){
14430 text = this.valueNotFoundText;
14433 this.lastSelectionText = text;
14434 if(this.hiddenField){
14435 this.hiddenField.dom.value = v;
14437 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14440 var close = this.closeTriggerEl();
14443 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14449 * @property {Object} the last set data for the element
14454 * Sets the value of the field based on a object which is related to the record format for the store.
14455 * @param {Object} value the value to set as. or false on reset?
14457 setFromData : function(o){
14464 var dv = ''; // display value
14465 var vv = ''; // value value..
14467 if (this.displayField) {
14468 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14470 // this is an error condition!!!
14471 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14474 if(this.valueField){
14475 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14478 var close = this.closeTriggerEl();
14481 if(dv.length || vv * 1 > 0){
14483 this.blockFocus=true;
14489 if(this.hiddenField){
14490 this.hiddenField.dom.value = vv;
14492 this.lastSelectionText = dv;
14493 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14497 // no hidden field.. - we store the value in 'value', but still display
14498 // display field!!!!
14499 this.lastSelectionText = dv;
14500 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14507 reset : function(){
14508 // overridden so that last data is reset..
14515 this.setValue(this.originalValue);
14516 //this.clearInvalid();
14517 this.lastData = false;
14519 this.view.clearSelections();
14525 findRecord : function(prop, value){
14527 if(this.store.getCount() > 0){
14528 this.store.each(function(r){
14529 if(r.data[prop] == value){
14539 getName: function()
14541 // returns hidden if it's set..
14542 if (!this.rendered) {return ''};
14543 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14547 onViewMove : function(e, t){
14548 this.inKeyMode = false;
14552 onViewOver : function(e, t){
14553 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14556 var item = this.view.findItemFromChild(t);
14559 var index = this.view.indexOf(item);
14560 this.select(index, false);
14565 onViewClick : function(view, doFocus, el, e)
14567 var index = this.view.getSelectedIndexes()[0];
14569 var r = this.store.getAt(index);
14573 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14580 Roo.each(this.tickItems, function(v,k){
14582 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14584 _this.tickItems.splice(k, 1);
14586 if(typeof(e) == 'undefined' && view == false){
14587 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14599 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14600 this.tickItems.push(r.data);
14603 if(typeof(e) == 'undefined' && view == false){
14604 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14611 this.onSelect(r, index);
14613 if(doFocus !== false && !this.blockFocus){
14614 this.inputEl().focus();
14619 restrictHeight : function(){
14620 //this.innerList.dom.style.height = '';
14621 //var inner = this.innerList.dom;
14622 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14623 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14624 //this.list.beginUpdate();
14625 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14626 this.list.alignTo(this.inputEl(), this.listAlign);
14627 this.list.alignTo(this.inputEl(), this.listAlign);
14628 //this.list.endUpdate();
14632 onEmptyResults : function(){
14634 if(this.tickable && this.editable){
14635 this.hasFocus = false;
14636 this.restrictHeight();
14644 * Returns true if the dropdown list is expanded, else false.
14646 isExpanded : function(){
14647 return this.list.isVisible();
14651 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14652 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14653 * @param {String} value The data value of the item to select
14654 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14655 * selected item if it is not currently in view (defaults to true)
14656 * @return {Boolean} True if the value matched an item in the list, else false
14658 selectByValue : function(v, scrollIntoView){
14659 if(v !== undefined && v !== null){
14660 var r = this.findRecord(this.valueField || this.displayField, v);
14662 this.select(this.store.indexOf(r), scrollIntoView);
14670 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14671 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14672 * @param {Number} index The zero-based index of the list item to select
14673 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14674 * selected item if it is not currently in view (defaults to true)
14676 select : function(index, scrollIntoView){
14677 this.selectedIndex = index;
14678 this.view.select(index);
14679 if(scrollIntoView !== false){
14680 var el = this.view.getNode(index);
14682 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14685 this.list.scrollChildIntoView(el, false);
14691 selectNext : function(){
14692 var ct = this.store.getCount();
14694 if(this.selectedIndex == -1){
14696 }else if(this.selectedIndex < ct-1){
14697 this.select(this.selectedIndex+1);
14703 selectPrev : function(){
14704 var ct = this.store.getCount();
14706 if(this.selectedIndex == -1){
14708 }else if(this.selectedIndex != 0){
14709 this.select(this.selectedIndex-1);
14715 onKeyUp : function(e){
14716 if(this.editable !== false && !e.isSpecialKey()){
14717 this.lastKey = e.getKey();
14718 this.dqTask.delay(this.queryDelay);
14723 validateBlur : function(){
14724 return !this.list || !this.list.isVisible();
14728 initQuery : function(){
14730 var v = this.getRawValue();
14732 if(this.tickable && this.editable){
14733 v = this.tickableInputEl().getValue();
14740 doForce : function(){
14741 if(this.inputEl().dom.value.length > 0){
14742 this.inputEl().dom.value =
14743 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14749 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14750 * query allowing the query action to be canceled if needed.
14751 * @param {String} query The SQL query to execute
14752 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14753 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14754 * saved in the current store (defaults to false)
14756 doQuery : function(q, forceAll){
14758 if(q === undefined || q === null){
14763 forceAll: forceAll,
14767 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14772 forceAll = qe.forceAll;
14773 if(forceAll === true || (q.length >= this.minChars)){
14775 this.hasQuery = true;
14777 if(this.lastQuery != q || this.alwaysQuery){
14778 this.lastQuery = q;
14779 if(this.mode == 'local'){
14780 this.selectedIndex = -1;
14782 this.store.clearFilter();
14785 if(this.specialFilter){
14786 this.fireEvent('specialfilter', this);
14791 this.store.filter(this.displayField, q);
14794 this.store.fireEvent("datachanged", this.store);
14801 this.store.baseParams[this.queryParam] = q;
14803 var options = {params : this.getParams(q)};
14806 options.add = true;
14807 options.params.start = this.page * this.pageSize;
14810 this.store.load(options);
14813 * this code will make the page width larger, at the beginning, the list not align correctly,
14814 * we should expand the list on onLoad
14815 * so command out it
14820 this.selectedIndex = -1;
14825 this.loadNext = false;
14829 getParams : function(q){
14831 //p[this.queryParam] = q;
14835 p.limit = this.pageSize;
14841 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14843 collapse : function(){
14844 if(!this.isExpanded()){
14850 this.hasFocus = false;
14854 this.cancelBtn.hide();
14855 this.trigger.show();
14858 this.tickableInputEl().dom.value = '';
14859 this.tickableInputEl().blur();
14864 Roo.get(document).un('mousedown', this.collapseIf, this);
14865 Roo.get(document).un('mousewheel', this.collapseIf, this);
14866 if (!this.editable) {
14867 Roo.get(document).un('keydown', this.listKeyPress, this);
14869 this.fireEvent('collapse', this);
14875 collapseIf : function(e){
14876 var in_combo = e.within(this.el);
14877 var in_list = e.within(this.list);
14878 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14880 if (in_combo || in_list || is_list) {
14881 //e.stopPropagation();
14886 this.onTickableFooterButtonClick(e, false, false);
14894 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14896 expand : function(){
14898 if(this.isExpanded() || !this.hasFocus){
14902 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14903 this.list.setWidth(lw);
14909 this.restrictHeight();
14913 this.tickItems = Roo.apply([], this.item);
14916 this.cancelBtn.show();
14917 this.trigger.hide();
14920 this.tickableInputEl().focus();
14925 Roo.get(document).on('mousedown', this.collapseIf, this);
14926 Roo.get(document).on('mousewheel', this.collapseIf, this);
14927 if (!this.editable) {
14928 Roo.get(document).on('keydown', this.listKeyPress, this);
14931 this.fireEvent('expand', this);
14935 // Implements the default empty TriggerField.onTriggerClick function
14936 onTriggerClick : function(e)
14938 Roo.log('trigger click');
14940 if(this.disabled || !this.triggerList){
14945 this.loadNext = false;
14947 if(this.isExpanded()){
14949 if (!this.blockFocus) {
14950 this.inputEl().focus();
14954 this.hasFocus = true;
14955 if(this.triggerAction == 'all') {
14956 this.doQuery(this.allQuery, true);
14958 this.doQuery(this.getRawValue());
14960 if (!this.blockFocus) {
14961 this.inputEl().focus();
14966 onTickableTriggerClick : function(e)
14973 this.loadNext = false;
14974 this.hasFocus = true;
14976 if(this.triggerAction == 'all') {
14977 this.doQuery(this.allQuery, true);
14979 this.doQuery(this.getRawValue());
14983 onSearchFieldClick : function(e)
14985 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14986 this.onTickableFooterButtonClick(e, false, false);
14990 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14995 this.loadNext = false;
14996 this.hasFocus = true;
14998 if(this.triggerAction == 'all') {
14999 this.doQuery(this.allQuery, true);
15001 this.doQuery(this.getRawValue());
15005 listKeyPress : function(e)
15007 //Roo.log('listkeypress');
15008 // scroll to first matching element based on key pres..
15009 if (e.isSpecialKey()) {
15012 var k = String.fromCharCode(e.getKey()).toUpperCase();
15015 var csel = this.view.getSelectedNodes();
15016 var cselitem = false;
15018 var ix = this.view.indexOf(csel[0]);
15019 cselitem = this.store.getAt(ix);
15020 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15026 this.store.each(function(v) {
15028 // start at existing selection.
15029 if (cselitem.id == v.id) {
15035 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15036 match = this.store.indexOf(v);
15042 if (match === false) {
15043 return true; // no more action?
15046 this.view.select(match);
15047 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15048 sn.scrollIntoView(sn.dom.parentNode, false);
15051 onViewScroll : function(e, t){
15053 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){
15057 this.hasQuery = true;
15059 this.loading = this.list.select('.loading', true).first();
15061 if(this.loading === null){
15062 this.list.createChild({
15064 cls: 'loading roo-select2-more-results roo-select2-active',
15065 html: 'Loading more results...'
15068 this.loading = this.list.select('.loading', true).first();
15070 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15072 this.loading.hide();
15075 this.loading.show();
15080 this.loadNext = true;
15082 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15087 addItem : function(o)
15089 var dv = ''; // display value
15091 if (this.displayField) {
15092 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15094 // this is an error condition!!!
15095 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15102 var choice = this.choices.createChild({
15104 cls: 'roo-select2-search-choice',
15113 cls: 'roo-select2-search-choice-close fa fa-times',
15118 }, this.searchField);
15120 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15122 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15130 this.inputEl().dom.value = '';
15135 onRemoveItem : function(e, _self, o)
15137 e.preventDefault();
15139 this.lastItem = Roo.apply([], this.item);
15141 var index = this.item.indexOf(o.data) * 1;
15144 Roo.log('not this item?!');
15148 this.item.splice(index, 1);
15153 this.fireEvent('remove', this, e);
15159 syncValue : function()
15161 if(!this.item.length){
15168 Roo.each(this.item, function(i){
15169 if(_this.valueField){
15170 value.push(i[_this.valueField]);
15177 this.value = value.join(',');
15179 if(this.hiddenField){
15180 this.hiddenField.dom.value = this.value;
15183 this.store.fireEvent("datachanged", this.store);
15188 clearItem : function()
15190 if(!this.multiple){
15196 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15204 if(this.tickable && !Roo.isTouch){
15205 this.view.refresh();
15209 inputEl: function ()
15211 if(Roo.isIOS && this.useNativeIOS){
15212 return this.el.select('select.roo-ios-select', true).first();
15215 if(Roo.isTouch && this.mobileTouchView){
15216 return this.el.select('input.form-control',true).first();
15220 return this.searchField;
15223 return this.el.select('input.form-control',true).first();
15226 onTickableFooterButtonClick : function(e, btn, el)
15228 e.preventDefault();
15230 this.lastItem = Roo.apply([], this.item);
15232 if(btn && btn.name == 'cancel'){
15233 this.tickItems = Roo.apply([], this.item);
15242 Roo.each(this.tickItems, function(o){
15250 validate : function()
15252 if(this.getVisibilityEl().hasClass('hidden')){
15256 var v = this.getRawValue();
15259 v = this.getValue();
15262 if(this.disabled || this.allowBlank || v.length){
15267 this.markInvalid();
15271 tickableInputEl : function()
15273 if(!this.tickable || !this.editable){
15274 return this.inputEl();
15277 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15281 getAutoCreateTouchView : function()
15286 cls: 'form-group' //input-group
15292 type : this.inputType,
15293 cls : 'form-control x-combo-noedit',
15294 autocomplete: 'new-password',
15295 placeholder : this.placeholder || '',
15300 input.name = this.name;
15304 input.cls += ' input-' + this.size;
15307 if (this.disabled) {
15308 input.disabled = true;
15319 inputblock.cls += ' input-group';
15321 inputblock.cn.unshift({
15323 cls : 'input-group-addon input-group-prepend input-group-text',
15328 if(this.removable && !this.multiple){
15329 inputblock.cls += ' roo-removable';
15331 inputblock.cn.push({
15334 cls : 'roo-combo-removable-btn close'
15338 if(this.hasFeedback && !this.allowBlank){
15340 inputblock.cls += ' has-feedback';
15342 inputblock.cn.push({
15344 cls: 'glyphicon form-control-feedback'
15351 inputblock.cls += (this.before) ? '' : ' input-group';
15353 inputblock.cn.push({
15355 cls : 'input-group-addon input-group-append input-group-text',
15361 var ibwrap = inputblock;
15366 cls: 'roo-select2-choices',
15370 cls: 'roo-select2-search-field',
15383 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15388 cls: 'form-hidden-field'
15394 if(!this.multiple && this.showToggleBtn){
15400 if (this.caret != false) {
15403 cls: 'fa fa-' + this.caret
15410 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15412 Roo.bootstrap.version == 3 ? caret : '',
15415 cls: 'combobox-clear',
15429 combobox.cls += ' roo-select2-container-multi';
15432 var align = this.labelAlign || this.parentLabelAlign();
15434 if (align ==='left' && this.fieldLabel.length) {
15439 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15440 tooltip : 'This field is required'
15444 cls : 'control-label col-form-label',
15445 html : this.fieldLabel
15456 var labelCfg = cfg.cn[1];
15457 var contentCfg = cfg.cn[2];
15460 if(this.indicatorpos == 'right'){
15465 cls : 'control-label col-form-label',
15469 html : this.fieldLabel
15473 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15474 tooltip : 'This field is required'
15487 labelCfg = cfg.cn[0];
15488 contentCfg = cfg.cn[1];
15493 if(this.labelWidth > 12){
15494 labelCfg.style = "width: " + this.labelWidth + 'px';
15497 if(this.labelWidth < 13 && this.labelmd == 0){
15498 this.labelmd = this.labelWidth;
15501 if(this.labellg > 0){
15502 labelCfg.cls += ' col-lg-' + this.labellg;
15503 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15506 if(this.labelmd > 0){
15507 labelCfg.cls += ' col-md-' + this.labelmd;
15508 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15511 if(this.labelsm > 0){
15512 labelCfg.cls += ' col-sm-' + this.labelsm;
15513 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15516 if(this.labelxs > 0){
15517 labelCfg.cls += ' col-xs-' + this.labelxs;
15518 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15522 } else if ( this.fieldLabel.length) {
15526 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15527 tooltip : 'This field is required'
15531 cls : 'control-label',
15532 html : this.fieldLabel
15543 if(this.indicatorpos == 'right'){
15547 cls : 'control-label',
15548 html : this.fieldLabel,
15552 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15553 tooltip : 'This field is required'
15570 var settings = this;
15572 ['xs','sm','md','lg'].map(function(size){
15573 if (settings[size]) {
15574 cfg.cls += ' col-' + size + '-' + settings[size];
15581 initTouchView : function()
15583 this.renderTouchView();
15585 this.touchViewEl.on('scroll', function(){
15586 this.el.dom.scrollTop = 0;
15589 this.originalValue = this.getValue();
15591 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15593 this.inputEl().on("click", this.showTouchView, this);
15594 if (this.triggerEl) {
15595 this.triggerEl.on("click", this.showTouchView, this);
15599 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15600 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15602 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15604 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15605 this.store.on('load', this.onTouchViewLoad, this);
15606 this.store.on('loadexception', this.onTouchViewLoadException, this);
15608 if(this.hiddenName){
15610 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15612 this.hiddenField.dom.value =
15613 this.hiddenValue !== undefined ? this.hiddenValue :
15614 this.value !== undefined ? this.value : '';
15616 this.el.dom.removeAttribute('name');
15617 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15621 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15622 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15625 if(this.removable && !this.multiple){
15626 var close = this.closeTriggerEl();
15628 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15629 close.on('click', this.removeBtnClick, this, close);
15633 * fix the bug in Safari iOS8
15635 this.inputEl().on("focus", function(e){
15636 document.activeElement.blur();
15639 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15646 renderTouchView : function()
15648 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15649 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15651 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15652 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15654 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15655 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15656 this.touchViewBodyEl.setStyle('overflow', 'auto');
15658 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15659 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15661 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15662 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15666 showTouchView : function()
15672 this.touchViewHeaderEl.hide();
15674 if(this.modalTitle.length){
15675 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15676 this.touchViewHeaderEl.show();
15679 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15680 this.touchViewEl.show();
15682 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15684 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15685 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15687 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15689 if(this.modalTitle.length){
15690 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15693 this.touchViewBodyEl.setHeight(bodyHeight);
15697 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15699 this.touchViewEl.addClass('in');
15702 if(this._touchViewMask){
15703 Roo.get(document.body).addClass("x-body-masked");
15704 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15705 this._touchViewMask.setStyle('z-index', 10000);
15706 this._touchViewMask.addClass('show');
15709 this.doTouchViewQuery();
15713 hideTouchView : function()
15715 this.touchViewEl.removeClass('in');
15719 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15721 this.touchViewEl.setStyle('display', 'none');
15724 if(this._touchViewMask){
15725 this._touchViewMask.removeClass('show');
15726 Roo.get(document.body).removeClass("x-body-masked");
15730 setTouchViewValue : function()
15737 Roo.each(this.tickItems, function(o){
15742 this.hideTouchView();
15745 doTouchViewQuery : function()
15754 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15758 if(!this.alwaysQuery || this.mode == 'local'){
15759 this.onTouchViewLoad();
15766 onTouchViewBeforeLoad : function(combo,opts)
15772 onTouchViewLoad : function()
15774 if(this.store.getCount() < 1){
15775 this.onTouchViewEmptyResults();
15779 this.clearTouchView();
15781 var rawValue = this.getRawValue();
15783 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15785 this.tickItems = [];
15787 this.store.data.each(function(d, rowIndex){
15788 var row = this.touchViewListGroup.createChild(template);
15790 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15791 row.addClass(d.data.cls);
15794 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15797 html : d.data[this.displayField]
15800 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15801 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15804 row.removeClass('selected');
15805 if(!this.multiple && this.valueField &&
15806 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15809 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15810 row.addClass('selected');
15813 if(this.multiple && this.valueField &&
15814 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15818 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15819 this.tickItems.push(d.data);
15822 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15826 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15828 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15830 if(this.modalTitle.length){
15831 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15834 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15836 if(this.mobile_restrict_height && listHeight < bodyHeight){
15837 this.touchViewBodyEl.setHeight(listHeight);
15842 if(firstChecked && listHeight > bodyHeight){
15843 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15848 onTouchViewLoadException : function()
15850 this.hideTouchView();
15853 onTouchViewEmptyResults : function()
15855 this.clearTouchView();
15857 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15859 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15863 clearTouchView : function()
15865 this.touchViewListGroup.dom.innerHTML = '';
15868 onTouchViewClick : function(e, el, o)
15870 e.preventDefault();
15873 var rowIndex = o.rowIndex;
15875 var r = this.store.getAt(rowIndex);
15877 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15879 if(!this.multiple){
15880 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15881 c.dom.removeAttribute('checked');
15884 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15886 this.setFromData(r.data);
15888 var close = this.closeTriggerEl();
15894 this.hideTouchView();
15896 this.fireEvent('select', this, r, rowIndex);
15901 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15902 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15903 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15907 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15908 this.addItem(r.data);
15909 this.tickItems.push(r.data);
15913 getAutoCreateNativeIOS : function()
15916 cls: 'form-group' //input-group,
15921 cls : 'roo-ios-select'
15925 combobox.name = this.name;
15928 if (this.disabled) {
15929 combobox.disabled = true;
15932 var settings = this;
15934 ['xs','sm','md','lg'].map(function(size){
15935 if (settings[size]) {
15936 cfg.cls += ' col-' + size + '-' + settings[size];
15946 initIOSView : function()
15948 this.store.on('load', this.onIOSViewLoad, this);
15953 onIOSViewLoad : function()
15955 if(this.store.getCount() < 1){
15959 this.clearIOSView();
15961 if(this.allowBlank) {
15963 var default_text = '-- SELECT --';
15965 if(this.placeholder.length){
15966 default_text = this.placeholder;
15969 if(this.emptyTitle.length){
15970 default_text += ' - ' + this.emptyTitle + ' -';
15973 var opt = this.inputEl().createChild({
15976 html : default_text
15980 o[this.valueField] = 0;
15981 o[this.displayField] = default_text;
15983 this.ios_options.push({
15990 this.store.data.each(function(d, rowIndex){
15994 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15995 html = d.data[this.displayField];
16000 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16001 value = d.data[this.valueField];
16010 if(this.value == d.data[this.valueField]){
16011 option['selected'] = true;
16014 var opt = this.inputEl().createChild(option);
16016 this.ios_options.push({
16023 this.inputEl().on('change', function(){
16024 this.fireEvent('select', this);
16029 clearIOSView: function()
16031 this.inputEl().dom.innerHTML = '';
16033 this.ios_options = [];
16036 setIOSValue: function(v)
16040 if(!this.ios_options){
16044 Roo.each(this.ios_options, function(opts){
16046 opts.el.dom.removeAttribute('selected');
16048 if(opts.data[this.valueField] != v){
16052 opts.el.dom.setAttribute('selected', true);
16058 * @cfg {Boolean} grow
16062 * @cfg {Number} growMin
16066 * @cfg {Number} growMax
16075 Roo.apply(Roo.bootstrap.ComboBox, {
16079 cls: 'modal-header',
16101 cls: 'list-group-item',
16105 cls: 'roo-combobox-list-group-item-value'
16109 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16123 listItemCheckbox : {
16125 cls: 'list-group-item',
16129 cls: 'roo-combobox-list-group-item-value'
16133 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16149 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16154 cls: 'modal-footer',
16162 cls: 'col-xs-6 text-left',
16165 cls: 'btn btn-danger roo-touch-view-cancel',
16171 cls: 'col-xs-6 text-right',
16174 cls: 'btn btn-success roo-touch-view-ok',
16185 Roo.apply(Roo.bootstrap.ComboBox, {
16187 touchViewTemplate : {
16189 cls: 'modal fade roo-combobox-touch-view',
16193 cls: 'modal-dialog',
16194 style : 'position:fixed', // we have to fix position....
16198 cls: 'modal-content',
16200 Roo.bootstrap.ComboBox.header,
16201 Roo.bootstrap.ComboBox.body,
16202 Roo.bootstrap.ComboBox.footer
16211 * Ext JS Library 1.1.1
16212 * Copyright(c) 2006-2007, Ext JS, LLC.
16214 * Originally Released Under LGPL - original licence link has changed is not relivant.
16217 * <script type="text/javascript">
16222 * @extends Roo.util.Observable
16223 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16224 * This class also supports single and multi selection modes. <br>
16225 * Create a data model bound view:
16227 var store = new Roo.data.Store(...);
16229 var view = new Roo.View({
16231 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16233 singleSelect: true,
16234 selectedClass: "ydataview-selected",
16238 // listen for node click?
16239 view.on("click", function(vw, index, node, e){
16240 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16244 dataModel.load("foobar.xml");
16246 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16248 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16249 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16251 * Note: old style constructor is still suported (container, template, config)
16254 * Create a new View
16255 * @param {Object} config The config object
16258 Roo.View = function(config, depreciated_tpl, depreciated_config){
16260 this.parent = false;
16262 if (typeof(depreciated_tpl) == 'undefined') {
16263 // new way.. - universal constructor.
16264 Roo.apply(this, config);
16265 this.el = Roo.get(this.el);
16268 this.el = Roo.get(config);
16269 this.tpl = depreciated_tpl;
16270 Roo.apply(this, depreciated_config);
16272 this.wrapEl = this.el.wrap().wrap();
16273 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16276 if(typeof(this.tpl) == "string"){
16277 this.tpl = new Roo.Template(this.tpl);
16279 // support xtype ctors..
16280 this.tpl = new Roo.factory(this.tpl, Roo);
16284 this.tpl.compile();
16289 * @event beforeclick
16290 * Fires before a click is processed. Returns false to cancel the default action.
16291 * @param {Roo.View} this
16292 * @param {Number} index The index of the target node
16293 * @param {HTMLElement} node The target node
16294 * @param {Roo.EventObject} e The raw event object
16296 "beforeclick" : true,
16299 * Fires when a template node is clicked.
16300 * @param {Roo.View} this
16301 * @param {Number} index The index of the target node
16302 * @param {HTMLElement} node The target node
16303 * @param {Roo.EventObject} e The raw event object
16308 * Fires when a template node is double clicked.
16309 * @param {Roo.View} this
16310 * @param {Number} index The index of the target node
16311 * @param {HTMLElement} node The target node
16312 * @param {Roo.EventObject} e The raw event object
16316 * @event contextmenu
16317 * Fires when a template node is right clicked.
16318 * @param {Roo.View} this
16319 * @param {Number} index The index of the target node
16320 * @param {HTMLElement} node The target node
16321 * @param {Roo.EventObject} e The raw event object
16323 "contextmenu" : true,
16325 * @event selectionchange
16326 * Fires when the selected nodes change.
16327 * @param {Roo.View} this
16328 * @param {Array} selections Array of the selected nodes
16330 "selectionchange" : true,
16333 * @event beforeselect
16334 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16335 * @param {Roo.View} this
16336 * @param {HTMLElement} node The node to be selected
16337 * @param {Array} selections Array of currently selected nodes
16339 "beforeselect" : true,
16341 * @event preparedata
16342 * Fires on every row to render, to allow you to change the data.
16343 * @param {Roo.View} this
16344 * @param {Object} data to be rendered (change this)
16346 "preparedata" : true
16354 "click": this.onClick,
16355 "dblclick": this.onDblClick,
16356 "contextmenu": this.onContextMenu,
16360 this.selections = [];
16362 this.cmp = new Roo.CompositeElementLite([]);
16364 this.store = Roo.factory(this.store, Roo.data);
16365 this.setStore(this.store, true);
16368 if ( this.footer && this.footer.xtype) {
16370 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16372 this.footer.dataSource = this.store;
16373 this.footer.container = fctr;
16374 this.footer = Roo.factory(this.footer, Roo);
16375 fctr.insertFirst(this.el);
16377 // this is a bit insane - as the paging toolbar seems to detach the el..
16378 // dom.parentNode.parentNode.parentNode
16379 // they get detached?
16383 Roo.View.superclass.constructor.call(this);
16388 Roo.extend(Roo.View, Roo.util.Observable, {
16391 * @cfg {Roo.data.Store} store Data store to load data from.
16396 * @cfg {String|Roo.Element} el The container element.
16401 * @cfg {String|Roo.Template} tpl The template used by this View
16405 * @cfg {String} dataName the named area of the template to use as the data area
16406 * Works with domtemplates roo-name="name"
16410 * @cfg {String} selectedClass The css class to add to selected nodes
16412 selectedClass : "x-view-selected",
16414 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16419 * @cfg {String} text to display on mask (default Loading)
16423 * @cfg {Boolean} multiSelect Allow multiple selection
16425 multiSelect : false,
16427 * @cfg {Boolean} singleSelect Allow single selection
16429 singleSelect: false,
16432 * @cfg {Boolean} toggleSelect - selecting
16434 toggleSelect : false,
16437 * @cfg {Boolean} tickable - selecting
16442 * Returns the element this view is bound to.
16443 * @return {Roo.Element}
16445 getEl : function(){
16446 return this.wrapEl;
16452 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16454 refresh : function(){
16455 //Roo.log('refresh');
16458 // if we are using something like 'domtemplate', then
16459 // the what gets used is:
16460 // t.applySubtemplate(NAME, data, wrapping data..)
16461 // the outer template then get' applied with
16462 // the store 'extra data'
16463 // and the body get's added to the
16464 // roo-name="data" node?
16465 // <span class='roo-tpl-{name}'></span> ?????
16469 this.clearSelections();
16470 this.el.update("");
16472 var records = this.store.getRange();
16473 if(records.length < 1) {
16475 // is this valid?? = should it render a template??
16477 this.el.update(this.emptyText);
16481 if (this.dataName) {
16482 this.el.update(t.apply(this.store.meta)); //????
16483 el = this.el.child('.roo-tpl-' + this.dataName);
16486 for(var i = 0, len = records.length; i < len; i++){
16487 var data = this.prepareData(records[i].data, i, records[i]);
16488 this.fireEvent("preparedata", this, data, i, records[i]);
16490 var d = Roo.apply({}, data);
16493 Roo.apply(d, {'roo-id' : Roo.id()});
16497 Roo.each(this.parent.item, function(item){
16498 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16501 Roo.apply(d, {'roo-data-checked' : 'checked'});
16505 html[html.length] = Roo.util.Format.trim(
16507 t.applySubtemplate(this.dataName, d, this.store.meta) :
16514 el.update(html.join(""));
16515 this.nodes = el.dom.childNodes;
16516 this.updateIndexes(0);
16521 * Function to override to reformat the data that is sent to
16522 * the template for each node.
16523 * DEPRICATED - use the preparedata event handler.
16524 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16525 * a JSON object for an UpdateManager bound view).
16527 prepareData : function(data, index, record)
16529 this.fireEvent("preparedata", this, data, index, record);
16533 onUpdate : function(ds, record){
16534 // Roo.log('on update');
16535 this.clearSelections();
16536 var index = this.store.indexOf(record);
16537 var n = this.nodes[index];
16538 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16539 n.parentNode.removeChild(n);
16540 this.updateIndexes(index, index);
16546 onAdd : function(ds, records, index)
16548 //Roo.log(['on Add', ds, records, index] );
16549 this.clearSelections();
16550 if(this.nodes.length == 0){
16554 var n = this.nodes[index];
16555 for(var i = 0, len = records.length; i < len; i++){
16556 var d = this.prepareData(records[i].data, i, records[i]);
16558 this.tpl.insertBefore(n, d);
16561 this.tpl.append(this.el, d);
16564 this.updateIndexes(index);
16567 onRemove : function(ds, record, index){
16568 // Roo.log('onRemove');
16569 this.clearSelections();
16570 var el = this.dataName ?
16571 this.el.child('.roo-tpl-' + this.dataName) :
16574 el.dom.removeChild(this.nodes[index]);
16575 this.updateIndexes(index);
16579 * Refresh an individual node.
16580 * @param {Number} index
16582 refreshNode : function(index){
16583 this.onUpdate(this.store, this.store.getAt(index));
16586 updateIndexes : function(startIndex, endIndex){
16587 var ns = this.nodes;
16588 startIndex = startIndex || 0;
16589 endIndex = endIndex || ns.length - 1;
16590 for(var i = startIndex; i <= endIndex; i++){
16591 ns[i].nodeIndex = i;
16596 * Changes the data store this view uses and refresh the view.
16597 * @param {Store} store
16599 setStore : function(store, initial){
16600 if(!initial && this.store){
16601 this.store.un("datachanged", this.refresh);
16602 this.store.un("add", this.onAdd);
16603 this.store.un("remove", this.onRemove);
16604 this.store.un("update", this.onUpdate);
16605 this.store.un("clear", this.refresh);
16606 this.store.un("beforeload", this.onBeforeLoad);
16607 this.store.un("load", this.onLoad);
16608 this.store.un("loadexception", this.onLoad);
16612 store.on("datachanged", this.refresh, this);
16613 store.on("add", this.onAdd, this);
16614 store.on("remove", this.onRemove, this);
16615 store.on("update", this.onUpdate, this);
16616 store.on("clear", this.refresh, this);
16617 store.on("beforeload", this.onBeforeLoad, this);
16618 store.on("load", this.onLoad, this);
16619 store.on("loadexception", this.onLoad, this);
16627 * onbeforeLoad - masks the loading area.
16630 onBeforeLoad : function(store,opts)
16632 //Roo.log('onBeforeLoad');
16634 this.el.update("");
16636 this.el.mask(this.mask ? this.mask : "Loading" );
16638 onLoad : function ()
16645 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16646 * @param {HTMLElement} node
16647 * @return {HTMLElement} The template node
16649 findItemFromChild : function(node){
16650 var el = this.dataName ?
16651 this.el.child('.roo-tpl-' + this.dataName,true) :
16654 if(!node || node.parentNode == el){
16657 var p = node.parentNode;
16658 while(p && p != el){
16659 if(p.parentNode == el){
16668 onClick : function(e){
16669 var item = this.findItemFromChild(e.getTarget());
16671 var index = this.indexOf(item);
16672 if(this.onItemClick(item, index, e) !== false){
16673 this.fireEvent("click", this, index, item, e);
16676 this.clearSelections();
16681 onContextMenu : function(e){
16682 var item = this.findItemFromChild(e.getTarget());
16684 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16689 onDblClick : function(e){
16690 var item = this.findItemFromChild(e.getTarget());
16692 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16696 onItemClick : function(item, index, e)
16698 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16701 if (this.toggleSelect) {
16702 var m = this.isSelected(item) ? 'unselect' : 'select';
16705 _t[m](item, true, false);
16708 if(this.multiSelect || this.singleSelect){
16709 if(this.multiSelect && e.shiftKey && this.lastSelection){
16710 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16712 this.select(item, this.multiSelect && e.ctrlKey);
16713 this.lastSelection = item;
16716 if(!this.tickable){
16717 e.preventDefault();
16725 * Get the number of selected nodes.
16728 getSelectionCount : function(){
16729 return this.selections.length;
16733 * Get the currently selected nodes.
16734 * @return {Array} An array of HTMLElements
16736 getSelectedNodes : function(){
16737 return this.selections;
16741 * Get the indexes of the selected nodes.
16744 getSelectedIndexes : function(){
16745 var indexes = [], s = this.selections;
16746 for(var i = 0, len = s.length; i < len; i++){
16747 indexes.push(s[i].nodeIndex);
16753 * Clear all selections
16754 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16756 clearSelections : function(suppressEvent){
16757 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16758 this.cmp.elements = this.selections;
16759 this.cmp.removeClass(this.selectedClass);
16760 this.selections = [];
16761 if(!suppressEvent){
16762 this.fireEvent("selectionchange", this, this.selections);
16768 * Returns true if the passed node is selected
16769 * @param {HTMLElement/Number} node The node or node index
16770 * @return {Boolean}
16772 isSelected : function(node){
16773 var s = this.selections;
16777 node = this.getNode(node);
16778 return s.indexOf(node) !== -1;
16783 * @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
16784 * @param {Boolean} keepExisting (optional) true to keep existing selections
16785 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16787 select : function(nodeInfo, keepExisting, suppressEvent){
16788 if(nodeInfo instanceof Array){
16790 this.clearSelections(true);
16792 for(var i = 0, len = nodeInfo.length; i < len; i++){
16793 this.select(nodeInfo[i], true, true);
16797 var node = this.getNode(nodeInfo);
16798 if(!node || this.isSelected(node)){
16799 return; // already selected.
16802 this.clearSelections(true);
16805 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16806 Roo.fly(node).addClass(this.selectedClass);
16807 this.selections.push(node);
16808 if(!suppressEvent){
16809 this.fireEvent("selectionchange", this, this.selections);
16817 * @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
16818 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16819 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16821 unselect : function(nodeInfo, keepExisting, suppressEvent)
16823 if(nodeInfo instanceof Array){
16824 Roo.each(this.selections, function(s) {
16825 this.unselect(s, nodeInfo);
16829 var node = this.getNode(nodeInfo);
16830 if(!node || !this.isSelected(node)){
16831 //Roo.log("not selected");
16832 return; // not selected.
16836 Roo.each(this.selections, function(s) {
16838 Roo.fly(node).removeClass(this.selectedClass);
16845 this.selections= ns;
16846 this.fireEvent("selectionchange", this, this.selections);
16850 * Gets a template node.
16851 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16852 * @return {HTMLElement} The node or null if it wasn't found
16854 getNode : function(nodeInfo){
16855 if(typeof nodeInfo == "string"){
16856 return document.getElementById(nodeInfo);
16857 }else if(typeof nodeInfo == "number"){
16858 return this.nodes[nodeInfo];
16864 * Gets a range template nodes.
16865 * @param {Number} startIndex
16866 * @param {Number} endIndex
16867 * @return {Array} An array of nodes
16869 getNodes : function(start, end){
16870 var ns = this.nodes;
16871 start = start || 0;
16872 end = typeof end == "undefined" ? ns.length - 1 : end;
16875 for(var i = start; i <= end; i++){
16879 for(var i = start; i >= end; i--){
16887 * Finds the index of the passed node
16888 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16889 * @return {Number} The index of the node or -1
16891 indexOf : function(node){
16892 node = this.getNode(node);
16893 if(typeof node.nodeIndex == "number"){
16894 return node.nodeIndex;
16896 var ns = this.nodes;
16897 for(var i = 0, len = ns.length; i < len; i++){
16908 * based on jquery fullcalendar
16912 Roo.bootstrap = Roo.bootstrap || {};
16914 * @class Roo.bootstrap.Calendar
16915 * @extends Roo.bootstrap.Component
16916 * Bootstrap Calendar class
16917 * @cfg {Boolean} loadMask (true|false) default false
16918 * @cfg {Object} header generate the user specific header of the calendar, default false
16921 * Create a new Container
16922 * @param {Object} config The config object
16927 Roo.bootstrap.Calendar = function(config){
16928 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16932 * Fires when a date is selected
16933 * @param {DatePicker} this
16934 * @param {Date} date The selected date
16938 * @event monthchange
16939 * Fires when the displayed month changes
16940 * @param {DatePicker} this
16941 * @param {Date} date The selected month
16943 'monthchange': true,
16945 * @event evententer
16946 * Fires when mouse over an event
16947 * @param {Calendar} this
16948 * @param {event} Event
16950 'evententer': true,
16952 * @event eventleave
16953 * Fires when the mouse leaves an
16954 * @param {Calendar} this
16957 'eventleave': true,
16959 * @event eventclick
16960 * Fires when the mouse click an
16961 * @param {Calendar} this
16970 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16973 * @cfg {Number} startDay
16974 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16982 getAutoCreate : function(){
16985 var fc_button = function(name, corner, style, content ) {
16986 return Roo.apply({},{
16988 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16990 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16993 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17004 style : 'width:100%',
17011 cls : 'fc-header-left',
17013 fc_button('prev', 'left', 'arrow', '‹' ),
17014 fc_button('next', 'right', 'arrow', '›' ),
17015 { tag: 'span', cls: 'fc-header-space' },
17016 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17024 cls : 'fc-header-center',
17028 cls: 'fc-header-title',
17031 html : 'month / year'
17039 cls : 'fc-header-right',
17041 /* fc_button('month', 'left', '', 'month' ),
17042 fc_button('week', '', '', 'week' ),
17043 fc_button('day', 'right', '', 'day' )
17055 header = this.header;
17058 var cal_heads = function() {
17060 // fixme - handle this.
17062 for (var i =0; i < Date.dayNames.length; i++) {
17063 var d = Date.dayNames[i];
17066 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17067 html : d.substring(0,3)
17071 ret[0].cls += ' fc-first';
17072 ret[6].cls += ' fc-last';
17075 var cal_cell = function(n) {
17078 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17083 cls: 'fc-day-number',
17087 cls: 'fc-day-content',
17091 style: 'position: relative;' // height: 17px;
17103 var cal_rows = function() {
17106 for (var r = 0; r < 6; r++) {
17113 for (var i =0; i < Date.dayNames.length; i++) {
17114 var d = Date.dayNames[i];
17115 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17118 row.cn[0].cls+=' fc-first';
17119 row.cn[0].cn[0].style = 'min-height:90px';
17120 row.cn[6].cls+=' fc-last';
17124 ret[0].cls += ' fc-first';
17125 ret[4].cls += ' fc-prev-last';
17126 ret[5].cls += ' fc-last';
17133 cls: 'fc-border-separate',
17134 style : 'width:100%',
17142 cls : 'fc-first fc-last',
17160 cls : 'fc-content',
17161 style : "position: relative;",
17164 cls : 'fc-view fc-view-month fc-grid',
17165 style : 'position: relative',
17166 unselectable : 'on',
17169 cls : 'fc-event-container',
17170 style : 'position:absolute;z-index:8;top:0;left:0;'
17188 initEvents : function()
17191 throw "can not find store for calendar";
17197 style: "text-align:center",
17201 style: "background-color:white;width:50%;margin:250 auto",
17205 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17216 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17218 var size = this.el.select('.fc-content', true).first().getSize();
17219 this.maskEl.setSize(size.width, size.height);
17220 this.maskEl.enableDisplayMode("block");
17221 if(!this.loadMask){
17222 this.maskEl.hide();
17225 this.store = Roo.factory(this.store, Roo.data);
17226 this.store.on('load', this.onLoad, this);
17227 this.store.on('beforeload', this.onBeforeLoad, this);
17231 this.cells = this.el.select('.fc-day',true);
17232 //Roo.log(this.cells);
17233 this.textNodes = this.el.query('.fc-day-number');
17234 this.cells.addClassOnOver('fc-state-hover');
17236 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17237 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17238 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17239 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17241 this.on('monthchange', this.onMonthChange, this);
17243 this.update(new Date().clearTime());
17246 resize : function() {
17247 var sz = this.el.getSize();
17249 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17250 this.el.select('.fc-day-content div',true).setHeight(34);
17255 showPrevMonth : function(e){
17256 this.update(this.activeDate.add("mo", -1));
17258 showToday : function(e){
17259 this.update(new Date().clearTime());
17262 showNextMonth : function(e){
17263 this.update(this.activeDate.add("mo", 1));
17267 showPrevYear : function(){
17268 this.update(this.activeDate.add("y", -1));
17272 showNextYear : function(){
17273 this.update(this.activeDate.add("y", 1));
17278 update : function(date)
17280 var vd = this.activeDate;
17281 this.activeDate = date;
17282 // if(vd && this.el){
17283 // var t = date.getTime();
17284 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17285 // Roo.log('using add remove');
17287 // this.fireEvent('monthchange', this, date);
17289 // this.cells.removeClass("fc-state-highlight");
17290 // this.cells.each(function(c){
17291 // if(c.dateValue == t){
17292 // c.addClass("fc-state-highlight");
17293 // setTimeout(function(){
17294 // try{c.dom.firstChild.focus();}catch(e){}
17304 var days = date.getDaysInMonth();
17306 var firstOfMonth = date.getFirstDateOfMonth();
17307 var startingPos = firstOfMonth.getDay()-this.startDay;
17309 if(startingPos < this.startDay){
17313 var pm = date.add(Date.MONTH, -1);
17314 var prevStart = pm.getDaysInMonth()-startingPos;
17316 this.cells = this.el.select('.fc-day',true);
17317 this.textNodes = this.el.query('.fc-day-number');
17318 this.cells.addClassOnOver('fc-state-hover');
17320 var cells = this.cells.elements;
17321 var textEls = this.textNodes;
17323 Roo.each(cells, function(cell){
17324 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17327 days += startingPos;
17329 // convert everything to numbers so it's fast
17330 var day = 86400000;
17331 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17334 //Roo.log(prevStart);
17336 var today = new Date().clearTime().getTime();
17337 var sel = date.clearTime().getTime();
17338 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17339 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17340 var ddMatch = this.disabledDatesRE;
17341 var ddText = this.disabledDatesText;
17342 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17343 var ddaysText = this.disabledDaysText;
17344 var format = this.format;
17346 var setCellClass = function(cal, cell){
17350 //Roo.log('set Cell Class');
17352 var t = d.getTime();
17356 cell.dateValue = t;
17358 cell.className += " fc-today";
17359 cell.className += " fc-state-highlight";
17360 cell.title = cal.todayText;
17363 // disable highlight in other month..
17364 //cell.className += " fc-state-highlight";
17369 cell.className = " fc-state-disabled";
17370 cell.title = cal.minText;
17374 cell.className = " fc-state-disabled";
17375 cell.title = cal.maxText;
17379 if(ddays.indexOf(d.getDay()) != -1){
17380 cell.title = ddaysText;
17381 cell.className = " fc-state-disabled";
17384 if(ddMatch && format){
17385 var fvalue = d.dateFormat(format);
17386 if(ddMatch.test(fvalue)){
17387 cell.title = ddText.replace("%0", fvalue);
17388 cell.className = " fc-state-disabled";
17392 if (!cell.initialClassName) {
17393 cell.initialClassName = cell.dom.className;
17396 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17401 for(; i < startingPos; i++) {
17402 textEls[i].innerHTML = (++prevStart);
17403 d.setDate(d.getDate()+1);
17405 cells[i].className = "fc-past fc-other-month";
17406 setCellClass(this, cells[i]);
17411 for(; i < days; i++){
17412 intDay = i - startingPos + 1;
17413 textEls[i].innerHTML = (intDay);
17414 d.setDate(d.getDate()+1);
17416 cells[i].className = ''; // "x-date-active";
17417 setCellClass(this, cells[i]);
17421 for(; i < 42; i++) {
17422 textEls[i].innerHTML = (++extraDays);
17423 d.setDate(d.getDate()+1);
17425 cells[i].className = "fc-future fc-other-month";
17426 setCellClass(this, cells[i]);
17429 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17431 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17433 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17434 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17436 if(totalRows != 6){
17437 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17438 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17441 this.fireEvent('monthchange', this, date);
17445 if(!this.internalRender){
17446 var main = this.el.dom.firstChild;
17447 var w = main.offsetWidth;
17448 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17449 Roo.fly(main).setWidth(w);
17450 this.internalRender = true;
17451 // opera does not respect the auto grow header center column
17452 // then, after it gets a width opera refuses to recalculate
17453 // without a second pass
17454 if(Roo.isOpera && !this.secondPass){
17455 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17456 this.secondPass = true;
17457 this.update.defer(10, this, [date]);
17464 findCell : function(dt) {
17465 dt = dt.clearTime().getTime();
17467 this.cells.each(function(c){
17468 //Roo.log("check " +c.dateValue + '?=' + dt);
17469 if(c.dateValue == dt){
17479 findCells : function(ev) {
17480 var s = ev.start.clone().clearTime().getTime();
17482 var e= ev.end.clone().clearTime().getTime();
17485 this.cells.each(function(c){
17486 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17488 if(c.dateValue > e){
17491 if(c.dateValue < s){
17500 // findBestRow: function(cells)
17504 // for (var i =0 ; i < cells.length;i++) {
17505 // ret = Math.max(cells[i].rows || 0,ret);
17512 addItem : function(ev)
17514 // look for vertical location slot in
17515 var cells = this.findCells(ev);
17517 // ev.row = this.findBestRow(cells);
17519 // work out the location.
17523 for(var i =0; i < cells.length; i++) {
17525 cells[i].row = cells[0].row;
17528 cells[i].row = cells[i].row + 1;
17538 if (crow.start.getY() == cells[i].getY()) {
17540 crow.end = cells[i];
17557 cells[0].events.push(ev);
17559 this.calevents.push(ev);
17562 clearEvents: function() {
17564 if(!this.calevents){
17568 Roo.each(this.cells.elements, function(c){
17574 Roo.each(this.calevents, function(e) {
17575 Roo.each(e.els, function(el) {
17576 el.un('mouseenter' ,this.onEventEnter, this);
17577 el.un('mouseleave' ,this.onEventLeave, this);
17582 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17588 renderEvents: function()
17592 this.cells.each(function(c) {
17601 if(c.row != c.events.length){
17602 r = 4 - (4 - (c.row - c.events.length));
17605 c.events = ev.slice(0, r);
17606 c.more = ev.slice(r);
17608 if(c.more.length && c.more.length == 1){
17609 c.events.push(c.more.pop());
17612 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17616 this.cells.each(function(c) {
17618 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17621 for (var e = 0; e < c.events.length; e++){
17622 var ev = c.events[e];
17623 var rows = ev.rows;
17625 for(var i = 0; i < rows.length; i++) {
17627 // how many rows should it span..
17630 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17631 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17633 unselectable : "on",
17636 cls: 'fc-event-inner',
17640 // cls: 'fc-event-time',
17641 // html : cells.length > 1 ? '' : ev.time
17645 cls: 'fc-event-title',
17646 html : String.format('{0}', ev.title)
17653 cls: 'ui-resizable-handle ui-resizable-e',
17654 html : '  '
17661 cfg.cls += ' fc-event-start';
17663 if ((i+1) == rows.length) {
17664 cfg.cls += ' fc-event-end';
17667 var ctr = _this.el.select('.fc-event-container',true).first();
17668 var cg = ctr.createChild(cfg);
17670 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17671 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17673 var r = (c.more.length) ? 1 : 0;
17674 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17675 cg.setWidth(ebox.right - sbox.x -2);
17677 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17678 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17679 cg.on('click', _this.onEventClick, _this, ev);
17690 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17691 style : 'position: absolute',
17692 unselectable : "on",
17695 cls: 'fc-event-inner',
17699 cls: 'fc-event-title',
17707 cls: 'ui-resizable-handle ui-resizable-e',
17708 html : '  '
17714 var ctr = _this.el.select('.fc-event-container',true).first();
17715 var cg = ctr.createChild(cfg);
17717 var sbox = c.select('.fc-day-content',true).first().getBox();
17718 var ebox = c.select('.fc-day-content',true).first().getBox();
17720 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17721 cg.setWidth(ebox.right - sbox.x -2);
17723 cg.on('click', _this.onMoreEventClick, _this, c.more);
17733 onEventEnter: function (e, el,event,d) {
17734 this.fireEvent('evententer', this, el, event);
17737 onEventLeave: function (e, el,event,d) {
17738 this.fireEvent('eventleave', this, el, event);
17741 onEventClick: function (e, el,event,d) {
17742 this.fireEvent('eventclick', this, el, event);
17745 onMonthChange: function () {
17749 onMoreEventClick: function(e, el, more)
17753 this.calpopover.placement = 'right';
17754 this.calpopover.setTitle('More');
17756 this.calpopover.setContent('');
17758 var ctr = this.calpopover.el.select('.popover-content', true).first();
17760 Roo.each(more, function(m){
17762 cls : 'fc-event-hori fc-event-draggable',
17765 var cg = ctr.createChild(cfg);
17767 cg.on('click', _this.onEventClick, _this, m);
17770 this.calpopover.show(el);
17775 onLoad: function ()
17777 this.calevents = [];
17780 if(this.store.getCount() > 0){
17781 this.store.data.each(function(d){
17784 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17785 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17786 time : d.data.start_time,
17787 title : d.data.title,
17788 description : d.data.description,
17789 venue : d.data.venue
17794 this.renderEvents();
17796 if(this.calevents.length && this.loadMask){
17797 this.maskEl.hide();
17801 onBeforeLoad: function()
17803 this.clearEvents();
17805 this.maskEl.show();
17819 * @class Roo.bootstrap.Popover
17820 * @extends Roo.bootstrap.Component
17821 * Bootstrap Popover class
17822 * @cfg {String} html contents of the popover (or false to use children..)
17823 * @cfg {String} title of popover (or false to hide)
17824 * @cfg {String} placement how it is placed
17825 * @cfg {String} trigger click || hover (or false to trigger manually)
17826 * @cfg {String} over what (parent or false to trigger manually.)
17827 * @cfg {Number} delay - delay before showing
17830 * Create a new Popover
17831 * @param {Object} config The config object
17834 Roo.bootstrap.Popover = function(config){
17835 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17841 * After the popover show
17843 * @param {Roo.bootstrap.Popover} this
17848 * After the popover hide
17850 * @param {Roo.bootstrap.Popover} this
17856 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17858 title: 'Fill in a title',
17861 placement : 'right',
17862 trigger : 'hover', // hover
17868 can_build_overlaid : false,
17870 getChildContainer : function()
17872 return this.el.select('.popover-content',true).first();
17875 getAutoCreate : function(){
17878 cls : 'popover roo-dynamic',
17879 style: 'display:block',
17885 cls : 'popover-inner',
17889 cls: 'popover-title popover-header',
17893 cls : 'popover-content popover-body',
17904 setTitle: function(str)
17907 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17909 setContent: function(str)
17912 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17914 // as it get's added to the bottom of the page.
17915 onRender : function(ct, position)
17917 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17919 var cfg = Roo.apply({}, this.getAutoCreate());
17923 cfg.cls += ' ' + this.cls;
17926 cfg.style = this.style;
17928 //Roo.log("adding to ");
17929 this.el = Roo.get(document.body).createChild(cfg, position);
17930 // Roo.log(this.el);
17935 initEvents : function()
17937 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17938 this.el.enableDisplayMode('block');
17940 if (this.over === false) {
17943 if (this.triggers === false) {
17946 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17947 var triggers = this.trigger ? this.trigger.split(' ') : [];
17948 Roo.each(triggers, function(trigger) {
17950 if (trigger == 'click') {
17951 on_el.on('click', this.toggle, this);
17952 } else if (trigger != 'manual') {
17953 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17954 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17956 on_el.on(eventIn ,this.enter, this);
17957 on_el.on(eventOut, this.leave, this);
17968 toggle : function () {
17969 this.hoverState == 'in' ? this.leave() : this.enter();
17972 enter : function () {
17974 clearTimeout(this.timeout);
17976 this.hoverState = 'in';
17978 if (!this.delay || !this.delay.show) {
17983 this.timeout = setTimeout(function () {
17984 if (_t.hoverState == 'in') {
17987 }, this.delay.show)
17990 leave : function() {
17991 clearTimeout(this.timeout);
17993 this.hoverState = 'out';
17995 if (!this.delay || !this.delay.hide) {
18000 this.timeout = setTimeout(function () {
18001 if (_t.hoverState == 'out') {
18004 }, this.delay.hide)
18007 show : function (on_el)
18010 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18014 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18015 if (this.html !== false) {
18016 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18018 this.el.removeClass([
18019 'fade','top','bottom', 'left', 'right','in',
18020 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18022 if (!this.title.length) {
18023 this.el.select('.popover-title',true).hide();
18026 var placement = typeof this.placement == 'function' ?
18027 this.placement.call(this, this.el, on_el) :
18030 var autoToken = /\s?auto?\s?/i;
18031 var autoPlace = autoToken.test(placement);
18033 placement = placement.replace(autoToken, '') || 'top';
18037 //this.el.setXY([0,0]);
18039 this.el.dom.style.display='block';
18040 this.el.addClass(placement);
18042 //this.el.appendTo(on_el);
18044 var p = this.getPosition();
18045 var box = this.el.getBox();
18050 var align = Roo.bootstrap.Popover.alignment[placement];
18053 this.el.alignTo(on_el, align[0],align[1]);
18054 //var arrow = this.el.select('.arrow',true).first();
18055 //arrow.set(align[2],
18057 this.el.addClass('in');
18060 if (this.el.hasClass('fade')) {
18064 this.hoverState = 'in';
18066 this.fireEvent('show', this);
18071 this.el.setXY([0,0]);
18072 this.el.removeClass('in');
18074 this.hoverState = null;
18076 this.fireEvent('hide', this);
18081 Roo.bootstrap.Popover.alignment = {
18082 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18083 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18084 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18085 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18096 * @class Roo.bootstrap.Progress
18097 * @extends Roo.bootstrap.Component
18098 * Bootstrap Progress class
18099 * @cfg {Boolean} striped striped of the progress bar
18100 * @cfg {Boolean} active animated of the progress bar
18104 * Create a new Progress
18105 * @param {Object} config The config object
18108 Roo.bootstrap.Progress = function(config){
18109 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18112 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18117 getAutoCreate : function(){
18125 cfg.cls += ' progress-striped';
18129 cfg.cls += ' active';
18148 * @class Roo.bootstrap.ProgressBar
18149 * @extends Roo.bootstrap.Component
18150 * Bootstrap ProgressBar class
18151 * @cfg {Number} aria_valuenow aria-value now
18152 * @cfg {Number} aria_valuemin aria-value min
18153 * @cfg {Number} aria_valuemax aria-value max
18154 * @cfg {String} label label for the progress bar
18155 * @cfg {String} panel (success | info | warning | danger )
18156 * @cfg {String} role role of the progress bar
18157 * @cfg {String} sr_only text
18161 * Create a new ProgressBar
18162 * @param {Object} config The config object
18165 Roo.bootstrap.ProgressBar = function(config){
18166 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18169 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18173 aria_valuemax : 100,
18179 getAutoCreate : function()
18184 cls: 'progress-bar',
18185 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18197 cfg.role = this.role;
18200 if(this.aria_valuenow){
18201 cfg['aria-valuenow'] = this.aria_valuenow;
18204 if(this.aria_valuemin){
18205 cfg['aria-valuemin'] = this.aria_valuemin;
18208 if(this.aria_valuemax){
18209 cfg['aria-valuemax'] = this.aria_valuemax;
18212 if(this.label && !this.sr_only){
18213 cfg.html = this.label;
18217 cfg.cls += ' progress-bar-' + this.panel;
18223 update : function(aria_valuenow)
18225 this.aria_valuenow = aria_valuenow;
18227 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18242 * @class Roo.bootstrap.TabGroup
18243 * @extends Roo.bootstrap.Column
18244 * Bootstrap Column class
18245 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18246 * @cfg {Boolean} carousel true to make the group behave like a carousel
18247 * @cfg {Boolean} bullets show bullets for the panels
18248 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18249 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18250 * @cfg {Boolean} showarrow (true|false) show arrow default true
18253 * Create a new TabGroup
18254 * @param {Object} config The config object
18257 Roo.bootstrap.TabGroup = function(config){
18258 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18260 this.navId = Roo.id();
18263 Roo.bootstrap.TabGroup.register(this);
18267 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18270 transition : false,
18275 slideOnTouch : false,
18278 getAutoCreate : function()
18280 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18282 cfg.cls += ' tab-content';
18284 if (this.carousel) {
18285 cfg.cls += ' carousel slide';
18288 cls : 'carousel-inner',
18292 if(this.bullets && !Roo.isTouch){
18295 cls : 'carousel-bullets',
18299 if(this.bullets_cls){
18300 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18307 cfg.cn[0].cn.push(bullets);
18310 if(this.showarrow){
18311 cfg.cn[0].cn.push({
18313 class : 'carousel-arrow',
18317 class : 'carousel-prev',
18321 class : 'fa fa-chevron-left'
18327 class : 'carousel-next',
18331 class : 'fa fa-chevron-right'
18344 initEvents: function()
18346 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18347 // this.el.on("touchstart", this.onTouchStart, this);
18350 if(this.autoslide){
18353 this.slideFn = window.setInterval(function() {
18354 _this.showPanelNext();
18358 if(this.showarrow){
18359 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18360 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18366 // onTouchStart : function(e, el, o)
18368 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18372 // this.showPanelNext();
18376 getChildContainer : function()
18378 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18382 * register a Navigation item
18383 * @param {Roo.bootstrap.NavItem} the navitem to add
18385 register : function(item)
18387 this.tabs.push( item);
18388 item.navId = this.navId; // not really needed..
18393 getActivePanel : function()
18396 Roo.each(this.tabs, function(t) {
18406 getPanelByName : function(n)
18409 Roo.each(this.tabs, function(t) {
18410 if (t.tabId == n) {
18418 indexOfPanel : function(p)
18421 Roo.each(this.tabs, function(t,i) {
18422 if (t.tabId == p.tabId) {
18431 * show a specific panel
18432 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18433 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18435 showPanel : function (pan)
18437 if(this.transition || typeof(pan) == 'undefined'){
18438 Roo.log("waiting for the transitionend");
18442 if (typeof(pan) == 'number') {
18443 pan = this.tabs[pan];
18446 if (typeof(pan) == 'string') {
18447 pan = this.getPanelByName(pan);
18450 var cur = this.getActivePanel();
18453 Roo.log('pan or acitve pan is undefined');
18457 if (pan.tabId == this.getActivePanel().tabId) {
18461 if (false === cur.fireEvent('beforedeactivate')) {
18465 if(this.bullets > 0 && !Roo.isTouch){
18466 this.setActiveBullet(this.indexOfPanel(pan));
18469 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18471 //class="carousel-item carousel-item-next carousel-item-left"
18473 this.transition = true;
18474 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18475 var lr = dir == 'next' ? 'left' : 'right';
18476 pan.el.addClass(dir); // or prev
18477 pan.el.addClass('carousel-item-' + dir); // or prev
18478 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18479 cur.el.addClass(lr); // or right
18480 pan.el.addClass(lr);
18481 cur.el.addClass('carousel-item-' +lr); // or right
18482 pan.el.addClass('carousel-item-' +lr);
18486 cur.el.on('transitionend', function() {
18487 Roo.log("trans end?");
18489 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18490 pan.setActive(true);
18492 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18493 cur.setActive(false);
18495 _this.transition = false;
18497 }, this, { single: true } );
18502 cur.setActive(false);
18503 pan.setActive(true);
18508 showPanelNext : function()
18510 var i = this.indexOfPanel(this.getActivePanel());
18512 if (i >= this.tabs.length - 1 && !this.autoslide) {
18516 if (i >= this.tabs.length - 1 && this.autoslide) {
18520 this.showPanel(this.tabs[i+1]);
18523 showPanelPrev : function()
18525 var i = this.indexOfPanel(this.getActivePanel());
18527 if (i < 1 && !this.autoslide) {
18531 if (i < 1 && this.autoslide) {
18532 i = this.tabs.length;
18535 this.showPanel(this.tabs[i-1]);
18539 addBullet: function()
18541 if(!this.bullets || Roo.isTouch){
18544 var ctr = this.el.select('.carousel-bullets',true).first();
18545 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18546 var bullet = ctr.createChild({
18547 cls : 'bullet bullet-' + i
18548 },ctr.dom.lastChild);
18553 bullet.on('click', (function(e, el, o, ii, t){
18555 e.preventDefault();
18557 this.showPanel(ii);
18559 if(this.autoslide && this.slideFn){
18560 clearInterval(this.slideFn);
18561 this.slideFn = window.setInterval(function() {
18562 _this.showPanelNext();
18566 }).createDelegate(this, [i, bullet], true));
18571 setActiveBullet : function(i)
18577 Roo.each(this.el.select('.bullet', true).elements, function(el){
18578 el.removeClass('selected');
18581 var bullet = this.el.select('.bullet-' + i, true).first();
18587 bullet.addClass('selected');
18598 Roo.apply(Roo.bootstrap.TabGroup, {
18602 * register a Navigation Group
18603 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18605 register : function(navgrp)
18607 this.groups[navgrp.navId] = navgrp;
18611 * fetch a Navigation Group based on the navigation ID
18612 * if one does not exist , it will get created.
18613 * @param {string} the navgroup to add
18614 * @returns {Roo.bootstrap.NavGroup} the navgroup
18616 get: function(navId) {
18617 if (typeof(this.groups[navId]) == 'undefined') {
18618 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18620 return this.groups[navId] ;
18635 * @class Roo.bootstrap.TabPanel
18636 * @extends Roo.bootstrap.Component
18637 * Bootstrap TabPanel class
18638 * @cfg {Boolean} active panel active
18639 * @cfg {String} html panel content
18640 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18641 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18642 * @cfg {String} href click to link..
18646 * Create a new TabPanel
18647 * @param {Object} config The config object
18650 Roo.bootstrap.TabPanel = function(config){
18651 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18655 * Fires when the active status changes
18656 * @param {Roo.bootstrap.TabPanel} this
18657 * @param {Boolean} state the new state
18662 * @event beforedeactivate
18663 * Fires before a tab is de-activated - can be used to do validation on a form.
18664 * @param {Roo.bootstrap.TabPanel} this
18665 * @return {Boolean} false if there is an error
18668 'beforedeactivate': true
18671 this.tabId = this.tabId || Roo.id();
18675 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18683 getAutoCreate : function(){
18688 // item is needed for carousel - not sure if it has any effect otherwise
18689 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18690 html: this.html || ''
18694 cfg.cls += ' active';
18698 cfg.tabId = this.tabId;
18706 initEvents: function()
18708 var p = this.parent();
18710 this.navId = this.navId || p.navId;
18712 if (typeof(this.navId) != 'undefined') {
18713 // not really needed.. but just in case.. parent should be a NavGroup.
18714 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18718 var i = tg.tabs.length - 1;
18720 if(this.active && tg.bullets > 0 && i < tg.bullets){
18721 tg.setActiveBullet(i);
18725 this.el.on('click', this.onClick, this);
18728 this.el.on("touchstart", this.onTouchStart, this);
18729 this.el.on("touchmove", this.onTouchMove, this);
18730 this.el.on("touchend", this.onTouchEnd, this);
18735 onRender : function(ct, position)
18737 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18740 setActive : function(state)
18742 Roo.log("panel - set active " + this.tabId + "=" + state);
18744 this.active = state;
18746 this.el.removeClass('active');
18748 } else if (!this.el.hasClass('active')) {
18749 this.el.addClass('active');
18752 this.fireEvent('changed', this, state);
18755 onClick : function(e)
18757 e.preventDefault();
18759 if(!this.href.length){
18763 window.location.href = this.href;
18772 onTouchStart : function(e)
18774 this.swiping = false;
18776 this.startX = e.browserEvent.touches[0].clientX;
18777 this.startY = e.browserEvent.touches[0].clientY;
18780 onTouchMove : function(e)
18782 this.swiping = true;
18784 this.endX = e.browserEvent.touches[0].clientX;
18785 this.endY = e.browserEvent.touches[0].clientY;
18788 onTouchEnd : function(e)
18795 var tabGroup = this.parent();
18797 if(this.endX > this.startX){ // swiping right
18798 tabGroup.showPanelPrev();
18802 if(this.startX > this.endX){ // swiping left
18803 tabGroup.showPanelNext();
18822 * @class Roo.bootstrap.DateField
18823 * @extends Roo.bootstrap.Input
18824 * Bootstrap DateField class
18825 * @cfg {Number} weekStart default 0
18826 * @cfg {String} viewMode default empty, (months|years)
18827 * @cfg {String} minViewMode default empty, (months|years)
18828 * @cfg {Number} startDate default -Infinity
18829 * @cfg {Number} endDate default Infinity
18830 * @cfg {Boolean} todayHighlight default false
18831 * @cfg {Boolean} todayBtn default false
18832 * @cfg {Boolean} calendarWeeks default false
18833 * @cfg {Object} daysOfWeekDisabled default empty
18834 * @cfg {Boolean} singleMode default false (true | false)
18836 * @cfg {Boolean} keyboardNavigation default true
18837 * @cfg {String} language default en
18840 * Create a new DateField
18841 * @param {Object} config The config object
18844 Roo.bootstrap.DateField = function(config){
18845 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18849 * Fires when this field show.
18850 * @param {Roo.bootstrap.DateField} this
18851 * @param {Mixed} date The date value
18856 * Fires when this field hide.
18857 * @param {Roo.bootstrap.DateField} this
18858 * @param {Mixed} date The date value
18863 * Fires when select a date.
18864 * @param {Roo.bootstrap.DateField} this
18865 * @param {Mixed} date The date value
18869 * @event beforeselect
18870 * Fires when before select a date.
18871 * @param {Roo.bootstrap.DateField} this
18872 * @param {Mixed} date The date value
18874 beforeselect : true
18878 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18881 * @cfg {String} format
18882 * The default date format string which can be overriden for localization support. The format must be
18883 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18887 * @cfg {String} altFormats
18888 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18889 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18891 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18899 todayHighlight : false,
18905 keyboardNavigation: true,
18907 calendarWeeks: false,
18909 startDate: -Infinity,
18913 daysOfWeekDisabled: [],
18917 singleMode : false,
18919 UTCDate: function()
18921 return new Date(Date.UTC.apply(Date, arguments));
18924 UTCToday: function()
18926 var today = new Date();
18927 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18930 getDate: function() {
18931 var d = this.getUTCDate();
18932 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18935 getUTCDate: function() {
18939 setDate: function(d) {
18940 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18943 setUTCDate: function(d) {
18945 this.setValue(this.formatDate(this.date));
18948 onRender: function(ct, position)
18951 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18953 this.language = this.language || 'en';
18954 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18955 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18957 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18958 this.format = this.format || 'm/d/y';
18959 this.isInline = false;
18960 this.isInput = true;
18961 this.component = this.el.select('.add-on', true).first() || false;
18962 this.component = (this.component && this.component.length === 0) ? false : this.component;
18963 this.hasInput = this.component && this.inputEl().length;
18965 if (typeof(this.minViewMode === 'string')) {
18966 switch (this.minViewMode) {
18968 this.minViewMode = 1;
18971 this.minViewMode = 2;
18974 this.minViewMode = 0;
18979 if (typeof(this.viewMode === 'string')) {
18980 switch (this.viewMode) {
18993 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18995 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18997 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18999 this.picker().on('mousedown', this.onMousedown, this);
19000 this.picker().on('click', this.onClick, this);
19002 this.picker().addClass('datepicker-dropdown');
19004 this.startViewMode = this.viewMode;
19006 if(this.singleMode){
19007 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19008 v.setVisibilityMode(Roo.Element.DISPLAY);
19012 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19013 v.setStyle('width', '189px');
19017 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19018 if(!this.calendarWeeks){
19023 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19024 v.attr('colspan', function(i, val){
19025 return parseInt(val) + 1;
19030 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19032 this.setStartDate(this.startDate);
19033 this.setEndDate(this.endDate);
19035 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19042 if(this.isInline) {
19047 picker : function()
19049 return this.pickerEl;
19050 // return this.el.select('.datepicker', true).first();
19053 fillDow: function()
19055 var dowCnt = this.weekStart;
19064 if(this.calendarWeeks){
19072 while (dowCnt < this.weekStart + 7) {
19076 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19080 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19083 fillMonths: function()
19086 var months = this.picker().select('>.datepicker-months td', true).first();
19088 months.dom.innerHTML = '';
19094 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19097 months.createChild(month);
19104 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;
19106 if (this.date < this.startDate) {
19107 this.viewDate = new Date(this.startDate);
19108 } else if (this.date > this.endDate) {
19109 this.viewDate = new Date(this.endDate);
19111 this.viewDate = new Date(this.date);
19119 var d = new Date(this.viewDate),
19120 year = d.getUTCFullYear(),
19121 month = d.getUTCMonth(),
19122 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19123 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19124 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19125 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19126 currentDate = this.date && this.date.valueOf(),
19127 today = this.UTCToday();
19129 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19131 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19133 // this.picker.select('>tfoot th.today').
19134 // .text(dates[this.language].today)
19135 // .toggle(this.todayBtn !== false);
19137 this.updateNavArrows();
19140 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19142 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19144 prevMonth.setUTCDate(day);
19146 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19148 var nextMonth = new Date(prevMonth);
19150 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19152 nextMonth = nextMonth.valueOf();
19154 var fillMonths = false;
19156 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19158 while(prevMonth.valueOf() <= nextMonth) {
19161 if (prevMonth.getUTCDay() === this.weekStart) {
19163 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19171 if(this.calendarWeeks){
19172 // ISO 8601: First week contains first thursday.
19173 // ISO also states week starts on Monday, but we can be more abstract here.
19175 // Start of current week: based on weekstart/current date
19176 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19177 // Thursday of this week
19178 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19179 // First Thursday of year, year from thursday
19180 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19181 // Calendar week: ms between thursdays, div ms per day, div 7 days
19182 calWeek = (th - yth) / 864e5 / 7 + 1;
19184 fillMonths.cn.push({
19192 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19194 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19197 if (this.todayHighlight &&
19198 prevMonth.getUTCFullYear() == today.getFullYear() &&
19199 prevMonth.getUTCMonth() == today.getMonth() &&
19200 prevMonth.getUTCDate() == today.getDate()) {
19201 clsName += ' today';
19204 if (currentDate && prevMonth.valueOf() === currentDate) {
19205 clsName += ' active';
19208 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19209 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19210 clsName += ' disabled';
19213 fillMonths.cn.push({
19215 cls: 'day ' + clsName,
19216 html: prevMonth.getDate()
19219 prevMonth.setDate(prevMonth.getDate()+1);
19222 var currentYear = this.date && this.date.getUTCFullYear();
19223 var currentMonth = this.date && this.date.getUTCMonth();
19225 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19227 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19228 v.removeClass('active');
19230 if(currentYear === year && k === currentMonth){
19231 v.addClass('active');
19234 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19235 v.addClass('disabled');
19241 year = parseInt(year/10, 10) * 10;
19243 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19245 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19248 for (var i = -1; i < 11; i++) {
19249 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19251 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19259 showMode: function(dir)
19262 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19265 Roo.each(this.picker().select('>div',true).elements, function(v){
19266 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19269 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19274 if(this.isInline) {
19278 this.picker().removeClass(['bottom', 'top']);
19280 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19282 * place to the top of element!
19286 this.picker().addClass('top');
19287 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19292 this.picker().addClass('bottom');
19294 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19297 parseDate : function(value)
19299 if(!value || value instanceof Date){
19302 var v = Date.parseDate(value, this.format);
19303 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19304 v = Date.parseDate(value, 'Y-m-d');
19306 if(!v && this.altFormats){
19307 if(!this.altFormatsArray){
19308 this.altFormatsArray = this.altFormats.split("|");
19310 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19311 v = Date.parseDate(value, this.altFormatsArray[i]);
19317 formatDate : function(date, fmt)
19319 return (!date || !(date instanceof Date)) ?
19320 date : date.dateFormat(fmt || this.format);
19323 onFocus : function()
19325 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19329 onBlur : function()
19331 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19333 var d = this.inputEl().getValue();
19340 showPopup : function()
19342 this.picker().show();
19346 this.fireEvent('showpopup', this, this.date);
19349 hidePopup : function()
19351 if(this.isInline) {
19354 this.picker().hide();
19355 this.viewMode = this.startViewMode;
19358 this.fireEvent('hidepopup', this, this.date);
19362 onMousedown: function(e)
19364 e.stopPropagation();
19365 e.preventDefault();
19370 Roo.bootstrap.DateField.superclass.keyup.call(this);
19374 setValue: function(v)
19376 if(this.fireEvent('beforeselect', this, v) !== false){
19377 var d = new Date(this.parseDate(v) ).clearTime();
19379 if(isNaN(d.getTime())){
19380 this.date = this.viewDate = '';
19381 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19385 v = this.formatDate(d);
19387 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19389 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19393 this.fireEvent('select', this, this.date);
19397 getValue: function()
19399 return this.formatDate(this.date);
19402 fireKey: function(e)
19404 if (!this.picker().isVisible()){
19405 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19411 var dateChanged = false,
19413 newDate, newViewDate;
19418 e.preventDefault();
19422 if (!this.keyboardNavigation) {
19425 dir = e.keyCode == 37 ? -1 : 1;
19428 newDate = this.moveYear(this.date, dir);
19429 newViewDate = this.moveYear(this.viewDate, dir);
19430 } else if (e.shiftKey){
19431 newDate = this.moveMonth(this.date, dir);
19432 newViewDate = this.moveMonth(this.viewDate, dir);
19434 newDate = new Date(this.date);
19435 newDate.setUTCDate(this.date.getUTCDate() + dir);
19436 newViewDate = new Date(this.viewDate);
19437 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19439 if (this.dateWithinRange(newDate)){
19440 this.date = newDate;
19441 this.viewDate = newViewDate;
19442 this.setValue(this.formatDate(this.date));
19444 e.preventDefault();
19445 dateChanged = true;
19450 if (!this.keyboardNavigation) {
19453 dir = e.keyCode == 38 ? -1 : 1;
19455 newDate = this.moveYear(this.date, dir);
19456 newViewDate = this.moveYear(this.viewDate, dir);
19457 } else if (e.shiftKey){
19458 newDate = this.moveMonth(this.date, dir);
19459 newViewDate = this.moveMonth(this.viewDate, dir);
19461 newDate = new Date(this.date);
19462 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19463 newViewDate = new Date(this.viewDate);
19464 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19466 if (this.dateWithinRange(newDate)){
19467 this.date = newDate;
19468 this.viewDate = newViewDate;
19469 this.setValue(this.formatDate(this.date));
19471 e.preventDefault();
19472 dateChanged = true;
19476 this.setValue(this.formatDate(this.date));
19478 e.preventDefault();
19481 this.setValue(this.formatDate(this.date));
19495 onClick: function(e)
19497 e.stopPropagation();
19498 e.preventDefault();
19500 var target = e.getTarget();
19502 if(target.nodeName.toLowerCase() === 'i'){
19503 target = Roo.get(target).dom.parentNode;
19506 var nodeName = target.nodeName;
19507 var className = target.className;
19508 var html = target.innerHTML;
19509 //Roo.log(nodeName);
19511 switch(nodeName.toLowerCase()) {
19513 switch(className) {
19519 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19520 switch(this.viewMode){
19522 this.viewDate = this.moveMonth(this.viewDate, dir);
19526 this.viewDate = this.moveYear(this.viewDate, dir);
19532 var date = new Date();
19533 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19535 this.setValue(this.formatDate(this.date));
19542 if (className.indexOf('disabled') < 0) {
19543 this.viewDate.setUTCDate(1);
19544 if (className.indexOf('month') > -1) {
19545 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19547 var year = parseInt(html, 10) || 0;
19548 this.viewDate.setUTCFullYear(year);
19552 if(this.singleMode){
19553 this.setValue(this.formatDate(this.viewDate));
19564 //Roo.log(className);
19565 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19566 var day = parseInt(html, 10) || 1;
19567 var year = this.viewDate.getUTCFullYear(),
19568 month = this.viewDate.getUTCMonth();
19570 if (className.indexOf('old') > -1) {
19577 } else if (className.indexOf('new') > -1) {
19585 //Roo.log([year,month,day]);
19586 this.date = this.UTCDate(year, month, day,0,0,0,0);
19587 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19589 //Roo.log(this.formatDate(this.date));
19590 this.setValue(this.formatDate(this.date));
19597 setStartDate: function(startDate)
19599 this.startDate = startDate || -Infinity;
19600 if (this.startDate !== -Infinity) {
19601 this.startDate = this.parseDate(this.startDate);
19604 this.updateNavArrows();
19607 setEndDate: function(endDate)
19609 this.endDate = endDate || Infinity;
19610 if (this.endDate !== Infinity) {
19611 this.endDate = this.parseDate(this.endDate);
19614 this.updateNavArrows();
19617 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19619 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19620 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19621 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19623 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19624 return parseInt(d, 10);
19627 this.updateNavArrows();
19630 updateNavArrows: function()
19632 if(this.singleMode){
19636 var d = new Date(this.viewDate),
19637 year = d.getUTCFullYear(),
19638 month = d.getUTCMonth();
19640 Roo.each(this.picker().select('.prev', true).elements, function(v){
19642 switch (this.viewMode) {
19645 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19651 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19658 Roo.each(this.picker().select('.next', true).elements, function(v){
19660 switch (this.viewMode) {
19663 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19669 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19677 moveMonth: function(date, dir)
19682 var new_date = new Date(date.valueOf()),
19683 day = new_date.getUTCDate(),
19684 month = new_date.getUTCMonth(),
19685 mag = Math.abs(dir),
19687 dir = dir > 0 ? 1 : -1;
19690 // If going back one month, make sure month is not current month
19691 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19693 return new_date.getUTCMonth() == month;
19695 // If going forward one month, make sure month is as expected
19696 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19698 return new_date.getUTCMonth() != new_month;
19700 new_month = month + dir;
19701 new_date.setUTCMonth(new_month);
19702 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19703 if (new_month < 0 || new_month > 11) {
19704 new_month = (new_month + 12) % 12;
19707 // For magnitudes >1, move one month at a time...
19708 for (var i=0; i<mag; i++) {
19709 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19710 new_date = this.moveMonth(new_date, dir);
19712 // ...then reset the day, keeping it in the new month
19713 new_month = new_date.getUTCMonth();
19714 new_date.setUTCDate(day);
19716 return new_month != new_date.getUTCMonth();
19719 // Common date-resetting loop -- if date is beyond end of month, make it
19722 new_date.setUTCDate(--day);
19723 new_date.setUTCMonth(new_month);
19728 moveYear: function(date, dir)
19730 return this.moveMonth(date, dir*12);
19733 dateWithinRange: function(date)
19735 return date >= this.startDate && date <= this.endDate;
19741 this.picker().remove();
19744 validateValue : function(value)
19746 if(this.getVisibilityEl().hasClass('hidden')){
19750 if(value.length < 1) {
19751 if(this.allowBlank){
19757 if(value.length < this.minLength){
19760 if(value.length > this.maxLength){
19764 var vt = Roo.form.VTypes;
19765 if(!vt[this.vtype](value, this)){
19769 if(typeof this.validator == "function"){
19770 var msg = this.validator(value);
19776 if(this.regex && !this.regex.test(value)){
19780 if(typeof(this.parseDate(value)) == 'undefined'){
19784 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19788 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19798 this.date = this.viewDate = '';
19800 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19805 Roo.apply(Roo.bootstrap.DateField, {
19816 html: '<i class="fa fa-arrow-left"/>'
19826 html: '<i class="fa fa-arrow-right"/>'
19868 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19869 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19870 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19871 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19872 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19885 navFnc: 'FullYear',
19890 navFnc: 'FullYear',
19895 Roo.apply(Roo.bootstrap.DateField, {
19899 cls: 'datepicker dropdown-menu roo-dynamic',
19903 cls: 'datepicker-days',
19907 cls: 'table-condensed',
19909 Roo.bootstrap.DateField.head,
19913 Roo.bootstrap.DateField.footer
19920 cls: 'datepicker-months',
19924 cls: 'table-condensed',
19926 Roo.bootstrap.DateField.head,
19927 Roo.bootstrap.DateField.content,
19928 Roo.bootstrap.DateField.footer
19935 cls: 'datepicker-years',
19939 cls: 'table-condensed',
19941 Roo.bootstrap.DateField.head,
19942 Roo.bootstrap.DateField.content,
19943 Roo.bootstrap.DateField.footer
19962 * @class Roo.bootstrap.TimeField
19963 * @extends Roo.bootstrap.Input
19964 * Bootstrap DateField class
19968 * Create a new TimeField
19969 * @param {Object} config The config object
19972 Roo.bootstrap.TimeField = function(config){
19973 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19977 * Fires when this field show.
19978 * @param {Roo.bootstrap.DateField} thisthis
19979 * @param {Mixed} date The date value
19984 * Fires when this field hide.
19985 * @param {Roo.bootstrap.DateField} this
19986 * @param {Mixed} date The date value
19991 * Fires when select a date.
19992 * @param {Roo.bootstrap.DateField} this
19993 * @param {Mixed} date The date value
19999 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20002 * @cfg {String} format
20003 * The default time format string which can be overriden for localization support. The format must be
20004 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20008 onRender: function(ct, position)
20011 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20013 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20015 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20017 this.pop = this.picker().select('>.datepicker-time',true).first();
20018 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20020 this.picker().on('mousedown', this.onMousedown, this);
20021 this.picker().on('click', this.onClick, this);
20023 this.picker().addClass('datepicker-dropdown');
20028 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20029 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20030 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20031 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20032 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20033 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20037 fireKey: function(e){
20038 if (!this.picker().isVisible()){
20039 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20045 e.preventDefault();
20053 this.onTogglePeriod();
20056 this.onIncrementMinutes();
20059 this.onDecrementMinutes();
20068 onClick: function(e) {
20069 e.stopPropagation();
20070 e.preventDefault();
20073 picker : function()
20075 return this.el.select('.datepicker', true).first();
20078 fillTime: function()
20080 var time = this.pop.select('tbody', true).first();
20082 time.dom.innerHTML = '';
20097 cls: 'hours-up glyphicon glyphicon-chevron-up'
20117 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20138 cls: 'timepicker-hour',
20153 cls: 'timepicker-minute',
20168 cls: 'btn btn-primary period',
20190 cls: 'hours-down glyphicon glyphicon-chevron-down'
20210 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20228 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20235 var hours = this.time.getHours();
20236 var minutes = this.time.getMinutes();
20249 hours = hours - 12;
20253 hours = '0' + hours;
20257 minutes = '0' + minutes;
20260 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20261 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20262 this.pop.select('button', true).first().dom.innerHTML = period;
20268 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20270 var cls = ['bottom'];
20272 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20279 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20284 this.picker().addClass(cls.join('-'));
20288 Roo.each(cls, function(c){
20290 _this.picker().setTop(_this.inputEl().getHeight());
20294 _this.picker().setTop(0 - _this.picker().getHeight());
20299 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20303 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20310 onFocus : function()
20312 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20316 onBlur : function()
20318 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20324 this.picker().show();
20329 this.fireEvent('show', this, this.date);
20334 this.picker().hide();
20337 this.fireEvent('hide', this, this.date);
20340 setTime : function()
20343 this.setValue(this.time.format(this.format));
20345 this.fireEvent('select', this, this.date);
20350 onMousedown: function(e){
20351 e.stopPropagation();
20352 e.preventDefault();
20355 onIncrementHours: function()
20357 Roo.log('onIncrementHours');
20358 this.time = this.time.add(Date.HOUR, 1);
20363 onDecrementHours: function()
20365 Roo.log('onDecrementHours');
20366 this.time = this.time.add(Date.HOUR, -1);
20370 onIncrementMinutes: function()
20372 Roo.log('onIncrementMinutes');
20373 this.time = this.time.add(Date.MINUTE, 1);
20377 onDecrementMinutes: function()
20379 Roo.log('onDecrementMinutes');
20380 this.time = this.time.add(Date.MINUTE, -1);
20384 onTogglePeriod: function()
20386 Roo.log('onTogglePeriod');
20387 this.time = this.time.add(Date.HOUR, 12);
20394 Roo.apply(Roo.bootstrap.TimeField, {
20424 cls: 'btn btn-info ok',
20436 Roo.apply(Roo.bootstrap.TimeField, {
20440 cls: 'datepicker dropdown-menu',
20444 cls: 'datepicker-time',
20448 cls: 'table-condensed',
20450 Roo.bootstrap.TimeField.content,
20451 Roo.bootstrap.TimeField.footer
20470 * @class Roo.bootstrap.MonthField
20471 * @extends Roo.bootstrap.Input
20472 * Bootstrap MonthField class
20474 * @cfg {String} language default en
20477 * Create a new MonthField
20478 * @param {Object} config The config object
20481 Roo.bootstrap.MonthField = function(config){
20482 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20487 * Fires when this field show.
20488 * @param {Roo.bootstrap.MonthField} this
20489 * @param {Mixed} date The date value
20494 * Fires when this field hide.
20495 * @param {Roo.bootstrap.MonthField} this
20496 * @param {Mixed} date The date value
20501 * Fires when select a date.
20502 * @param {Roo.bootstrap.MonthField} this
20503 * @param {String} oldvalue The old value
20504 * @param {String} newvalue The new value
20510 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20512 onRender: function(ct, position)
20515 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20517 this.language = this.language || 'en';
20518 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20519 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20521 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20522 this.isInline = false;
20523 this.isInput = true;
20524 this.component = this.el.select('.add-on', true).first() || false;
20525 this.component = (this.component && this.component.length === 0) ? false : this.component;
20526 this.hasInput = this.component && this.inputEL().length;
20528 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20530 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20532 this.picker().on('mousedown', this.onMousedown, this);
20533 this.picker().on('click', this.onClick, this);
20535 this.picker().addClass('datepicker-dropdown');
20537 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20538 v.setStyle('width', '189px');
20545 if(this.isInline) {
20551 setValue: function(v, suppressEvent)
20553 var o = this.getValue();
20555 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20559 if(suppressEvent !== true){
20560 this.fireEvent('select', this, o, v);
20565 getValue: function()
20570 onClick: function(e)
20572 e.stopPropagation();
20573 e.preventDefault();
20575 var target = e.getTarget();
20577 if(target.nodeName.toLowerCase() === 'i'){
20578 target = Roo.get(target).dom.parentNode;
20581 var nodeName = target.nodeName;
20582 var className = target.className;
20583 var html = target.innerHTML;
20585 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20589 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20591 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20597 picker : function()
20599 return this.pickerEl;
20602 fillMonths: function()
20605 var months = this.picker().select('>.datepicker-months td', true).first();
20607 months.dom.innerHTML = '';
20613 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20616 months.createChild(month);
20625 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20626 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20629 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20630 e.removeClass('active');
20632 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20633 e.addClass('active');
20640 if(this.isInline) {
20644 this.picker().removeClass(['bottom', 'top']);
20646 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20648 * place to the top of element!
20652 this.picker().addClass('top');
20653 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20658 this.picker().addClass('bottom');
20660 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20663 onFocus : function()
20665 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20669 onBlur : function()
20671 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20673 var d = this.inputEl().getValue();
20682 this.picker().show();
20683 this.picker().select('>.datepicker-months', true).first().show();
20687 this.fireEvent('show', this, this.date);
20692 if(this.isInline) {
20695 this.picker().hide();
20696 this.fireEvent('hide', this, this.date);
20700 onMousedown: function(e)
20702 e.stopPropagation();
20703 e.preventDefault();
20708 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20712 fireKey: function(e)
20714 if (!this.picker().isVisible()){
20715 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20726 e.preventDefault();
20730 dir = e.keyCode == 37 ? -1 : 1;
20732 this.vIndex = this.vIndex + dir;
20734 if(this.vIndex < 0){
20738 if(this.vIndex > 11){
20742 if(isNaN(this.vIndex)){
20746 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20752 dir = e.keyCode == 38 ? -1 : 1;
20754 this.vIndex = this.vIndex + dir * 4;
20756 if(this.vIndex < 0){
20760 if(this.vIndex > 11){
20764 if(isNaN(this.vIndex)){
20768 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20773 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20774 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20778 e.preventDefault();
20781 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20782 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20798 this.picker().remove();
20803 Roo.apply(Roo.bootstrap.MonthField, {
20822 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20823 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20828 Roo.apply(Roo.bootstrap.MonthField, {
20832 cls: 'datepicker dropdown-menu roo-dynamic',
20836 cls: 'datepicker-months',
20840 cls: 'table-condensed',
20842 Roo.bootstrap.DateField.content
20862 * @class Roo.bootstrap.CheckBox
20863 * @extends Roo.bootstrap.Input
20864 * Bootstrap CheckBox class
20866 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20867 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20868 * @cfg {String} boxLabel The text that appears beside the checkbox
20869 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20870 * @cfg {Boolean} checked initnal the element
20871 * @cfg {Boolean} inline inline the element (default false)
20872 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20873 * @cfg {String} tooltip label tooltip
20876 * Create a new CheckBox
20877 * @param {Object} config The config object
20880 Roo.bootstrap.CheckBox = function(config){
20881 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20886 * Fires when the element is checked or unchecked.
20887 * @param {Roo.bootstrap.CheckBox} this This input
20888 * @param {Boolean} checked The new checked value
20893 * Fires when the element is click.
20894 * @param {Roo.bootstrap.CheckBox} this This input
20901 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20903 inputType: 'checkbox',
20912 getAutoCreate : function()
20914 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20920 cfg.cls = 'form-group ' + this.inputType; //input-group
20923 cfg.cls += ' ' + this.inputType + '-inline';
20929 type : this.inputType,
20930 value : this.inputValue,
20931 cls : 'roo-' + this.inputType, //'form-box',
20932 placeholder : this.placeholder || ''
20936 if(this.inputType != 'radio'){
20940 cls : 'roo-hidden-value',
20941 value : this.checked ? this.inputValue : this.valueOff
20946 if (this.weight) { // Validity check?
20947 cfg.cls += " " + this.inputType + "-" + this.weight;
20950 if (this.disabled) {
20951 input.disabled=true;
20955 input.checked = this.checked;
20960 input.name = this.name;
20962 if(this.inputType != 'radio'){
20963 hidden.name = this.name;
20964 input.name = '_hidden_' + this.name;
20969 input.cls += ' input-' + this.size;
20974 ['xs','sm','md','lg'].map(function(size){
20975 if (settings[size]) {
20976 cfg.cls += ' col-' + size + '-' + settings[size];
20980 var inputblock = input;
20982 if (this.before || this.after) {
20985 cls : 'input-group',
20990 inputblock.cn.push({
20992 cls : 'input-group-addon',
20997 inputblock.cn.push(input);
20999 if(this.inputType != 'radio'){
21000 inputblock.cn.push(hidden);
21004 inputblock.cn.push({
21006 cls : 'input-group-addon',
21013 if (align ==='left' && this.fieldLabel.length) {
21014 // Roo.log("left and has label");
21019 cls : 'control-label',
21020 html : this.fieldLabel
21030 if(this.labelWidth > 12){
21031 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21034 if(this.labelWidth < 13 && this.labelmd == 0){
21035 this.labelmd = this.labelWidth;
21038 if(this.labellg > 0){
21039 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21040 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21043 if(this.labelmd > 0){
21044 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21045 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21048 if(this.labelsm > 0){
21049 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21050 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21053 if(this.labelxs > 0){
21054 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21055 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21058 } else if ( this.fieldLabel.length) {
21059 // Roo.log(" label");
21063 tag: this.boxLabel ? 'span' : 'label',
21065 cls: 'control-label box-input-label',
21066 //cls : 'input-group-addon',
21067 html : this.fieldLabel
21076 // Roo.log(" no label && no align");
21077 cfg.cn = [ inputblock ] ;
21083 var boxLabelCfg = {
21085 //'for': id, // box label is handled by onclick - so no for...
21087 html: this.boxLabel
21091 boxLabelCfg.tooltip = this.tooltip;
21094 cfg.cn.push(boxLabelCfg);
21097 if(this.inputType != 'radio'){
21098 cfg.cn.push(hidden);
21106 * return the real input element.
21108 inputEl: function ()
21110 return this.el.select('input.roo-' + this.inputType,true).first();
21112 hiddenEl: function ()
21114 return this.el.select('input.roo-hidden-value',true).first();
21117 labelEl: function()
21119 return this.el.select('label.control-label',true).first();
21121 /* depricated... */
21125 return this.labelEl();
21128 boxLabelEl: function()
21130 return this.el.select('label.box-label',true).first();
21133 initEvents : function()
21135 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21137 this.inputEl().on('click', this.onClick, this);
21139 if (this.boxLabel) {
21140 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21143 this.startValue = this.getValue();
21146 Roo.bootstrap.CheckBox.register(this);
21150 onClick : function(e)
21152 if(this.fireEvent('click', this, e) !== false){
21153 this.setChecked(!this.checked);
21158 setChecked : function(state,suppressEvent)
21160 this.startValue = this.getValue();
21162 if(this.inputType == 'radio'){
21164 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21165 e.dom.checked = false;
21168 this.inputEl().dom.checked = true;
21170 this.inputEl().dom.value = this.inputValue;
21172 if(suppressEvent !== true){
21173 this.fireEvent('check', this, true);
21181 this.checked = state;
21183 this.inputEl().dom.checked = state;
21186 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21188 if(suppressEvent !== true){
21189 this.fireEvent('check', this, state);
21195 getValue : function()
21197 if(this.inputType == 'radio'){
21198 return this.getGroupValue();
21201 return this.hiddenEl().dom.value;
21205 getGroupValue : function()
21207 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21211 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21214 setValue : function(v,suppressEvent)
21216 if(this.inputType == 'radio'){
21217 this.setGroupValue(v, suppressEvent);
21221 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21226 setGroupValue : function(v, suppressEvent)
21228 this.startValue = this.getValue();
21230 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21231 e.dom.checked = false;
21233 if(e.dom.value == v){
21234 e.dom.checked = true;
21238 if(suppressEvent !== true){
21239 this.fireEvent('check', this, true);
21247 validate : function()
21249 if(this.getVisibilityEl().hasClass('hidden')){
21255 (this.inputType == 'radio' && this.validateRadio()) ||
21256 (this.inputType == 'checkbox' && this.validateCheckbox())
21262 this.markInvalid();
21266 validateRadio : function()
21268 if(this.getVisibilityEl().hasClass('hidden')){
21272 if(this.allowBlank){
21278 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21279 if(!e.dom.checked){
21291 validateCheckbox : function()
21294 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21295 //return (this.getValue() == this.inputValue) ? true : false;
21298 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21306 for(var i in group){
21307 if(group[i].el.isVisible(true)){
21315 for(var i in group){
21320 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21327 * Mark this field as valid
21329 markValid : function()
21333 this.fireEvent('valid', this);
21335 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21338 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21345 if(this.inputType == 'radio'){
21346 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21347 var fg = e.findParent('.form-group', false, true);
21348 if (Roo.bootstrap.version == 3) {
21349 fg.removeClass([_this.invalidClass, _this.validClass]);
21350 fg.addClass(_this.validClass);
21352 fg.removeClass(['is-valid', 'is-invalid']);
21353 fg.addClass('is-valid');
21361 var fg = this.el.findParent('.form-group', false, true);
21362 if (Roo.bootstrap.version == 3) {
21363 fg.removeClass([this.invalidClass, this.validClass]);
21364 fg.addClass(this.validClass);
21366 fg.removeClass(['is-valid', 'is-invalid']);
21367 fg.addClass('is-valid');
21372 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21378 for(var i in group){
21379 var fg = group[i].el.findParent('.form-group', false, true);
21380 if (Roo.bootstrap.version == 3) {
21381 fg.removeClass([this.invalidClass, this.validClass]);
21382 fg.addClass(this.validClass);
21384 fg.removeClass(['is-valid', 'is-invalid']);
21385 fg.addClass('is-valid');
21391 * Mark this field as invalid
21392 * @param {String} msg The validation message
21394 markInvalid : function(msg)
21396 if(this.allowBlank){
21402 this.fireEvent('invalid', this, msg);
21404 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21407 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21411 label.markInvalid();
21414 if(this.inputType == 'radio'){
21416 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21417 var fg = e.findParent('.form-group', false, true);
21418 if (Roo.bootstrap.version == 3) {
21419 fg.removeClass([_this.invalidClass, _this.validClass]);
21420 fg.addClass(_this.invalidClass);
21422 fg.removeClass(['is-invalid', 'is-valid']);
21423 fg.addClass('is-invalid');
21431 var fg = this.el.findParent('.form-group', false, true);
21432 if (Roo.bootstrap.version == 3) {
21433 fg.removeClass([_this.invalidClass, _this.validClass]);
21434 fg.addClass(_this.invalidClass);
21436 fg.removeClass(['is-invalid', 'is-valid']);
21437 fg.addClass('is-invalid');
21442 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21448 for(var i in group){
21449 var fg = group[i].el.findParent('.form-group', false, true);
21450 if (Roo.bootstrap.version == 3) {
21451 fg.removeClass([_this.invalidClass, _this.validClass]);
21452 fg.addClass(_this.invalidClass);
21454 fg.removeClass(['is-invalid', 'is-valid']);
21455 fg.addClass('is-invalid');
21461 clearInvalid : function()
21463 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21465 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21467 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21469 if (label && label.iconEl) {
21470 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21471 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21475 disable : function()
21477 if(this.inputType != 'radio'){
21478 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21485 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21486 _this.getActionEl().addClass(this.disabledClass);
21487 e.dom.disabled = true;
21491 this.disabled = true;
21492 this.fireEvent("disable", this);
21496 enable : function()
21498 if(this.inputType != 'radio'){
21499 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21506 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21507 _this.getActionEl().removeClass(this.disabledClass);
21508 e.dom.disabled = false;
21512 this.disabled = false;
21513 this.fireEvent("enable", this);
21517 setBoxLabel : function(v)
21522 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21528 Roo.apply(Roo.bootstrap.CheckBox, {
21533 * register a CheckBox Group
21534 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21536 register : function(checkbox)
21538 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21539 this.groups[checkbox.groupId] = {};
21542 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21546 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21550 * fetch a CheckBox Group based on the group ID
21551 * @param {string} the group ID
21552 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21554 get: function(groupId) {
21555 if (typeof(this.groups[groupId]) == 'undefined') {
21559 return this.groups[groupId] ;
21572 * @class Roo.bootstrap.Radio
21573 * @extends Roo.bootstrap.Component
21574 * Bootstrap Radio class
21575 * @cfg {String} boxLabel - the label associated
21576 * @cfg {String} value - the value of radio
21579 * Create a new Radio
21580 * @param {Object} config The config object
21582 Roo.bootstrap.Radio = function(config){
21583 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21587 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21593 getAutoCreate : function()
21597 cls : 'form-group radio',
21602 html : this.boxLabel
21610 initEvents : function()
21612 this.parent().register(this);
21614 this.el.on('click', this.onClick, this);
21618 onClick : function(e)
21620 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21621 this.setChecked(true);
21625 setChecked : function(state, suppressEvent)
21627 this.parent().setValue(this.value, suppressEvent);
21631 setBoxLabel : function(v)
21636 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21651 * @class Roo.bootstrap.SecurePass
21652 * @extends Roo.bootstrap.Input
21653 * Bootstrap SecurePass class
21657 * Create a new SecurePass
21658 * @param {Object} config The config object
21661 Roo.bootstrap.SecurePass = function (config) {
21662 // these go here, so the translation tool can replace them..
21664 PwdEmpty: "Please type a password, and then retype it to confirm.",
21665 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21666 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21667 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21668 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21669 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21670 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21671 TooWeak: "Your password is Too Weak."
21673 this.meterLabel = "Password strength:";
21674 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21675 this.meterClass = [
21676 "roo-password-meter-tooweak",
21677 "roo-password-meter-weak",
21678 "roo-password-meter-medium",
21679 "roo-password-meter-strong",
21680 "roo-password-meter-grey"
21685 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21688 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21690 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21692 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21693 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21694 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21695 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21696 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21697 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21698 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21708 * @cfg {String/Object} Label for the strength meter (defaults to
21709 * 'Password strength:')
21714 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21715 * ['Weak', 'Medium', 'Strong'])
21718 pwdStrengths: false,
21731 initEvents: function ()
21733 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21735 if (this.el.is('input[type=password]') && Roo.isSafari) {
21736 this.el.on('keydown', this.SafariOnKeyDown, this);
21739 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21742 onRender: function (ct, position)
21744 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21745 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21746 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21748 this.trigger.createChild({
21753 cls: 'roo-password-meter-grey col-xs-12',
21756 //width: this.meterWidth + 'px'
21760 cls: 'roo-password-meter-text'
21766 if (this.hideTrigger) {
21767 this.trigger.setDisplayed(false);
21769 this.setSize(this.width || '', this.height || '');
21772 onDestroy: function ()
21774 if (this.trigger) {
21775 this.trigger.removeAllListeners();
21776 this.trigger.remove();
21779 this.wrap.remove();
21781 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21784 checkStrength: function ()
21786 var pwd = this.inputEl().getValue();
21787 if (pwd == this._lastPwd) {
21792 if (this.ClientSideStrongPassword(pwd)) {
21794 } else if (this.ClientSideMediumPassword(pwd)) {
21796 } else if (this.ClientSideWeakPassword(pwd)) {
21802 Roo.log('strength1: ' + strength);
21804 //var pm = this.trigger.child('div/div/div').dom;
21805 var pm = this.trigger.child('div/div');
21806 pm.removeClass(this.meterClass);
21807 pm.addClass(this.meterClass[strength]);
21810 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21812 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21814 this._lastPwd = pwd;
21818 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21820 this._lastPwd = '';
21822 var pm = this.trigger.child('div/div');
21823 pm.removeClass(this.meterClass);
21824 pm.addClass('roo-password-meter-grey');
21827 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21830 this.inputEl().dom.type='password';
21833 validateValue: function (value)
21836 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21839 if (value.length == 0) {
21840 if (this.allowBlank) {
21841 this.clearInvalid();
21845 this.markInvalid(this.errors.PwdEmpty);
21846 this.errorMsg = this.errors.PwdEmpty;
21854 if ('[\x21-\x7e]*'.match(value)) {
21855 this.markInvalid(this.errors.PwdBadChar);
21856 this.errorMsg = this.errors.PwdBadChar;
21859 if (value.length < 6) {
21860 this.markInvalid(this.errors.PwdShort);
21861 this.errorMsg = this.errors.PwdShort;
21864 if (value.length > 16) {
21865 this.markInvalid(this.errors.PwdLong);
21866 this.errorMsg = this.errors.PwdLong;
21870 if (this.ClientSideStrongPassword(value)) {
21872 } else if (this.ClientSideMediumPassword(value)) {
21874 } else if (this.ClientSideWeakPassword(value)) {
21881 if (strength < 2) {
21882 //this.markInvalid(this.errors.TooWeak);
21883 this.errorMsg = this.errors.TooWeak;
21888 console.log('strength2: ' + strength);
21890 //var pm = this.trigger.child('div/div/div').dom;
21892 var pm = this.trigger.child('div/div');
21893 pm.removeClass(this.meterClass);
21894 pm.addClass(this.meterClass[strength]);
21896 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21898 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21900 this.errorMsg = '';
21904 CharacterSetChecks: function (type)
21907 this.fResult = false;
21910 isctype: function (character, type)
21913 case this.kCapitalLetter:
21914 if (character >= 'A' && character <= 'Z') {
21919 case this.kSmallLetter:
21920 if (character >= 'a' && character <= 'z') {
21926 if (character >= '0' && character <= '9') {
21931 case this.kPunctuation:
21932 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21943 IsLongEnough: function (pwd, size)
21945 return !(pwd == null || isNaN(size) || pwd.length < size);
21948 SpansEnoughCharacterSets: function (word, nb)
21950 if (!this.IsLongEnough(word, nb))
21955 var characterSetChecks = new Array(
21956 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21957 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21960 for (var index = 0; index < word.length; ++index) {
21961 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21962 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21963 characterSetChecks[nCharSet].fResult = true;
21970 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21971 if (characterSetChecks[nCharSet].fResult) {
21976 if (nCharSets < nb) {
21982 ClientSideStrongPassword: function (pwd)
21984 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21987 ClientSideMediumPassword: function (pwd)
21989 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21992 ClientSideWeakPassword: function (pwd)
21994 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21997 })//<script type="text/javascript">
22000 * Based Ext JS Library 1.1.1
22001 * Copyright(c) 2006-2007, Ext JS, LLC.
22007 * @class Roo.HtmlEditorCore
22008 * @extends Roo.Component
22009 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22011 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22014 Roo.HtmlEditorCore = function(config){
22017 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22022 * @event initialize
22023 * Fires when the editor is fully initialized (including the iframe)
22024 * @param {Roo.HtmlEditorCore} this
22029 * Fires when the editor is first receives the focus. Any insertion must wait
22030 * until after this event.
22031 * @param {Roo.HtmlEditorCore} this
22035 * @event beforesync
22036 * Fires before the textarea is updated with content from the editor iframe. Return false
22037 * to cancel the sync.
22038 * @param {Roo.HtmlEditorCore} this
22039 * @param {String} html
22043 * @event beforepush
22044 * Fires before the iframe editor is updated with content from the textarea. Return false
22045 * to cancel the push.
22046 * @param {Roo.HtmlEditorCore} this
22047 * @param {String} html
22052 * Fires when the textarea is updated with content from the editor iframe.
22053 * @param {Roo.HtmlEditorCore} this
22054 * @param {String} html
22059 * Fires when the iframe editor is updated with content from the textarea.
22060 * @param {Roo.HtmlEditorCore} this
22061 * @param {String} html
22066 * @event editorevent
22067 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22068 * @param {Roo.HtmlEditorCore} this
22074 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22076 // defaults : white / black...
22077 this.applyBlacklists();
22084 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22088 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22094 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22099 * @cfg {Number} height (in pixels)
22103 * @cfg {Number} width (in pixels)
22108 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22111 stylesheets: false,
22116 // private properties
22117 validationEvent : false,
22119 initialized : false,
22121 sourceEditMode : false,
22122 onFocus : Roo.emptyFn,
22124 hideMode:'offsets',
22128 // blacklist + whitelisted elements..
22135 * Protected method that will not generally be called directly. It
22136 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22137 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22139 getDocMarkup : function(){
22143 // inherit styels from page...??
22144 if (this.stylesheets === false) {
22146 Roo.get(document.head).select('style').each(function(node) {
22147 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22150 Roo.get(document.head).select('link').each(function(node) {
22151 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22154 } else if (!this.stylesheets.length) {
22156 st = '<style type="text/css">' +
22157 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22160 st = '<style type="text/css">' +
22165 st += '<style type="text/css">' +
22166 'IMG { cursor: pointer } ' +
22169 var cls = 'roo-htmleditor-body';
22171 if(this.bodyCls.length){
22172 cls += ' ' + this.bodyCls;
22175 return '<html><head>' + st +
22176 //<style type="text/css">' +
22177 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22179 ' </head><body class="' + cls + '"></body></html>';
22183 onRender : function(ct, position)
22186 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22187 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22190 this.el.dom.style.border = '0 none';
22191 this.el.dom.setAttribute('tabIndex', -1);
22192 this.el.addClass('x-hidden hide');
22196 if(Roo.isIE){ // fix IE 1px bogus margin
22197 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22201 this.frameId = Roo.id();
22205 var iframe = this.owner.wrap.createChild({
22207 cls: 'form-control', // bootstrap..
22209 name: this.frameId,
22210 frameBorder : 'no',
22211 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22216 this.iframe = iframe.dom;
22218 this.assignDocWin();
22220 this.doc.designMode = 'on';
22223 this.doc.write(this.getDocMarkup());
22227 var task = { // must defer to wait for browser to be ready
22229 //console.log("run task?" + this.doc.readyState);
22230 this.assignDocWin();
22231 if(this.doc.body || this.doc.readyState == 'complete'){
22233 this.doc.designMode="on";
22237 Roo.TaskMgr.stop(task);
22238 this.initEditor.defer(10, this);
22245 Roo.TaskMgr.start(task);
22250 onResize : function(w, h)
22252 Roo.log('resize: ' +w + ',' + h );
22253 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22257 if(typeof w == 'number'){
22259 this.iframe.style.width = w + 'px';
22261 if(typeof h == 'number'){
22263 this.iframe.style.height = h + 'px';
22265 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22272 * Toggles the editor between standard and source edit mode.
22273 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22275 toggleSourceEdit : function(sourceEditMode){
22277 this.sourceEditMode = sourceEditMode === true;
22279 if(this.sourceEditMode){
22281 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22284 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22285 //this.iframe.className = '';
22288 //this.setSize(this.owner.wrap.getSize());
22289 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22296 * Protected method that will not generally be called directly. If you need/want
22297 * custom HTML cleanup, this is the method you should override.
22298 * @param {String} html The HTML to be cleaned
22299 * return {String} The cleaned HTML
22301 cleanHtml : function(html){
22302 html = String(html);
22303 if(html.length > 5){
22304 if(Roo.isSafari){ // strip safari nonsense
22305 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22308 if(html == ' '){
22315 * HTML Editor -> Textarea
22316 * Protected method that will not generally be called directly. Syncs the contents
22317 * of the editor iframe with the textarea.
22319 syncValue : function(){
22320 if(this.initialized){
22321 var bd = (this.doc.body || this.doc.documentElement);
22322 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22323 var html = bd.innerHTML;
22325 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22326 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22328 html = '<div style="'+m[0]+'">' + html + '</div>';
22331 html = this.cleanHtml(html);
22332 // fix up the special chars.. normaly like back quotes in word...
22333 // however we do not want to do this with chinese..
22334 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22335 var cc = b.charCodeAt();
22337 (cc >= 0x4E00 && cc < 0xA000 ) ||
22338 (cc >= 0x3400 && cc < 0x4E00 ) ||
22339 (cc >= 0xf900 && cc < 0xfb00 )
22345 if(this.owner.fireEvent('beforesync', this, html) !== false){
22346 this.el.dom.value = html;
22347 this.owner.fireEvent('sync', this, html);
22353 * Protected method that will not generally be called directly. Pushes the value of the textarea
22354 * into the iframe editor.
22356 pushValue : function(){
22357 if(this.initialized){
22358 var v = this.el.dom.value.trim();
22360 // if(v.length < 1){
22364 if(this.owner.fireEvent('beforepush', this, v) !== false){
22365 var d = (this.doc.body || this.doc.documentElement);
22367 this.cleanUpPaste();
22368 this.el.dom.value = d.innerHTML;
22369 this.owner.fireEvent('push', this, v);
22375 deferFocus : function(){
22376 this.focus.defer(10, this);
22380 focus : function(){
22381 if(this.win && !this.sourceEditMode){
22388 assignDocWin: function()
22390 var iframe = this.iframe;
22393 this.doc = iframe.contentWindow.document;
22394 this.win = iframe.contentWindow;
22396 // if (!Roo.get(this.frameId)) {
22399 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22400 // this.win = Roo.get(this.frameId).dom.contentWindow;
22402 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22406 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22407 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22412 initEditor : function(){
22413 //console.log("INIT EDITOR");
22414 this.assignDocWin();
22418 this.doc.designMode="on";
22420 this.doc.write(this.getDocMarkup());
22423 var dbody = (this.doc.body || this.doc.documentElement);
22424 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22425 // this copies styles from the containing element into thsi one..
22426 // not sure why we need all of this..
22427 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22429 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22430 //ss['background-attachment'] = 'fixed'; // w3c
22431 dbody.bgProperties = 'fixed'; // ie
22432 //Roo.DomHelper.applyStyles(dbody, ss);
22433 Roo.EventManager.on(this.doc, {
22434 //'mousedown': this.onEditorEvent,
22435 'mouseup': this.onEditorEvent,
22436 'dblclick': this.onEditorEvent,
22437 'click': this.onEditorEvent,
22438 'keyup': this.onEditorEvent,
22443 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22445 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22446 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22448 this.initialized = true;
22450 this.owner.fireEvent('initialize', this);
22455 onDestroy : function(){
22461 //for (var i =0; i < this.toolbars.length;i++) {
22462 // // fixme - ask toolbars for heights?
22463 // this.toolbars[i].onDestroy();
22466 //this.wrap.dom.innerHTML = '';
22467 //this.wrap.remove();
22472 onFirstFocus : function(){
22474 this.assignDocWin();
22477 this.activated = true;
22480 if(Roo.isGecko){ // prevent silly gecko errors
22482 var s = this.win.getSelection();
22483 if(!s.focusNode || s.focusNode.nodeType != 3){
22484 var r = s.getRangeAt(0);
22485 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22490 this.execCmd('useCSS', true);
22491 this.execCmd('styleWithCSS', false);
22494 this.owner.fireEvent('activate', this);
22498 adjustFont: function(btn){
22499 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22500 //if(Roo.isSafari){ // safari
22503 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22504 if(Roo.isSafari){ // safari
22505 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22506 v = (v < 10) ? 10 : v;
22507 v = (v > 48) ? 48 : v;
22508 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22513 v = Math.max(1, v+adjust);
22515 this.execCmd('FontSize', v );
22518 onEditorEvent : function(e)
22520 this.owner.fireEvent('editorevent', this, e);
22521 // this.updateToolbar();
22522 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22525 insertTag : function(tg)
22527 // could be a bit smarter... -> wrap the current selected tRoo..
22528 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22530 range = this.createRange(this.getSelection());
22531 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22532 wrappingNode.appendChild(range.extractContents());
22533 range.insertNode(wrappingNode);
22540 this.execCmd("formatblock", tg);
22544 insertText : function(txt)
22548 var range = this.createRange();
22549 range.deleteContents();
22550 //alert(Sender.getAttribute('label'));
22552 range.insertNode(this.doc.createTextNode(txt));
22558 * Executes a Midas editor command on the editor document and performs necessary focus and
22559 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22560 * @param {String} cmd The Midas command
22561 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22563 relayCmd : function(cmd, value){
22565 this.execCmd(cmd, value);
22566 this.owner.fireEvent('editorevent', this);
22567 //this.updateToolbar();
22568 this.owner.deferFocus();
22572 * Executes a Midas editor command directly on the editor document.
22573 * For visual commands, you should use {@link #relayCmd} instead.
22574 * <b>This should only be called after the editor is initialized.</b>
22575 * @param {String} cmd The Midas command
22576 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22578 execCmd : function(cmd, value){
22579 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22586 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22588 * @param {String} text | dom node..
22590 insertAtCursor : function(text)
22593 if(!this.activated){
22599 var r = this.doc.selection.createRange();
22610 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22614 // from jquery ui (MIT licenced)
22616 var win = this.win;
22618 if (win.getSelection && win.getSelection().getRangeAt) {
22619 range = win.getSelection().getRangeAt(0);
22620 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22621 range.insertNode(node);
22622 } else if (win.document.selection && win.document.selection.createRange) {
22623 // no firefox support
22624 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22625 win.document.selection.createRange().pasteHTML(txt);
22627 // no firefox support
22628 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22629 this.execCmd('InsertHTML', txt);
22638 mozKeyPress : function(e){
22640 var c = e.getCharCode(), cmd;
22643 c = String.fromCharCode(c).toLowerCase();
22657 this.cleanUpPaste.defer(100, this);
22665 e.preventDefault();
22673 fixKeys : function(){ // load time branching for fastest keydown performance
22675 return function(e){
22676 var k = e.getKey(), r;
22679 r = this.doc.selection.createRange();
22682 r.pasteHTML('    ');
22689 r = this.doc.selection.createRange();
22691 var target = r.parentElement();
22692 if(!target || target.tagName.toLowerCase() != 'li'){
22694 r.pasteHTML('<br />');
22700 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22701 this.cleanUpPaste.defer(100, this);
22707 }else if(Roo.isOpera){
22708 return function(e){
22709 var k = e.getKey();
22713 this.execCmd('InsertHTML','    ');
22716 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22717 this.cleanUpPaste.defer(100, this);
22722 }else if(Roo.isSafari){
22723 return function(e){
22724 var k = e.getKey();
22728 this.execCmd('InsertText','\t');
22732 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22733 this.cleanUpPaste.defer(100, this);
22741 getAllAncestors: function()
22743 var p = this.getSelectedNode();
22746 a.push(p); // push blank onto stack..
22747 p = this.getParentElement();
22751 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22755 a.push(this.doc.body);
22759 lastSelNode : false,
22762 getSelection : function()
22764 this.assignDocWin();
22765 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22768 getSelectedNode: function()
22770 // this may only work on Gecko!!!
22772 // should we cache this!!!!
22777 var range = this.createRange(this.getSelection()).cloneRange();
22780 var parent = range.parentElement();
22782 var testRange = range.duplicate();
22783 testRange.moveToElementText(parent);
22784 if (testRange.inRange(range)) {
22787 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22790 parent = parent.parentElement;
22795 // is ancestor a text element.
22796 var ac = range.commonAncestorContainer;
22797 if (ac.nodeType == 3) {
22798 ac = ac.parentNode;
22801 var ar = ac.childNodes;
22804 var other_nodes = [];
22805 var has_other_nodes = false;
22806 for (var i=0;i<ar.length;i++) {
22807 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22810 // fullly contained node.
22812 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22817 // probably selected..
22818 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22819 other_nodes.push(ar[i]);
22823 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22828 has_other_nodes = true;
22830 if (!nodes.length && other_nodes.length) {
22831 nodes= other_nodes;
22833 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22839 createRange: function(sel)
22841 // this has strange effects when using with
22842 // top toolbar - not sure if it's a great idea.
22843 //this.editor.contentWindow.focus();
22844 if (typeof sel != "undefined") {
22846 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22848 return this.doc.createRange();
22851 return this.doc.createRange();
22854 getParentElement: function()
22857 this.assignDocWin();
22858 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22860 var range = this.createRange(sel);
22863 var p = range.commonAncestorContainer;
22864 while (p.nodeType == 3) { // text node
22875 * Range intersection.. the hard stuff...
22879 * [ -- selected range --- ]
22883 * if end is before start or hits it. fail.
22884 * if start is after end or hits it fail.
22886 * if either hits (but other is outside. - then it's not
22892 // @see http://www.thismuchiknow.co.uk/?p=64.
22893 rangeIntersectsNode : function(range, node)
22895 var nodeRange = node.ownerDocument.createRange();
22897 nodeRange.selectNode(node);
22899 nodeRange.selectNodeContents(node);
22902 var rangeStartRange = range.cloneRange();
22903 rangeStartRange.collapse(true);
22905 var rangeEndRange = range.cloneRange();
22906 rangeEndRange.collapse(false);
22908 var nodeStartRange = nodeRange.cloneRange();
22909 nodeStartRange.collapse(true);
22911 var nodeEndRange = nodeRange.cloneRange();
22912 nodeEndRange.collapse(false);
22914 return rangeStartRange.compareBoundaryPoints(
22915 Range.START_TO_START, nodeEndRange) == -1 &&
22916 rangeEndRange.compareBoundaryPoints(
22917 Range.START_TO_START, nodeStartRange) == 1;
22921 rangeCompareNode : function(range, node)
22923 var nodeRange = node.ownerDocument.createRange();
22925 nodeRange.selectNode(node);
22927 nodeRange.selectNodeContents(node);
22931 range.collapse(true);
22933 nodeRange.collapse(true);
22935 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22936 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22938 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22940 var nodeIsBefore = ss == 1;
22941 var nodeIsAfter = ee == -1;
22943 if (nodeIsBefore && nodeIsAfter) {
22946 if (!nodeIsBefore && nodeIsAfter) {
22947 return 1; //right trailed.
22950 if (nodeIsBefore && !nodeIsAfter) {
22951 return 2; // left trailed.
22957 // private? - in a new class?
22958 cleanUpPaste : function()
22960 // cleans up the whole document..
22961 Roo.log('cleanuppaste');
22963 this.cleanUpChildren(this.doc.body);
22964 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22965 if (clean != this.doc.body.innerHTML) {
22966 this.doc.body.innerHTML = clean;
22971 cleanWordChars : function(input) {// change the chars to hex code
22972 var he = Roo.HtmlEditorCore;
22974 var output = input;
22975 Roo.each(he.swapCodes, function(sw) {
22976 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22978 output = output.replace(swapper, sw[1]);
22985 cleanUpChildren : function (n)
22987 if (!n.childNodes.length) {
22990 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22991 this.cleanUpChild(n.childNodes[i]);
22998 cleanUpChild : function (node)
23001 //console.log(node);
23002 if (node.nodeName == "#text") {
23003 // clean up silly Windows -- stuff?
23006 if (node.nodeName == "#comment") {
23007 node.parentNode.removeChild(node);
23008 // clean up silly Windows -- stuff?
23011 var lcname = node.tagName.toLowerCase();
23012 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23013 // whitelist of tags..
23015 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23017 node.parentNode.removeChild(node);
23022 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23024 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23025 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23027 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23028 // remove_keep_children = true;
23031 if (remove_keep_children) {
23032 this.cleanUpChildren(node);
23033 // inserts everything just before this node...
23034 while (node.childNodes.length) {
23035 var cn = node.childNodes[0];
23036 node.removeChild(cn);
23037 node.parentNode.insertBefore(cn, node);
23039 node.parentNode.removeChild(node);
23043 if (!node.attributes || !node.attributes.length) {
23044 this.cleanUpChildren(node);
23048 function cleanAttr(n,v)
23051 if (v.match(/^\./) || v.match(/^\//)) {
23054 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23057 if (v.match(/^#/)) {
23060 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23061 node.removeAttribute(n);
23065 var cwhite = this.cwhite;
23066 var cblack = this.cblack;
23068 function cleanStyle(n,v)
23070 if (v.match(/expression/)) { //XSS?? should we even bother..
23071 node.removeAttribute(n);
23075 var parts = v.split(/;/);
23078 Roo.each(parts, function(p) {
23079 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23083 var l = p.split(':').shift().replace(/\s+/g,'');
23084 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23086 if ( cwhite.length && cblack.indexOf(l) > -1) {
23087 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23088 //node.removeAttribute(n);
23092 // only allow 'c whitelisted system attributes'
23093 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23094 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23095 //node.removeAttribute(n);
23105 if (clean.length) {
23106 node.setAttribute(n, clean.join(';'));
23108 node.removeAttribute(n);
23114 for (var i = node.attributes.length-1; i > -1 ; i--) {
23115 var a = node.attributes[i];
23118 if (a.name.toLowerCase().substr(0,2)=='on') {
23119 node.removeAttribute(a.name);
23122 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23123 node.removeAttribute(a.name);
23126 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23127 cleanAttr(a.name,a.value); // fixme..
23130 if (a.name == 'style') {
23131 cleanStyle(a.name,a.value);
23134 /// clean up MS crap..
23135 // tecnically this should be a list of valid class'es..
23138 if (a.name == 'class') {
23139 if (a.value.match(/^Mso/)) {
23140 node.className = '';
23143 if (a.value.match(/^body$/)) {
23144 node.className = '';
23155 this.cleanUpChildren(node);
23161 * Clean up MS wordisms...
23163 cleanWord : function(node)
23168 this.cleanWord(this.doc.body);
23171 if (node.nodeName == "#text") {
23172 // clean up silly Windows -- stuff?
23175 if (node.nodeName == "#comment") {
23176 node.parentNode.removeChild(node);
23177 // clean up silly Windows -- stuff?
23181 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23182 node.parentNode.removeChild(node);
23186 // remove - but keep children..
23187 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23188 while (node.childNodes.length) {
23189 var cn = node.childNodes[0];
23190 node.removeChild(cn);
23191 node.parentNode.insertBefore(cn, node);
23193 node.parentNode.removeChild(node);
23194 this.iterateChildren(node, this.cleanWord);
23198 if (node.className.length) {
23200 var cn = node.className.split(/\W+/);
23202 Roo.each(cn, function(cls) {
23203 if (cls.match(/Mso[a-zA-Z]+/)) {
23208 node.className = cna.length ? cna.join(' ') : '';
23210 node.removeAttribute("class");
23214 if (node.hasAttribute("lang")) {
23215 node.removeAttribute("lang");
23218 if (node.hasAttribute("style")) {
23220 var styles = node.getAttribute("style").split(";");
23222 Roo.each(styles, function(s) {
23223 if (!s.match(/:/)) {
23226 var kv = s.split(":");
23227 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23230 // what ever is left... we allow.
23233 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23234 if (!nstyle.length) {
23235 node.removeAttribute('style');
23238 this.iterateChildren(node, this.cleanWord);
23244 * iterateChildren of a Node, calling fn each time, using this as the scole..
23245 * @param {DomNode} node node to iterate children of.
23246 * @param {Function} fn method of this class to call on each item.
23248 iterateChildren : function(node, fn)
23250 if (!node.childNodes.length) {
23253 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23254 fn.call(this, node.childNodes[i])
23260 * cleanTableWidths.
23262 * Quite often pasting from word etc.. results in tables with column and widths.
23263 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23266 cleanTableWidths : function(node)
23271 this.cleanTableWidths(this.doc.body);
23276 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23279 Roo.log(node.tagName);
23280 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23281 this.iterateChildren(node, this.cleanTableWidths);
23284 if (node.hasAttribute('width')) {
23285 node.removeAttribute('width');
23289 if (node.hasAttribute("style")) {
23292 var styles = node.getAttribute("style").split(";");
23294 Roo.each(styles, function(s) {
23295 if (!s.match(/:/)) {
23298 var kv = s.split(":");
23299 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23302 // what ever is left... we allow.
23305 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23306 if (!nstyle.length) {
23307 node.removeAttribute('style');
23311 this.iterateChildren(node, this.cleanTableWidths);
23319 domToHTML : function(currentElement, depth, nopadtext) {
23321 depth = depth || 0;
23322 nopadtext = nopadtext || false;
23324 if (!currentElement) {
23325 return this.domToHTML(this.doc.body);
23328 //Roo.log(currentElement);
23330 var allText = false;
23331 var nodeName = currentElement.nodeName;
23332 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23334 if (nodeName == '#text') {
23336 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23341 if (nodeName != 'BODY') {
23344 // Prints the node tagName, such as <A>, <IMG>, etc
23347 for(i = 0; i < currentElement.attributes.length;i++) {
23349 var aname = currentElement.attributes.item(i).name;
23350 if (!currentElement.attributes.item(i).value.length) {
23353 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23356 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23365 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23368 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23373 // Traverse the tree
23375 var currentElementChild = currentElement.childNodes.item(i);
23376 var allText = true;
23377 var innerHTML = '';
23379 while (currentElementChild) {
23380 // Formatting code (indent the tree so it looks nice on the screen)
23381 var nopad = nopadtext;
23382 if (lastnode == 'SPAN') {
23386 if (currentElementChild.nodeName == '#text') {
23387 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23388 toadd = nopadtext ? toadd : toadd.trim();
23389 if (!nopad && toadd.length > 80) {
23390 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23392 innerHTML += toadd;
23395 currentElementChild = currentElement.childNodes.item(i);
23401 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23403 // Recursively traverse the tree structure of the child node
23404 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23405 lastnode = currentElementChild.nodeName;
23407 currentElementChild=currentElement.childNodes.item(i);
23413 // The remaining code is mostly for formatting the tree
23414 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23419 ret+= "</"+tagName+">";
23425 applyBlacklists : function()
23427 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23428 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23432 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23433 if (b.indexOf(tag) > -1) {
23436 this.white.push(tag);
23440 Roo.each(w, function(tag) {
23441 if (b.indexOf(tag) > -1) {
23444 if (this.white.indexOf(tag) > -1) {
23447 this.white.push(tag);
23452 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23453 if (w.indexOf(tag) > -1) {
23456 this.black.push(tag);
23460 Roo.each(b, function(tag) {
23461 if (w.indexOf(tag) > -1) {
23464 if (this.black.indexOf(tag) > -1) {
23467 this.black.push(tag);
23472 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23473 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23477 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23478 if (b.indexOf(tag) > -1) {
23481 this.cwhite.push(tag);
23485 Roo.each(w, function(tag) {
23486 if (b.indexOf(tag) > -1) {
23489 if (this.cwhite.indexOf(tag) > -1) {
23492 this.cwhite.push(tag);
23497 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23498 if (w.indexOf(tag) > -1) {
23501 this.cblack.push(tag);
23505 Roo.each(b, function(tag) {
23506 if (w.indexOf(tag) > -1) {
23509 if (this.cblack.indexOf(tag) > -1) {
23512 this.cblack.push(tag);
23517 setStylesheets : function(stylesheets)
23519 if(typeof(stylesheets) == 'string'){
23520 Roo.get(this.iframe.contentDocument.head).createChild({
23522 rel : 'stylesheet',
23531 Roo.each(stylesheets, function(s) {
23536 Roo.get(_this.iframe.contentDocument.head).createChild({
23538 rel : 'stylesheet',
23547 removeStylesheets : function()
23551 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23556 setStyle : function(style)
23558 Roo.get(this.iframe.contentDocument.head).createChild({
23567 // hide stuff that is not compatible
23581 * @event specialkey
23585 * @cfg {String} fieldClass @hide
23588 * @cfg {String} focusClass @hide
23591 * @cfg {String} autoCreate @hide
23594 * @cfg {String} inputType @hide
23597 * @cfg {String} invalidClass @hide
23600 * @cfg {String} invalidText @hide
23603 * @cfg {String} msgFx @hide
23606 * @cfg {String} validateOnBlur @hide
23610 Roo.HtmlEditorCore.white = [
23611 'area', 'br', 'img', 'input', 'hr', 'wbr',
23613 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23614 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23615 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23616 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23617 'table', 'ul', 'xmp',
23619 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23622 'dir', 'menu', 'ol', 'ul', 'dl',
23628 Roo.HtmlEditorCore.black = [
23629 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23631 'base', 'basefont', 'bgsound', 'blink', 'body',
23632 'frame', 'frameset', 'head', 'html', 'ilayer',
23633 'iframe', 'layer', 'link', 'meta', 'object',
23634 'script', 'style' ,'title', 'xml' // clean later..
23636 Roo.HtmlEditorCore.clean = [
23637 'script', 'style', 'title', 'xml'
23639 Roo.HtmlEditorCore.remove = [
23644 Roo.HtmlEditorCore.ablack = [
23648 Roo.HtmlEditorCore.aclean = [
23649 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23653 Roo.HtmlEditorCore.pwhite= [
23654 'http', 'https', 'mailto'
23657 // white listed style attributes.
23658 Roo.HtmlEditorCore.cwhite= [
23659 // 'text-align', /// default is to allow most things..
23665 // black listed style attributes.
23666 Roo.HtmlEditorCore.cblack= [
23667 // 'font-size' -- this can be set by the project
23671 Roo.HtmlEditorCore.swapCodes =[
23690 * @class Roo.bootstrap.HtmlEditor
23691 * @extends Roo.bootstrap.TextArea
23692 * Bootstrap HtmlEditor class
23695 * Create a new HtmlEditor
23696 * @param {Object} config The config object
23699 Roo.bootstrap.HtmlEditor = function(config){
23700 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23701 if (!this.toolbars) {
23702 this.toolbars = [];
23705 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23708 * @event initialize
23709 * Fires when the editor is fully initialized (including the iframe)
23710 * @param {HtmlEditor} this
23715 * Fires when the editor is first receives the focus. Any insertion must wait
23716 * until after this event.
23717 * @param {HtmlEditor} this
23721 * @event beforesync
23722 * Fires before the textarea is updated with content from the editor iframe. Return false
23723 * to cancel the sync.
23724 * @param {HtmlEditor} this
23725 * @param {String} html
23729 * @event beforepush
23730 * Fires before the iframe editor is updated with content from the textarea. Return false
23731 * to cancel the push.
23732 * @param {HtmlEditor} this
23733 * @param {String} html
23738 * Fires when the textarea is updated with content from the editor iframe.
23739 * @param {HtmlEditor} this
23740 * @param {String} html
23745 * Fires when the iframe editor is updated with content from the textarea.
23746 * @param {HtmlEditor} this
23747 * @param {String} html
23751 * @event editmodechange
23752 * Fires when the editor switches edit modes
23753 * @param {HtmlEditor} this
23754 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23756 editmodechange: true,
23758 * @event editorevent
23759 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23760 * @param {HtmlEditor} this
23764 * @event firstfocus
23765 * Fires when on first focus - needed by toolbars..
23766 * @param {HtmlEditor} this
23771 * Auto save the htmlEditor value as a file into Events
23772 * @param {HtmlEditor} this
23776 * @event savedpreview
23777 * preview the saved version of htmlEditor
23778 * @param {HtmlEditor} this
23785 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23789 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23794 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23799 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23804 * @cfg {Number} height (in pixels)
23808 * @cfg {Number} width (in pixels)
23813 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23816 stylesheets: false,
23821 // private properties
23822 validationEvent : false,
23824 initialized : false,
23827 onFocus : Roo.emptyFn,
23829 hideMode:'offsets',
23831 tbContainer : false,
23835 toolbarContainer :function() {
23836 return this.wrap.select('.x-html-editor-tb',true).first();
23840 * Protected method that will not generally be called directly. It
23841 * is called when the editor creates its toolbar. Override this method if you need to
23842 * add custom toolbar buttons.
23843 * @param {HtmlEditor} editor
23845 createToolbar : function(){
23846 Roo.log('renewing');
23847 Roo.log("create toolbars");
23849 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23850 this.toolbars[0].render(this.toolbarContainer());
23854 // if (!editor.toolbars || !editor.toolbars.length) {
23855 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23858 // for (var i =0 ; i < editor.toolbars.length;i++) {
23859 // editor.toolbars[i] = Roo.factory(
23860 // typeof(editor.toolbars[i]) == 'string' ?
23861 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23862 // Roo.bootstrap.HtmlEditor);
23863 // editor.toolbars[i].init(editor);
23869 onRender : function(ct, position)
23871 // Roo.log("Call onRender: " + this.xtype);
23873 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23875 this.wrap = this.inputEl().wrap({
23876 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23879 this.editorcore.onRender(ct, position);
23881 if (this.resizable) {
23882 this.resizeEl = new Roo.Resizable(this.wrap, {
23886 minHeight : this.height,
23887 height: this.height,
23888 handles : this.resizable,
23891 resize : function(r, w, h) {
23892 _t.onResize(w,h); // -something
23898 this.createToolbar(this);
23901 if(!this.width && this.resizable){
23902 this.setSize(this.wrap.getSize());
23904 if (this.resizeEl) {
23905 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23906 // should trigger onReize..
23912 onResize : function(w, h)
23914 Roo.log('resize: ' +w + ',' + h );
23915 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23919 if(this.inputEl() ){
23920 if(typeof w == 'number'){
23921 var aw = w - this.wrap.getFrameWidth('lr');
23922 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23925 if(typeof h == 'number'){
23926 var tbh = -11; // fixme it needs to tool bar size!
23927 for (var i =0; i < this.toolbars.length;i++) {
23928 // fixme - ask toolbars for heights?
23929 tbh += this.toolbars[i].el.getHeight();
23930 //if (this.toolbars[i].footer) {
23931 // tbh += this.toolbars[i].footer.el.getHeight();
23939 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23940 ah -= 5; // knock a few pixes off for look..
23941 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23945 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23946 this.editorcore.onResize(ew,eh);
23951 * Toggles the editor between standard and source edit mode.
23952 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23954 toggleSourceEdit : function(sourceEditMode)
23956 this.editorcore.toggleSourceEdit(sourceEditMode);
23958 if(this.editorcore.sourceEditMode){
23959 Roo.log('editor - showing textarea');
23962 // Roo.log(this.syncValue());
23964 this.inputEl().removeClass(['hide', 'x-hidden']);
23965 this.inputEl().dom.removeAttribute('tabIndex');
23966 this.inputEl().focus();
23968 Roo.log('editor - hiding textarea');
23970 // Roo.log(this.pushValue());
23973 this.inputEl().addClass(['hide', 'x-hidden']);
23974 this.inputEl().dom.setAttribute('tabIndex', -1);
23975 //this.deferFocus();
23978 if(this.resizable){
23979 this.setSize(this.wrap.getSize());
23982 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23985 // private (for BoxComponent)
23986 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23988 // private (for BoxComponent)
23989 getResizeEl : function(){
23993 // private (for BoxComponent)
23994 getPositionEl : function(){
23999 initEvents : function(){
24000 this.originalValue = this.getValue();
24004 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24007 // markInvalid : Roo.emptyFn,
24009 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24012 // clearInvalid : Roo.emptyFn,
24014 setValue : function(v){
24015 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24016 this.editorcore.pushValue();
24021 deferFocus : function(){
24022 this.focus.defer(10, this);
24026 focus : function(){
24027 this.editorcore.focus();
24033 onDestroy : function(){
24039 for (var i =0; i < this.toolbars.length;i++) {
24040 // fixme - ask toolbars for heights?
24041 this.toolbars[i].onDestroy();
24044 this.wrap.dom.innerHTML = '';
24045 this.wrap.remove();
24050 onFirstFocus : function(){
24051 //Roo.log("onFirstFocus");
24052 this.editorcore.onFirstFocus();
24053 for (var i =0; i < this.toolbars.length;i++) {
24054 this.toolbars[i].onFirstFocus();
24060 syncValue : function()
24062 this.editorcore.syncValue();
24065 pushValue : function()
24067 this.editorcore.pushValue();
24071 // hide stuff that is not compatible
24085 * @event specialkey
24089 * @cfg {String} fieldClass @hide
24092 * @cfg {String} focusClass @hide
24095 * @cfg {String} autoCreate @hide
24098 * @cfg {String} inputType @hide
24102 * @cfg {String} invalidText @hide
24105 * @cfg {String} msgFx @hide
24108 * @cfg {String} validateOnBlur @hide
24117 Roo.namespace('Roo.bootstrap.htmleditor');
24119 * @class Roo.bootstrap.HtmlEditorToolbar1
24125 new Roo.bootstrap.HtmlEditor({
24128 new Roo.bootstrap.HtmlEditorToolbar1({
24129 disable : { fonts: 1 , format: 1, ..., ... , ...],
24135 * @cfg {Object} disable List of elements to disable..
24136 * @cfg {Array} btns List of additional buttons.
24140 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24143 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24146 Roo.apply(this, config);
24148 // default disabled, based on 'good practice'..
24149 this.disable = this.disable || {};
24150 Roo.applyIf(this.disable, {
24153 specialElements : true
24155 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24157 this.editor = config.editor;
24158 this.editorcore = config.editor.editorcore;
24160 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24162 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24163 // dont call parent... till later.
24165 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24170 editorcore : false,
24175 "h1","h2","h3","h4","h5","h6",
24177 "abbr", "acronym", "address", "cite", "samp", "var",
24181 onRender : function(ct, position)
24183 // Roo.log("Call onRender: " + this.xtype);
24185 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24187 this.el.dom.style.marginBottom = '0';
24189 var editorcore = this.editorcore;
24190 var editor= this.editor;
24193 var btn = function(id,cmd , toggle, handler, html){
24195 var event = toggle ? 'toggle' : 'click';
24200 xns: Roo.bootstrap,
24204 enableToggle:toggle !== false,
24206 pressed : toggle ? false : null,
24209 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24210 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24216 // var cb_box = function...
24221 xns: Roo.bootstrap,
24226 xns: Roo.bootstrap,
24230 Roo.each(this.formats, function(f) {
24231 style.menu.items.push({
24233 xns: Roo.bootstrap,
24234 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24239 editorcore.insertTag(this.tagname);
24246 children.push(style);
24248 btn('bold',false,true);
24249 btn('italic',false,true);
24250 btn('align-left', 'justifyleft',true);
24251 btn('align-center', 'justifycenter',true);
24252 btn('align-right' , 'justifyright',true);
24253 btn('link', false, false, function(btn) {
24254 //Roo.log("create link?");
24255 var url = prompt(this.createLinkText, this.defaultLinkValue);
24256 if(url && url != 'http:/'+'/'){
24257 this.editorcore.relayCmd('createlink', url);
24260 btn('list','insertunorderedlist',true);
24261 btn('pencil', false,true, function(btn){
24263 this.toggleSourceEdit(btn.pressed);
24266 if (this.editor.btns.length > 0) {
24267 for (var i = 0; i<this.editor.btns.length; i++) {
24268 children.push(this.editor.btns[i]);
24276 xns: Roo.bootstrap,
24281 xns: Roo.bootstrap,
24286 cog.menu.items.push({
24288 xns: Roo.bootstrap,
24289 html : Clean styles,
24294 editorcore.insertTag(this.tagname);
24303 this.xtype = 'NavSimplebar';
24305 for(var i=0;i< children.length;i++) {
24307 this.buttons.add(this.addxtypeChild(children[i]));
24311 editor.on('editorevent', this.updateToolbar, this);
24313 onBtnClick : function(id)
24315 this.editorcore.relayCmd(id);
24316 this.editorcore.focus();
24320 * Protected method that will not generally be called directly. It triggers
24321 * a toolbar update by reading the markup state of the current selection in the editor.
24323 updateToolbar: function(){
24325 if(!this.editorcore.activated){
24326 this.editor.onFirstFocus(); // is this neeed?
24330 var btns = this.buttons;
24331 var doc = this.editorcore.doc;
24332 btns.get('bold').setActive(doc.queryCommandState('bold'));
24333 btns.get('italic').setActive(doc.queryCommandState('italic'));
24334 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24336 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24337 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24338 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24340 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24341 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24344 var ans = this.editorcore.getAllAncestors();
24345 if (this.formatCombo) {
24348 var store = this.formatCombo.store;
24349 this.formatCombo.setValue("");
24350 for (var i =0; i < ans.length;i++) {
24351 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24353 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24361 // hides menus... - so this cant be on a menu...
24362 Roo.bootstrap.MenuMgr.hideAll();
24364 Roo.bootstrap.MenuMgr.hideAll();
24365 //this.editorsyncValue();
24367 onFirstFocus: function() {
24368 this.buttons.each(function(item){
24372 toggleSourceEdit : function(sourceEditMode){
24375 if(sourceEditMode){
24376 Roo.log("disabling buttons");
24377 this.buttons.each( function(item){
24378 if(item.cmd != 'pencil'){
24384 Roo.log("enabling buttons");
24385 if(this.editorcore.initialized){
24386 this.buttons.each( function(item){
24392 Roo.log("calling toggole on editor");
24393 // tell the editor that it's been pressed..
24394 this.editor.toggleSourceEdit(sourceEditMode);
24404 * @class Roo.bootstrap.Table.AbstractSelectionModel
24405 * @extends Roo.util.Observable
24406 * Abstract base class for grid SelectionModels. It provides the interface that should be
24407 * implemented by descendant classes. This class should not be directly instantiated.
24410 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24411 this.locked = false;
24412 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24416 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24417 /** @ignore Called by the grid automatically. Do not call directly. */
24418 init : function(grid){
24424 * Locks the selections.
24427 this.locked = true;
24431 * Unlocks the selections.
24433 unlock : function(){
24434 this.locked = false;
24438 * Returns true if the selections are locked.
24439 * @return {Boolean}
24441 isLocked : function(){
24442 return this.locked;
24446 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24447 * @class Roo.bootstrap.Table.RowSelectionModel
24448 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24449 * It supports multiple selections and keyboard selection/navigation.
24451 * @param {Object} config
24454 Roo.bootstrap.Table.RowSelectionModel = function(config){
24455 Roo.apply(this, config);
24456 this.selections = new Roo.util.MixedCollection(false, function(o){
24461 this.lastActive = false;
24465 * @event selectionchange
24466 * Fires when the selection changes
24467 * @param {SelectionModel} this
24469 "selectionchange" : true,
24471 * @event afterselectionchange
24472 * Fires after the selection changes (eg. by key press or clicking)
24473 * @param {SelectionModel} this
24475 "afterselectionchange" : true,
24477 * @event beforerowselect
24478 * Fires when a row is selected being selected, return false to cancel.
24479 * @param {SelectionModel} this
24480 * @param {Number} rowIndex The selected index
24481 * @param {Boolean} keepExisting False if other selections will be cleared
24483 "beforerowselect" : true,
24486 * Fires when a row is selected.
24487 * @param {SelectionModel} this
24488 * @param {Number} rowIndex The selected index
24489 * @param {Roo.data.Record} r The record
24491 "rowselect" : true,
24493 * @event rowdeselect
24494 * Fires when a row is deselected.
24495 * @param {SelectionModel} this
24496 * @param {Number} rowIndex The selected index
24498 "rowdeselect" : true
24500 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24501 this.locked = false;
24504 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24506 * @cfg {Boolean} singleSelect
24507 * True to allow selection of only one row at a time (defaults to false)
24509 singleSelect : false,
24512 initEvents : function()
24515 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24516 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24517 //}else{ // allow click to work like normal
24518 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24520 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24521 this.grid.on("rowclick", this.handleMouseDown, this);
24523 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24524 "up" : function(e){
24526 this.selectPrevious(e.shiftKey);
24527 }else if(this.last !== false && this.lastActive !== false){
24528 var last = this.last;
24529 this.selectRange(this.last, this.lastActive-1);
24530 this.grid.getView().focusRow(this.lastActive);
24531 if(last !== false){
24535 this.selectFirstRow();
24537 this.fireEvent("afterselectionchange", this);
24539 "down" : function(e){
24541 this.selectNext(e.shiftKey);
24542 }else if(this.last !== false && this.lastActive !== false){
24543 var last = this.last;
24544 this.selectRange(this.last, this.lastActive+1);
24545 this.grid.getView().focusRow(this.lastActive);
24546 if(last !== false){
24550 this.selectFirstRow();
24552 this.fireEvent("afterselectionchange", this);
24556 this.grid.store.on('load', function(){
24557 this.selections.clear();
24560 var view = this.grid.view;
24561 view.on("refresh", this.onRefresh, this);
24562 view.on("rowupdated", this.onRowUpdated, this);
24563 view.on("rowremoved", this.onRemove, this);
24568 onRefresh : function()
24570 var ds = this.grid.store, i, v = this.grid.view;
24571 var s = this.selections;
24572 s.each(function(r){
24573 if((i = ds.indexOfId(r.id)) != -1){
24582 onRemove : function(v, index, r){
24583 this.selections.remove(r);
24587 onRowUpdated : function(v, index, r){
24588 if(this.isSelected(r)){
24589 v.onRowSelect(index);
24595 * @param {Array} records The records to select
24596 * @param {Boolean} keepExisting (optional) True to keep existing selections
24598 selectRecords : function(records, keepExisting)
24601 this.clearSelections();
24603 var ds = this.grid.store;
24604 for(var i = 0, len = records.length; i < len; i++){
24605 this.selectRow(ds.indexOf(records[i]), true);
24610 * Gets the number of selected rows.
24613 getCount : function(){
24614 return this.selections.length;
24618 * Selects the first row in the grid.
24620 selectFirstRow : function(){
24625 * Select the last row.
24626 * @param {Boolean} keepExisting (optional) True to keep existing selections
24628 selectLastRow : function(keepExisting){
24629 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24630 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24634 * Selects the row immediately following the last selected row.
24635 * @param {Boolean} keepExisting (optional) True to keep existing selections
24637 selectNext : function(keepExisting)
24639 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24640 this.selectRow(this.last+1, keepExisting);
24641 this.grid.getView().focusRow(this.last);
24646 * Selects the row that precedes the last selected row.
24647 * @param {Boolean} keepExisting (optional) True to keep existing selections
24649 selectPrevious : function(keepExisting){
24651 this.selectRow(this.last-1, keepExisting);
24652 this.grid.getView().focusRow(this.last);
24657 * Returns the selected records
24658 * @return {Array} Array of selected records
24660 getSelections : function(){
24661 return [].concat(this.selections.items);
24665 * Returns the first selected record.
24668 getSelected : function(){
24669 return this.selections.itemAt(0);
24674 * Clears all selections.
24676 clearSelections : function(fast)
24682 var ds = this.grid.store;
24683 var s = this.selections;
24684 s.each(function(r){
24685 this.deselectRow(ds.indexOfId(r.id));
24689 this.selections.clear();
24696 * Selects all rows.
24698 selectAll : function(){
24702 this.selections.clear();
24703 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24704 this.selectRow(i, true);
24709 * Returns True if there is a selection.
24710 * @return {Boolean}
24712 hasSelection : function(){
24713 return this.selections.length > 0;
24717 * Returns True if the specified row is selected.
24718 * @param {Number/Record} record The record or index of the record to check
24719 * @return {Boolean}
24721 isSelected : function(index){
24722 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24723 return (r && this.selections.key(r.id) ? true : false);
24727 * Returns True if the specified record id is selected.
24728 * @param {String} id The id of record to check
24729 * @return {Boolean}
24731 isIdSelected : function(id){
24732 return (this.selections.key(id) ? true : false);
24737 handleMouseDBClick : function(e, t){
24741 handleMouseDown : function(e, t)
24743 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24744 if(this.isLocked() || rowIndex < 0 ){
24747 if(e.shiftKey && this.last !== false){
24748 var last = this.last;
24749 this.selectRange(last, rowIndex, e.ctrlKey);
24750 this.last = last; // reset the last
24754 var isSelected = this.isSelected(rowIndex);
24755 //Roo.log("select row:" + rowIndex);
24757 this.deselectRow(rowIndex);
24759 this.selectRow(rowIndex, true);
24763 if(e.button !== 0 && isSelected){
24764 alert('rowIndex 2: ' + rowIndex);
24765 view.focusRow(rowIndex);
24766 }else if(e.ctrlKey && isSelected){
24767 this.deselectRow(rowIndex);
24768 }else if(!isSelected){
24769 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24770 view.focusRow(rowIndex);
24774 this.fireEvent("afterselectionchange", this);
24777 handleDragableRowClick : function(grid, rowIndex, e)
24779 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24780 this.selectRow(rowIndex, false);
24781 grid.view.focusRow(rowIndex);
24782 this.fireEvent("afterselectionchange", this);
24787 * Selects multiple rows.
24788 * @param {Array} rows Array of the indexes of the row to select
24789 * @param {Boolean} keepExisting (optional) True to keep existing selections
24791 selectRows : function(rows, keepExisting){
24793 this.clearSelections();
24795 for(var i = 0, len = rows.length; i < len; i++){
24796 this.selectRow(rows[i], true);
24801 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24802 * @param {Number} startRow The index of the first row in the range
24803 * @param {Number} endRow The index of the last row in the range
24804 * @param {Boolean} keepExisting (optional) True to retain existing selections
24806 selectRange : function(startRow, endRow, keepExisting){
24811 this.clearSelections();
24813 if(startRow <= endRow){
24814 for(var i = startRow; i <= endRow; i++){
24815 this.selectRow(i, true);
24818 for(var i = startRow; i >= endRow; i--){
24819 this.selectRow(i, true);
24825 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24826 * @param {Number} startRow The index of the first row in the range
24827 * @param {Number} endRow The index of the last row in the range
24829 deselectRange : function(startRow, endRow, preventViewNotify){
24833 for(var i = startRow; i <= endRow; i++){
24834 this.deselectRow(i, preventViewNotify);
24840 * @param {Number} row The index of the row to select
24841 * @param {Boolean} keepExisting (optional) True to keep existing selections
24843 selectRow : function(index, keepExisting, preventViewNotify)
24845 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24848 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24849 if(!keepExisting || this.singleSelect){
24850 this.clearSelections();
24853 var r = this.grid.store.getAt(index);
24854 //console.log('selectRow - record id :' + r.id);
24856 this.selections.add(r);
24857 this.last = this.lastActive = index;
24858 if(!preventViewNotify){
24859 var proxy = new Roo.Element(
24860 this.grid.getRowDom(index)
24862 proxy.addClass('bg-info info');
24864 this.fireEvent("rowselect", this, index, r);
24865 this.fireEvent("selectionchange", this);
24871 * @param {Number} row The index of the row to deselect
24873 deselectRow : function(index, preventViewNotify)
24878 if(this.last == index){
24881 if(this.lastActive == index){
24882 this.lastActive = false;
24885 var r = this.grid.store.getAt(index);
24890 this.selections.remove(r);
24891 //.console.log('deselectRow - record id :' + r.id);
24892 if(!preventViewNotify){
24894 var proxy = new Roo.Element(
24895 this.grid.getRowDom(index)
24897 proxy.removeClass('bg-info info');
24899 this.fireEvent("rowdeselect", this, index);
24900 this.fireEvent("selectionchange", this);
24904 restoreLast : function(){
24906 this.last = this._last;
24911 acceptsNav : function(row, col, cm){
24912 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24916 onEditorKey : function(field, e){
24917 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24922 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24924 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24926 }else if(k == e.ENTER && !e.ctrlKey){
24930 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24932 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24934 }else if(k == e.ESC){
24938 g.startEditing(newCell[0], newCell[1]);
24944 * Ext JS Library 1.1.1
24945 * Copyright(c) 2006-2007, Ext JS, LLC.
24947 * Originally Released Under LGPL - original licence link has changed is not relivant.
24950 * <script type="text/javascript">
24954 * @class Roo.bootstrap.PagingToolbar
24955 * @extends Roo.bootstrap.NavSimplebar
24956 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24958 * Create a new PagingToolbar
24959 * @param {Object} config The config object
24960 * @param {Roo.data.Store} store
24962 Roo.bootstrap.PagingToolbar = function(config)
24964 // old args format still supported... - xtype is prefered..
24965 // created from xtype...
24967 this.ds = config.dataSource;
24969 if (config.store && !this.ds) {
24970 this.store= Roo.factory(config.store, Roo.data);
24971 this.ds = this.store;
24972 this.ds.xmodule = this.xmodule || false;
24975 this.toolbarItems = [];
24976 if (config.items) {
24977 this.toolbarItems = config.items;
24980 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24985 this.bind(this.ds);
24988 if (Roo.bootstrap.version == 4) {
24989 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24991 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24996 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24998 * @cfg {Roo.data.Store} dataSource
24999 * The underlying data store providing the paged data
25002 * @cfg {String/HTMLElement/Element} container
25003 * container The id or element that will contain the toolbar
25006 * @cfg {Boolean} displayInfo
25007 * True to display the displayMsg (defaults to false)
25010 * @cfg {Number} pageSize
25011 * The number of records to display per page (defaults to 20)
25015 * @cfg {String} displayMsg
25016 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25018 displayMsg : 'Displaying {0} - {1} of {2}',
25020 * @cfg {String} emptyMsg
25021 * The message to display when no records are found (defaults to "No data to display")
25023 emptyMsg : 'No data to display',
25025 * Customizable piece of the default paging text (defaults to "Page")
25028 beforePageText : "Page",
25030 * Customizable piece of the default paging text (defaults to "of %0")
25033 afterPageText : "of {0}",
25035 * Customizable piece of the default paging text (defaults to "First Page")
25038 firstText : "First Page",
25040 * Customizable piece of the default paging text (defaults to "Previous Page")
25043 prevText : "Previous Page",
25045 * Customizable piece of the default paging text (defaults to "Next Page")
25048 nextText : "Next Page",
25050 * Customizable piece of the default paging text (defaults to "Last Page")
25053 lastText : "Last Page",
25055 * Customizable piece of the default paging text (defaults to "Refresh")
25058 refreshText : "Refresh",
25062 onRender : function(ct, position)
25064 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25065 this.navgroup.parentId = this.id;
25066 this.navgroup.onRender(this.el, null);
25067 // add the buttons to the navgroup
25069 if(this.displayInfo){
25070 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25071 this.displayEl = this.el.select('.x-paging-info', true).first();
25072 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25073 // this.displayEl = navel.el.select('span',true).first();
25079 Roo.each(_this.buttons, function(e){ // this might need to use render????
25080 Roo.factory(e).render(_this.el);
25084 Roo.each(_this.toolbarItems, function(e) {
25085 _this.navgroup.addItem(e);
25089 this.first = this.navgroup.addItem({
25090 tooltip: this.firstText,
25091 cls: "prev btn-outline-secondary",
25092 html : ' <i class="fa fa-step-backward"></i>',
25094 preventDefault: true,
25095 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25098 this.prev = this.navgroup.addItem({
25099 tooltip: this.prevText,
25100 cls: "prev btn-outline-secondary",
25101 html : ' <i class="fa fa-backward"></i>',
25103 preventDefault: true,
25104 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25106 //this.addSeparator();
25109 var field = this.navgroup.addItem( {
25111 cls : 'x-paging-position btn-outline-secondary',
25113 html : this.beforePageText +
25114 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25115 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25118 this.field = field.el.select('input', true).first();
25119 this.field.on("keydown", this.onPagingKeydown, this);
25120 this.field.on("focus", function(){this.dom.select();});
25123 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25124 //this.field.setHeight(18);
25125 //this.addSeparator();
25126 this.next = this.navgroup.addItem({
25127 tooltip: this.nextText,
25128 cls: "next btn-outline-secondary",
25129 html : ' <i class="fa fa-forward"></i>',
25131 preventDefault: true,
25132 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25134 this.last = this.navgroup.addItem({
25135 tooltip: this.lastText,
25136 html : ' <i class="fa fa-step-forward"></i>',
25137 cls: "next btn-outline-secondary",
25139 preventDefault: true,
25140 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25142 //this.addSeparator();
25143 this.loading = this.navgroup.addItem({
25144 tooltip: this.refreshText,
25145 cls: "btn-outline-secondary",
25146 html : ' <i class="fa fa-refresh"></i>',
25147 preventDefault: true,
25148 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25154 updateInfo : function(){
25155 if(this.displayEl){
25156 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25157 var msg = count == 0 ?
25161 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25163 this.displayEl.update(msg);
25168 onLoad : function(ds, r, o)
25170 this.cursor = o.params.start ? o.params.start : 0;
25172 var d = this.getPageData(),
25177 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25178 this.field.dom.value = ap;
25179 this.first.setDisabled(ap == 1);
25180 this.prev.setDisabled(ap == 1);
25181 this.next.setDisabled(ap == ps);
25182 this.last.setDisabled(ap == ps);
25183 this.loading.enable();
25188 getPageData : function(){
25189 var total = this.ds.getTotalCount();
25192 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25193 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25198 onLoadError : function(){
25199 this.loading.enable();
25203 onPagingKeydown : function(e){
25204 var k = e.getKey();
25205 var d = this.getPageData();
25207 var v = this.field.dom.value, pageNum;
25208 if(!v || isNaN(pageNum = parseInt(v, 10))){
25209 this.field.dom.value = d.activePage;
25212 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25213 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25216 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))
25218 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25219 this.field.dom.value = pageNum;
25220 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25223 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25225 var v = this.field.dom.value, pageNum;
25226 var increment = (e.shiftKey) ? 10 : 1;
25227 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25230 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25231 this.field.dom.value = d.activePage;
25234 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25236 this.field.dom.value = parseInt(v, 10) + increment;
25237 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25238 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25245 beforeLoad : function(){
25247 this.loading.disable();
25252 onClick : function(which){
25261 ds.load({params:{start: 0, limit: this.pageSize}});
25264 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25267 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25270 var total = ds.getTotalCount();
25271 var extra = total % this.pageSize;
25272 var lastStart = extra ? (total - extra) : total-this.pageSize;
25273 ds.load({params:{start: lastStart, limit: this.pageSize}});
25276 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25282 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25283 * @param {Roo.data.Store} store The data store to unbind
25285 unbind : function(ds){
25286 ds.un("beforeload", this.beforeLoad, this);
25287 ds.un("load", this.onLoad, this);
25288 ds.un("loadexception", this.onLoadError, this);
25289 ds.un("remove", this.updateInfo, this);
25290 ds.un("add", this.updateInfo, this);
25291 this.ds = undefined;
25295 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25296 * @param {Roo.data.Store} store The data store to bind
25298 bind : function(ds){
25299 ds.on("beforeload", this.beforeLoad, this);
25300 ds.on("load", this.onLoad, this);
25301 ds.on("loadexception", this.onLoadError, this);
25302 ds.on("remove", this.updateInfo, this);
25303 ds.on("add", this.updateInfo, this);
25314 * @class Roo.bootstrap.MessageBar
25315 * @extends Roo.bootstrap.Component
25316 * Bootstrap MessageBar class
25317 * @cfg {String} html contents of the MessageBar
25318 * @cfg {String} weight (info | success | warning | danger) default info
25319 * @cfg {String} beforeClass insert the bar before the given class
25320 * @cfg {Boolean} closable (true | false) default false
25321 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25324 * Create a new Element
25325 * @param {Object} config The config object
25328 Roo.bootstrap.MessageBar = function(config){
25329 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25332 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25338 beforeClass: 'bootstrap-sticky-wrap',
25340 getAutoCreate : function(){
25344 cls: 'alert alert-dismissable alert-' + this.weight,
25349 html: this.html || ''
25355 cfg.cls += ' alert-messages-fixed';
25369 onRender : function(ct, position)
25371 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25374 var cfg = Roo.apply({}, this.getAutoCreate());
25378 cfg.cls += ' ' + this.cls;
25381 cfg.style = this.style;
25383 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25385 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25388 this.el.select('>button.close').on('click', this.hide, this);
25394 if (!this.rendered) {
25400 this.fireEvent('show', this);
25406 if (!this.rendered) {
25412 this.fireEvent('hide', this);
25415 update : function()
25417 // var e = this.el.dom.firstChild;
25419 // if(this.closable){
25420 // e = e.nextSibling;
25423 // e.data = this.html || '';
25425 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25441 * @class Roo.bootstrap.Graph
25442 * @extends Roo.bootstrap.Component
25443 * Bootstrap Graph class
25447 @cfg {String} graphtype bar | vbar | pie
25448 @cfg {number} g_x coodinator | centre x (pie)
25449 @cfg {number} g_y coodinator | centre y (pie)
25450 @cfg {number} g_r radius (pie)
25451 @cfg {number} g_height height of the chart (respected by all elements in the set)
25452 @cfg {number} g_width width of the chart (respected by all elements in the set)
25453 @cfg {Object} title The title of the chart
25456 -opts (object) options for the chart
25458 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25459 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25461 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.
25462 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25464 o stretch (boolean)
25466 -opts (object) options for the pie
25469 o startAngle (number)
25470 o endAngle (number)
25474 * Create a new Input
25475 * @param {Object} config The config object
25478 Roo.bootstrap.Graph = function(config){
25479 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25485 * The img click event for the img.
25486 * @param {Roo.EventObject} e
25492 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25503 //g_colors: this.colors,
25510 getAutoCreate : function(){
25521 onRender : function(ct,position){
25524 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25526 if (typeof(Raphael) == 'undefined') {
25527 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25531 this.raphael = Raphael(this.el.dom);
25533 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25534 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25535 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25536 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25538 r.text(160, 10, "Single Series Chart").attr(txtattr);
25539 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25540 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25541 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25543 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25544 r.barchart(330, 10, 300, 220, data1);
25545 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25546 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25549 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25550 // r.barchart(30, 30, 560, 250, xdata, {
25551 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25552 // axis : "0 0 1 1",
25553 // axisxlabels : xdata
25554 // //yvalues : cols,
25557 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25559 // this.load(null,xdata,{
25560 // axis : "0 0 1 1",
25561 // axisxlabels : xdata
25566 load : function(graphtype,xdata,opts)
25568 this.raphael.clear();
25570 graphtype = this.graphtype;
25575 var r = this.raphael,
25576 fin = function () {
25577 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25579 fout = function () {
25580 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25582 pfin = function() {
25583 this.sector.stop();
25584 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25587 this.label[0].stop();
25588 this.label[0].attr({ r: 7.5 });
25589 this.label[1].attr({ "font-weight": 800 });
25592 pfout = function() {
25593 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25596 this.label[0].animate({ r: 5 }, 500, "bounce");
25597 this.label[1].attr({ "font-weight": 400 });
25603 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25606 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25609 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25610 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25612 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25619 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25624 setTitle: function(o)
25629 initEvents: function() {
25632 this.el.on('click', this.onClick, this);
25636 onClick : function(e)
25638 Roo.log('img onclick');
25639 this.fireEvent('click', this, e);
25651 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25654 * @class Roo.bootstrap.dash.NumberBox
25655 * @extends Roo.bootstrap.Component
25656 * Bootstrap NumberBox class
25657 * @cfg {String} headline Box headline
25658 * @cfg {String} content Box content
25659 * @cfg {String} icon Box icon
25660 * @cfg {String} footer Footer text
25661 * @cfg {String} fhref Footer href
25664 * Create a new NumberBox
25665 * @param {Object} config The config object
25669 Roo.bootstrap.dash.NumberBox = function(config){
25670 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25674 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25683 getAutoCreate : function(){
25687 cls : 'small-box ',
25695 cls : 'roo-headline',
25696 html : this.headline
25700 cls : 'roo-content',
25701 html : this.content
25715 cls : 'ion ' + this.icon
25724 cls : 'small-box-footer',
25725 href : this.fhref || '#',
25729 cfg.cn.push(footer);
25736 onRender : function(ct,position){
25737 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25744 setHeadline: function (value)
25746 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25749 setFooter: function (value, href)
25751 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25754 this.el.select('a.small-box-footer',true).first().attr('href', href);
25759 setContent: function (value)
25761 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25764 initEvents: function()
25778 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25781 * @class Roo.bootstrap.dash.TabBox
25782 * @extends Roo.bootstrap.Component
25783 * Bootstrap TabBox class
25784 * @cfg {String} title Title of the TabBox
25785 * @cfg {String} icon Icon of the TabBox
25786 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25787 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25790 * Create a new TabBox
25791 * @param {Object} config The config object
25795 Roo.bootstrap.dash.TabBox = function(config){
25796 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25801 * When a pane is added
25802 * @param {Roo.bootstrap.dash.TabPane} pane
25806 * @event activatepane
25807 * When a pane is activated
25808 * @param {Roo.bootstrap.dash.TabPane} pane
25810 "activatepane" : true
25818 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25823 tabScrollable : false,
25825 getChildContainer : function()
25827 return this.el.select('.tab-content', true).first();
25830 getAutoCreate : function(){
25834 cls: 'pull-left header',
25842 cls: 'fa ' + this.icon
25848 cls: 'nav nav-tabs pull-right',
25854 if(this.tabScrollable){
25861 cls: 'nav nav-tabs pull-right',
25872 cls: 'nav-tabs-custom',
25877 cls: 'tab-content no-padding',
25885 initEvents : function()
25887 //Roo.log('add add pane handler');
25888 this.on('addpane', this.onAddPane, this);
25891 * Updates the box title
25892 * @param {String} html to set the title to.
25894 setTitle : function(value)
25896 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25898 onAddPane : function(pane)
25900 this.panes.push(pane);
25901 //Roo.log('addpane');
25903 // tabs are rendere left to right..
25904 if(!this.showtabs){
25908 var ctr = this.el.select('.nav-tabs', true).first();
25911 var existing = ctr.select('.nav-tab',true);
25912 var qty = existing.getCount();;
25915 var tab = ctr.createChild({
25917 cls : 'nav-tab' + (qty ? '' : ' active'),
25925 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25928 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25930 pane.el.addClass('active');
25935 onTabClick : function(ev,un,ob,pane)
25937 //Roo.log('tab - prev default');
25938 ev.preventDefault();
25941 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25942 pane.tab.addClass('active');
25943 //Roo.log(pane.title);
25944 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25945 // technically we should have a deactivate event.. but maybe add later.
25946 // and it should not de-activate the selected tab...
25947 this.fireEvent('activatepane', pane);
25948 pane.el.addClass('active');
25949 pane.fireEvent('activate');
25954 getActivePane : function()
25957 Roo.each(this.panes, function(p) {
25958 if(p.el.hasClass('active')){
25979 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25981 * @class Roo.bootstrap.TabPane
25982 * @extends Roo.bootstrap.Component
25983 * Bootstrap TabPane class
25984 * @cfg {Boolean} active (false | true) Default false
25985 * @cfg {String} title title of panel
25989 * Create a new TabPane
25990 * @param {Object} config The config object
25993 Roo.bootstrap.dash.TabPane = function(config){
25994 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26000 * When a pane is activated
26001 * @param {Roo.bootstrap.dash.TabPane} pane
26008 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26013 // the tabBox that this is attached to.
26016 getAutoCreate : function()
26024 cfg.cls += ' active';
26029 initEvents : function()
26031 //Roo.log('trigger add pane handler');
26032 this.parent().fireEvent('addpane', this)
26036 * Updates the tab title
26037 * @param {String} html to set the title to.
26039 setTitle: function(str)
26045 this.tab.select('a', true).first().dom.innerHTML = str;
26062 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26065 * @class Roo.bootstrap.menu.Menu
26066 * @extends Roo.bootstrap.Component
26067 * Bootstrap Menu class - container for Menu
26068 * @cfg {String} html Text of the menu
26069 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26070 * @cfg {String} icon Font awesome icon
26071 * @cfg {String} pos Menu align to (top | bottom) default bottom
26075 * Create a new Menu
26076 * @param {Object} config The config object
26080 Roo.bootstrap.menu.Menu = function(config){
26081 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26085 * @event beforeshow
26086 * Fires before this menu is displayed
26087 * @param {Roo.bootstrap.menu.Menu} this
26091 * @event beforehide
26092 * Fires before this menu is hidden
26093 * @param {Roo.bootstrap.menu.Menu} this
26098 * Fires after this menu is displayed
26099 * @param {Roo.bootstrap.menu.Menu} this
26104 * Fires after this menu is hidden
26105 * @param {Roo.bootstrap.menu.Menu} this
26110 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26111 * @param {Roo.bootstrap.menu.Menu} this
26112 * @param {Roo.EventObject} e
26119 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26123 weight : 'default',
26128 getChildContainer : function() {
26129 if(this.isSubMenu){
26133 return this.el.select('ul.dropdown-menu', true).first();
26136 getAutoCreate : function()
26141 cls : 'roo-menu-text',
26149 cls : 'fa ' + this.icon
26160 cls : 'dropdown-button btn btn-' + this.weight,
26165 cls : 'dropdown-toggle btn btn-' + this.weight,
26175 cls : 'dropdown-menu'
26181 if(this.pos == 'top'){
26182 cfg.cls += ' dropup';
26185 if(this.isSubMenu){
26188 cls : 'dropdown-menu'
26195 onRender : function(ct, position)
26197 this.isSubMenu = ct.hasClass('dropdown-submenu');
26199 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26202 initEvents : function()
26204 if(this.isSubMenu){
26208 this.hidden = true;
26210 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26211 this.triggerEl.on('click', this.onTriggerPress, this);
26213 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26214 this.buttonEl.on('click', this.onClick, this);
26220 if(this.isSubMenu){
26224 return this.el.select('ul.dropdown-menu', true).first();
26227 onClick : function(e)
26229 this.fireEvent("click", this, e);
26232 onTriggerPress : function(e)
26234 if (this.isVisible()) {
26241 isVisible : function(){
26242 return !this.hidden;
26247 this.fireEvent("beforeshow", this);
26249 this.hidden = false;
26250 this.el.addClass('open');
26252 Roo.get(document).on("mouseup", this.onMouseUp, this);
26254 this.fireEvent("show", this);
26261 this.fireEvent("beforehide", this);
26263 this.hidden = true;
26264 this.el.removeClass('open');
26266 Roo.get(document).un("mouseup", this.onMouseUp);
26268 this.fireEvent("hide", this);
26271 onMouseUp : function()
26285 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26288 * @class Roo.bootstrap.menu.Item
26289 * @extends Roo.bootstrap.Component
26290 * Bootstrap MenuItem class
26291 * @cfg {Boolean} submenu (true | false) default false
26292 * @cfg {String} html text of the item
26293 * @cfg {String} href the link
26294 * @cfg {Boolean} disable (true | false) default false
26295 * @cfg {Boolean} preventDefault (true | false) default true
26296 * @cfg {String} icon Font awesome icon
26297 * @cfg {String} pos Submenu align to (left | right) default right
26301 * Create a new Item
26302 * @param {Object} config The config object
26306 Roo.bootstrap.menu.Item = function(config){
26307 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26311 * Fires when the mouse is hovering over this menu
26312 * @param {Roo.bootstrap.menu.Item} this
26313 * @param {Roo.EventObject} e
26318 * Fires when the mouse exits this menu
26319 * @param {Roo.bootstrap.menu.Item} this
26320 * @param {Roo.EventObject} e
26326 * The raw click event for the entire grid.
26327 * @param {Roo.EventObject} e
26333 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26338 preventDefault: true,
26343 getAutoCreate : function()
26348 cls : 'roo-menu-item-text',
26356 cls : 'fa ' + this.icon
26365 href : this.href || '#',
26372 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26376 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26378 if(this.pos == 'left'){
26379 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26386 initEvents : function()
26388 this.el.on('mouseover', this.onMouseOver, this);
26389 this.el.on('mouseout', this.onMouseOut, this);
26391 this.el.select('a', true).first().on('click', this.onClick, this);
26395 onClick : function(e)
26397 if(this.preventDefault){
26398 e.preventDefault();
26401 this.fireEvent("click", this, e);
26404 onMouseOver : function(e)
26406 if(this.submenu && this.pos == 'left'){
26407 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26410 this.fireEvent("mouseover", this, e);
26413 onMouseOut : function(e)
26415 this.fireEvent("mouseout", this, e);
26427 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26430 * @class Roo.bootstrap.menu.Separator
26431 * @extends Roo.bootstrap.Component
26432 * Bootstrap Separator class
26435 * Create a new Separator
26436 * @param {Object} config The config object
26440 Roo.bootstrap.menu.Separator = function(config){
26441 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26444 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26446 getAutoCreate : function(){
26467 * @class Roo.bootstrap.Tooltip
26468 * Bootstrap Tooltip class
26469 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26470 * to determine which dom element triggers the tooltip.
26472 * It needs to add support for additional attributes like tooltip-position
26475 * Create a new Toolti
26476 * @param {Object} config The config object
26479 Roo.bootstrap.Tooltip = function(config){
26480 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26482 this.alignment = Roo.bootstrap.Tooltip.alignment;
26484 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26485 this.alignment = config.alignment;
26490 Roo.apply(Roo.bootstrap.Tooltip, {
26492 * @function init initialize tooltip monitoring.
26496 currentTip : false,
26497 currentRegion : false,
26503 Roo.get(document).on('mouseover', this.enter ,this);
26504 Roo.get(document).on('mouseout', this.leave, this);
26507 this.currentTip = new Roo.bootstrap.Tooltip();
26510 enter : function(ev)
26512 var dom = ev.getTarget();
26514 //Roo.log(['enter',dom]);
26515 var el = Roo.fly(dom);
26516 if (this.currentEl) {
26518 //Roo.log(this.currentEl);
26519 //Roo.log(this.currentEl.contains(dom));
26520 if (this.currentEl == el) {
26523 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26529 if (this.currentTip.el) {
26530 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26534 if(!el || el.dom == document){
26540 // you can not look for children, as if el is the body.. then everythign is the child..
26541 if (!el.attr('tooltip')) { //
26542 if (!el.select("[tooltip]").elements.length) {
26545 // is the mouse over this child...?
26546 bindEl = el.select("[tooltip]").first();
26547 var xy = ev.getXY();
26548 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26549 //Roo.log("not in region.");
26552 //Roo.log("child element over..");
26555 this.currentEl = bindEl;
26556 this.currentTip.bind(bindEl);
26557 this.currentRegion = Roo.lib.Region.getRegion(dom);
26558 this.currentTip.enter();
26561 leave : function(ev)
26563 var dom = ev.getTarget();
26564 //Roo.log(['leave',dom]);
26565 if (!this.currentEl) {
26570 if (dom != this.currentEl.dom) {
26573 var xy = ev.getXY();
26574 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26577 // only activate leave if mouse cursor is outside... bounding box..
26582 if (this.currentTip) {
26583 this.currentTip.leave();
26585 //Roo.log('clear currentEl');
26586 this.currentEl = false;
26591 'left' : ['r-l', [-2,0], 'right'],
26592 'right' : ['l-r', [2,0], 'left'],
26593 'bottom' : ['t-b', [0,2], 'top'],
26594 'top' : [ 'b-t', [0,-2], 'bottom']
26600 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26605 delay : null, // can be { show : 300 , hide: 500}
26609 hoverState : null, //???
26611 placement : 'bottom',
26615 getAutoCreate : function(){
26622 cls : 'tooltip-arrow'
26625 cls : 'tooltip-inner'
26632 bind : function(el)
26638 enter : function () {
26640 if (this.timeout != null) {
26641 clearTimeout(this.timeout);
26644 this.hoverState = 'in';
26645 //Roo.log("enter - show");
26646 if (!this.delay || !this.delay.show) {
26651 this.timeout = setTimeout(function () {
26652 if (_t.hoverState == 'in') {
26655 }, this.delay.show);
26659 clearTimeout(this.timeout);
26661 this.hoverState = 'out';
26662 if (!this.delay || !this.delay.hide) {
26668 this.timeout = setTimeout(function () {
26669 //Roo.log("leave - timeout");
26671 if (_t.hoverState == 'out') {
26673 Roo.bootstrap.Tooltip.currentEl = false;
26678 show : function (msg)
26681 this.render(document.body);
26684 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26686 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26688 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26690 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26692 var placement = typeof this.placement == 'function' ?
26693 this.placement.call(this, this.el, on_el) :
26696 var autoToken = /\s?auto?\s?/i;
26697 var autoPlace = autoToken.test(placement);
26699 placement = placement.replace(autoToken, '') || 'top';
26703 //this.el.setXY([0,0]);
26705 //this.el.dom.style.display='block';
26707 //this.el.appendTo(on_el);
26709 var p = this.getPosition();
26710 var box = this.el.getBox();
26716 var align = this.alignment[placement];
26718 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26720 if(placement == 'top' || placement == 'bottom'){
26722 placement = 'right';
26725 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26726 placement = 'left';
26729 var scroll = Roo.select('body', true).first().getScroll();
26731 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26735 align = this.alignment[placement];
26738 this.el.alignTo(this.bindEl, align[0],align[1]);
26739 //var arrow = this.el.select('.arrow',true).first();
26740 //arrow.set(align[2],
26742 this.el.addClass(placement);
26744 this.el.addClass('in fade');
26746 this.hoverState = null;
26748 if (this.el.hasClass('fade')) {
26759 //this.el.setXY([0,0]);
26760 this.el.removeClass('in');
26776 * @class Roo.bootstrap.LocationPicker
26777 * @extends Roo.bootstrap.Component
26778 * Bootstrap LocationPicker class
26779 * @cfg {Number} latitude Position when init default 0
26780 * @cfg {Number} longitude Position when init default 0
26781 * @cfg {Number} zoom default 15
26782 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26783 * @cfg {Boolean} mapTypeControl default false
26784 * @cfg {Boolean} disableDoubleClickZoom default false
26785 * @cfg {Boolean} scrollwheel default true
26786 * @cfg {Boolean} streetViewControl default false
26787 * @cfg {Number} radius default 0
26788 * @cfg {String} locationName
26789 * @cfg {Boolean} draggable default true
26790 * @cfg {Boolean} enableAutocomplete default false
26791 * @cfg {Boolean} enableReverseGeocode default true
26792 * @cfg {String} markerTitle
26795 * Create a new LocationPicker
26796 * @param {Object} config The config object
26800 Roo.bootstrap.LocationPicker = function(config){
26802 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26807 * Fires when the picker initialized.
26808 * @param {Roo.bootstrap.LocationPicker} this
26809 * @param {Google Location} location
26813 * @event positionchanged
26814 * Fires when the picker position changed.
26815 * @param {Roo.bootstrap.LocationPicker} this
26816 * @param {Google Location} location
26818 positionchanged : true,
26821 * Fires when the map resize.
26822 * @param {Roo.bootstrap.LocationPicker} this
26827 * Fires when the map show.
26828 * @param {Roo.bootstrap.LocationPicker} this
26833 * Fires when the map hide.
26834 * @param {Roo.bootstrap.LocationPicker} this
26839 * Fires when click the map.
26840 * @param {Roo.bootstrap.LocationPicker} this
26841 * @param {Map event} e
26845 * @event mapRightClick
26846 * Fires when right click the map.
26847 * @param {Roo.bootstrap.LocationPicker} this
26848 * @param {Map event} e
26850 mapRightClick : true,
26852 * @event markerClick
26853 * Fires when click the marker.
26854 * @param {Roo.bootstrap.LocationPicker} this
26855 * @param {Map event} e
26857 markerClick : true,
26859 * @event markerRightClick
26860 * Fires when right click the marker.
26861 * @param {Roo.bootstrap.LocationPicker} this
26862 * @param {Map event} e
26864 markerRightClick : true,
26866 * @event OverlayViewDraw
26867 * Fires when OverlayView Draw
26868 * @param {Roo.bootstrap.LocationPicker} this
26870 OverlayViewDraw : true,
26872 * @event OverlayViewOnAdd
26873 * Fires when OverlayView Draw
26874 * @param {Roo.bootstrap.LocationPicker} this
26876 OverlayViewOnAdd : true,
26878 * @event OverlayViewOnRemove
26879 * Fires when OverlayView Draw
26880 * @param {Roo.bootstrap.LocationPicker} this
26882 OverlayViewOnRemove : true,
26884 * @event OverlayViewShow
26885 * Fires when OverlayView Draw
26886 * @param {Roo.bootstrap.LocationPicker} this
26887 * @param {Pixel} cpx
26889 OverlayViewShow : true,
26891 * @event OverlayViewHide
26892 * Fires when OverlayView Draw
26893 * @param {Roo.bootstrap.LocationPicker} this
26895 OverlayViewHide : true,
26897 * @event loadexception
26898 * Fires when load google lib failed.
26899 * @param {Roo.bootstrap.LocationPicker} this
26901 loadexception : true
26906 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26908 gMapContext: false,
26914 mapTypeControl: false,
26915 disableDoubleClickZoom: false,
26917 streetViewControl: false,
26921 enableAutocomplete: false,
26922 enableReverseGeocode: true,
26925 getAutoCreate: function()
26930 cls: 'roo-location-picker'
26936 initEvents: function(ct, position)
26938 if(!this.el.getWidth() || this.isApplied()){
26942 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26947 initial: function()
26949 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26950 this.fireEvent('loadexception', this);
26954 if(!this.mapTypeId){
26955 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26958 this.gMapContext = this.GMapContext();
26960 this.initOverlayView();
26962 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26966 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26967 _this.setPosition(_this.gMapContext.marker.position);
26970 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26971 _this.fireEvent('mapClick', this, event);
26975 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26976 _this.fireEvent('mapRightClick', this, event);
26980 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26981 _this.fireEvent('markerClick', this, event);
26985 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26986 _this.fireEvent('markerRightClick', this, event);
26990 this.setPosition(this.gMapContext.location);
26992 this.fireEvent('initial', this, this.gMapContext.location);
26995 initOverlayView: function()
26999 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27003 _this.fireEvent('OverlayViewDraw', _this);
27008 _this.fireEvent('OverlayViewOnAdd', _this);
27011 onRemove: function()
27013 _this.fireEvent('OverlayViewOnRemove', _this);
27016 show: function(cpx)
27018 _this.fireEvent('OverlayViewShow', _this, cpx);
27023 _this.fireEvent('OverlayViewHide', _this);
27029 fromLatLngToContainerPixel: function(event)
27031 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27034 isApplied: function()
27036 return this.getGmapContext() == false ? false : true;
27039 getGmapContext: function()
27041 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27044 GMapContext: function()
27046 var position = new google.maps.LatLng(this.latitude, this.longitude);
27048 var _map = new google.maps.Map(this.el.dom, {
27051 mapTypeId: this.mapTypeId,
27052 mapTypeControl: this.mapTypeControl,
27053 disableDoubleClickZoom: this.disableDoubleClickZoom,
27054 scrollwheel: this.scrollwheel,
27055 streetViewControl: this.streetViewControl,
27056 locationName: this.locationName,
27057 draggable: this.draggable,
27058 enableAutocomplete: this.enableAutocomplete,
27059 enableReverseGeocode: this.enableReverseGeocode
27062 var _marker = new google.maps.Marker({
27063 position: position,
27065 title: this.markerTitle,
27066 draggable: this.draggable
27073 location: position,
27074 radius: this.radius,
27075 locationName: this.locationName,
27076 addressComponents: {
27077 formatted_address: null,
27078 addressLine1: null,
27079 addressLine2: null,
27081 streetNumber: null,
27085 stateOrProvince: null
27088 domContainer: this.el.dom,
27089 geodecoder: new google.maps.Geocoder()
27093 drawCircle: function(center, radius, options)
27095 if (this.gMapContext.circle != null) {
27096 this.gMapContext.circle.setMap(null);
27100 options = Roo.apply({}, options, {
27101 strokeColor: "#0000FF",
27102 strokeOpacity: .35,
27104 fillColor: "#0000FF",
27108 options.map = this.gMapContext.map;
27109 options.radius = radius;
27110 options.center = center;
27111 this.gMapContext.circle = new google.maps.Circle(options);
27112 return this.gMapContext.circle;
27118 setPosition: function(location)
27120 this.gMapContext.location = location;
27121 this.gMapContext.marker.setPosition(location);
27122 this.gMapContext.map.panTo(location);
27123 this.drawCircle(location, this.gMapContext.radius, {});
27127 if (this.gMapContext.settings.enableReverseGeocode) {
27128 this.gMapContext.geodecoder.geocode({
27129 latLng: this.gMapContext.location
27130 }, function(results, status) {
27132 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27133 _this.gMapContext.locationName = results[0].formatted_address;
27134 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27136 _this.fireEvent('positionchanged', this, location);
27143 this.fireEvent('positionchanged', this, location);
27148 google.maps.event.trigger(this.gMapContext.map, "resize");
27150 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27152 this.fireEvent('resize', this);
27155 setPositionByLatLng: function(latitude, longitude)
27157 this.setPosition(new google.maps.LatLng(latitude, longitude));
27160 getCurrentPosition: function()
27163 latitude: this.gMapContext.location.lat(),
27164 longitude: this.gMapContext.location.lng()
27168 getAddressName: function()
27170 return this.gMapContext.locationName;
27173 getAddressComponents: function()
27175 return this.gMapContext.addressComponents;
27178 address_component_from_google_geocode: function(address_components)
27182 for (var i = 0; i < address_components.length; i++) {
27183 var component = address_components[i];
27184 if (component.types.indexOf("postal_code") >= 0) {
27185 result.postalCode = component.short_name;
27186 } else if (component.types.indexOf("street_number") >= 0) {
27187 result.streetNumber = component.short_name;
27188 } else if (component.types.indexOf("route") >= 0) {
27189 result.streetName = component.short_name;
27190 } else if (component.types.indexOf("neighborhood") >= 0) {
27191 result.city = component.short_name;
27192 } else if (component.types.indexOf("locality") >= 0) {
27193 result.city = component.short_name;
27194 } else if (component.types.indexOf("sublocality") >= 0) {
27195 result.district = component.short_name;
27196 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27197 result.stateOrProvince = component.short_name;
27198 } else if (component.types.indexOf("country") >= 0) {
27199 result.country = component.short_name;
27203 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27204 result.addressLine2 = "";
27208 setZoomLevel: function(zoom)
27210 this.gMapContext.map.setZoom(zoom);
27223 this.fireEvent('show', this);
27234 this.fireEvent('hide', this);
27239 Roo.apply(Roo.bootstrap.LocationPicker, {
27241 OverlayView : function(map, options)
27243 options = options || {};
27250 * @class Roo.bootstrap.Alert
27251 * @extends Roo.bootstrap.Component
27252 * Bootstrap Alert class - shows an alert area box
27254 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27255 Enter a valid email address
27258 * @cfg {String} title The title of alert
27259 * @cfg {String} html The content of alert
27260 * @cfg {String} weight ( success | info | warning | danger )
27261 * @cfg {String} faicon font-awesomeicon
27264 * Create a new alert
27265 * @param {Object} config The config object
27269 Roo.bootstrap.Alert = function(config){
27270 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27274 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27281 getAutoCreate : function()
27290 cls : 'roo-alert-icon'
27295 cls : 'roo-alert-title',
27300 cls : 'roo-alert-text',
27307 cfg.cn[0].cls += ' fa ' + this.faicon;
27311 cfg.cls += ' alert-' + this.weight;
27317 initEvents: function()
27319 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27322 setTitle : function(str)
27324 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27327 setText : function(str)
27329 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27332 setWeight : function(weight)
27335 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27338 this.weight = weight;
27340 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27343 setIcon : function(icon)
27346 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27349 this.faicon = icon;
27351 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27372 * @class Roo.bootstrap.UploadCropbox
27373 * @extends Roo.bootstrap.Component
27374 * Bootstrap UploadCropbox class
27375 * @cfg {String} emptyText show when image has been loaded
27376 * @cfg {String} rotateNotify show when image too small to rotate
27377 * @cfg {Number} errorTimeout default 3000
27378 * @cfg {Number} minWidth default 300
27379 * @cfg {Number} minHeight default 300
27380 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27381 * @cfg {Boolean} isDocument (true|false) default false
27382 * @cfg {String} url action url
27383 * @cfg {String} paramName default 'imageUpload'
27384 * @cfg {String} method default POST
27385 * @cfg {Boolean} loadMask (true|false) default true
27386 * @cfg {Boolean} loadingText default 'Loading...'
27389 * Create a new UploadCropbox
27390 * @param {Object} config The config object
27393 Roo.bootstrap.UploadCropbox = function(config){
27394 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27398 * @event beforeselectfile
27399 * Fire before select file
27400 * @param {Roo.bootstrap.UploadCropbox} this
27402 "beforeselectfile" : true,
27405 * Fire after initEvent
27406 * @param {Roo.bootstrap.UploadCropbox} this
27411 * Fire after initEvent
27412 * @param {Roo.bootstrap.UploadCropbox} this
27413 * @param {String} data
27418 * Fire when preparing the file data
27419 * @param {Roo.bootstrap.UploadCropbox} this
27420 * @param {Object} file
27425 * Fire when get exception
27426 * @param {Roo.bootstrap.UploadCropbox} this
27427 * @param {XMLHttpRequest} xhr
27429 "exception" : true,
27431 * @event beforeloadcanvas
27432 * Fire before load the canvas
27433 * @param {Roo.bootstrap.UploadCropbox} this
27434 * @param {String} src
27436 "beforeloadcanvas" : true,
27439 * Fire when trash image
27440 * @param {Roo.bootstrap.UploadCropbox} this
27445 * Fire when download the image
27446 * @param {Roo.bootstrap.UploadCropbox} this
27450 * @event footerbuttonclick
27451 * Fire when footerbuttonclick
27452 * @param {Roo.bootstrap.UploadCropbox} this
27453 * @param {String} type
27455 "footerbuttonclick" : true,
27459 * @param {Roo.bootstrap.UploadCropbox} this
27464 * Fire when rotate the image
27465 * @param {Roo.bootstrap.UploadCropbox} this
27466 * @param {String} pos
27471 * Fire when inspect the file
27472 * @param {Roo.bootstrap.UploadCropbox} this
27473 * @param {Object} file
27478 * Fire when xhr upload the file
27479 * @param {Roo.bootstrap.UploadCropbox} this
27480 * @param {Object} data
27485 * Fire when arrange the file data
27486 * @param {Roo.bootstrap.UploadCropbox} this
27487 * @param {Object} formData
27492 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27495 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27497 emptyText : 'Click to upload image',
27498 rotateNotify : 'Image is too small to rotate',
27499 errorTimeout : 3000,
27513 cropType : 'image/jpeg',
27515 canvasLoaded : false,
27516 isDocument : false,
27518 paramName : 'imageUpload',
27520 loadingText : 'Loading...',
27523 getAutoCreate : function()
27527 cls : 'roo-upload-cropbox',
27531 cls : 'roo-upload-cropbox-selector',
27536 cls : 'roo-upload-cropbox-body',
27537 style : 'cursor:pointer',
27541 cls : 'roo-upload-cropbox-preview'
27545 cls : 'roo-upload-cropbox-thumb'
27549 cls : 'roo-upload-cropbox-empty-notify',
27550 html : this.emptyText
27554 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27555 html : this.rotateNotify
27561 cls : 'roo-upload-cropbox-footer',
27564 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27574 onRender : function(ct, position)
27576 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27578 if (this.buttons.length) {
27580 Roo.each(this.buttons, function(bb) {
27582 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27584 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27590 this.maskEl = this.el;
27594 initEvents : function()
27596 this.urlAPI = (window.createObjectURL && window) ||
27597 (window.URL && URL.revokeObjectURL && URL) ||
27598 (window.webkitURL && webkitURL);
27600 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27601 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27603 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27604 this.selectorEl.hide();
27606 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27607 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27609 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27610 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27611 this.thumbEl.hide();
27613 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27614 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27616 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27617 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27618 this.errorEl.hide();
27620 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27621 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27622 this.footerEl.hide();
27624 this.setThumbBoxSize();
27630 this.fireEvent('initial', this);
27637 window.addEventListener("resize", function() { _this.resize(); } );
27639 this.bodyEl.on('click', this.beforeSelectFile, this);
27642 this.bodyEl.on('touchstart', this.onTouchStart, this);
27643 this.bodyEl.on('touchmove', this.onTouchMove, this);
27644 this.bodyEl.on('touchend', this.onTouchEnd, this);
27648 this.bodyEl.on('mousedown', this.onMouseDown, this);
27649 this.bodyEl.on('mousemove', this.onMouseMove, this);
27650 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27651 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27652 Roo.get(document).on('mouseup', this.onMouseUp, this);
27655 this.selectorEl.on('change', this.onFileSelected, this);
27661 this.baseScale = 1;
27663 this.baseRotate = 1;
27664 this.dragable = false;
27665 this.pinching = false;
27668 this.cropData = false;
27669 this.notifyEl.dom.innerHTML = this.emptyText;
27671 this.selectorEl.dom.value = '';
27675 resize : function()
27677 if(this.fireEvent('resize', this) != false){
27678 this.setThumbBoxPosition();
27679 this.setCanvasPosition();
27683 onFooterButtonClick : function(e, el, o, type)
27686 case 'rotate-left' :
27687 this.onRotateLeft(e);
27689 case 'rotate-right' :
27690 this.onRotateRight(e);
27693 this.beforeSelectFile(e);
27708 this.fireEvent('footerbuttonclick', this, type);
27711 beforeSelectFile : function(e)
27713 e.preventDefault();
27715 if(this.fireEvent('beforeselectfile', this) != false){
27716 this.selectorEl.dom.click();
27720 onFileSelected : function(e)
27722 e.preventDefault();
27724 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27728 var file = this.selectorEl.dom.files[0];
27730 if(this.fireEvent('inspect', this, file) != false){
27731 this.prepare(file);
27736 trash : function(e)
27738 this.fireEvent('trash', this);
27741 download : function(e)
27743 this.fireEvent('download', this);
27746 loadCanvas : function(src)
27748 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27752 this.imageEl = document.createElement('img');
27756 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27758 this.imageEl.src = src;
27762 onLoadCanvas : function()
27764 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27765 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27767 this.bodyEl.un('click', this.beforeSelectFile, this);
27769 this.notifyEl.hide();
27770 this.thumbEl.show();
27771 this.footerEl.show();
27773 this.baseRotateLevel();
27775 if(this.isDocument){
27776 this.setThumbBoxSize();
27779 this.setThumbBoxPosition();
27781 this.baseScaleLevel();
27787 this.canvasLoaded = true;
27790 this.maskEl.unmask();
27795 setCanvasPosition : function()
27797 if(!this.canvasEl){
27801 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27802 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27804 this.previewEl.setLeft(pw);
27805 this.previewEl.setTop(ph);
27809 onMouseDown : function(e)
27813 this.dragable = true;
27814 this.pinching = false;
27816 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27817 this.dragable = false;
27821 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27822 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27826 onMouseMove : function(e)
27830 if(!this.canvasLoaded){
27834 if (!this.dragable){
27838 var minX = Math.ceil(this.thumbEl.getLeft(true));
27839 var minY = Math.ceil(this.thumbEl.getTop(true));
27841 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27842 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27844 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27845 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27847 x = x - this.mouseX;
27848 y = y - this.mouseY;
27850 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27851 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27853 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27854 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27856 this.previewEl.setLeft(bgX);
27857 this.previewEl.setTop(bgY);
27859 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27860 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27863 onMouseUp : function(e)
27867 this.dragable = false;
27870 onMouseWheel : function(e)
27874 this.startScale = this.scale;
27876 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27878 if(!this.zoomable()){
27879 this.scale = this.startScale;
27888 zoomable : function()
27890 var minScale = this.thumbEl.getWidth() / this.minWidth;
27892 if(this.minWidth < this.minHeight){
27893 minScale = this.thumbEl.getHeight() / this.minHeight;
27896 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27897 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27901 (this.rotate == 0 || this.rotate == 180) &&
27903 width > this.imageEl.OriginWidth ||
27904 height > this.imageEl.OriginHeight ||
27905 (width < this.minWidth && height < this.minHeight)
27913 (this.rotate == 90 || this.rotate == 270) &&
27915 width > this.imageEl.OriginWidth ||
27916 height > this.imageEl.OriginHeight ||
27917 (width < this.minHeight && height < this.minWidth)
27924 !this.isDocument &&
27925 (this.rotate == 0 || this.rotate == 180) &&
27927 width < this.minWidth ||
27928 width > this.imageEl.OriginWidth ||
27929 height < this.minHeight ||
27930 height > this.imageEl.OriginHeight
27937 !this.isDocument &&
27938 (this.rotate == 90 || this.rotate == 270) &&
27940 width < this.minHeight ||
27941 width > this.imageEl.OriginWidth ||
27942 height < this.minWidth ||
27943 height > this.imageEl.OriginHeight
27953 onRotateLeft : function(e)
27955 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27957 var minScale = this.thumbEl.getWidth() / this.minWidth;
27959 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27960 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27962 this.startScale = this.scale;
27964 while (this.getScaleLevel() < minScale){
27966 this.scale = this.scale + 1;
27968 if(!this.zoomable()){
27973 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27974 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27979 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27986 this.scale = this.startScale;
27988 this.onRotateFail();
27993 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27995 if(this.isDocument){
27996 this.setThumbBoxSize();
27997 this.setThumbBoxPosition();
27998 this.setCanvasPosition();
28003 this.fireEvent('rotate', this, 'left');
28007 onRotateRight : function(e)
28009 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28011 var minScale = this.thumbEl.getWidth() / this.minWidth;
28013 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28014 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28016 this.startScale = this.scale;
28018 while (this.getScaleLevel() < minScale){
28020 this.scale = this.scale + 1;
28022 if(!this.zoomable()){
28027 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28028 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28033 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28040 this.scale = this.startScale;
28042 this.onRotateFail();
28047 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28049 if(this.isDocument){
28050 this.setThumbBoxSize();
28051 this.setThumbBoxPosition();
28052 this.setCanvasPosition();
28057 this.fireEvent('rotate', this, 'right');
28060 onRotateFail : function()
28062 this.errorEl.show(true);
28066 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28071 this.previewEl.dom.innerHTML = '';
28073 var canvasEl = document.createElement("canvas");
28075 var contextEl = canvasEl.getContext("2d");
28077 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28078 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28079 var center = this.imageEl.OriginWidth / 2;
28081 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28082 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28083 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28084 center = this.imageEl.OriginHeight / 2;
28087 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28089 contextEl.translate(center, center);
28090 contextEl.rotate(this.rotate * Math.PI / 180);
28092 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28094 this.canvasEl = document.createElement("canvas");
28096 this.contextEl = this.canvasEl.getContext("2d");
28098 switch (this.rotate) {
28101 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28102 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28104 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28109 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28110 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28112 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28113 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);
28117 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28122 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28123 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28125 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28126 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);
28130 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);
28135 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28136 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28138 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28139 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28143 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);
28150 this.previewEl.appendChild(this.canvasEl);
28152 this.setCanvasPosition();
28157 if(!this.canvasLoaded){
28161 var imageCanvas = document.createElement("canvas");
28163 var imageContext = imageCanvas.getContext("2d");
28165 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28166 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28168 var center = imageCanvas.width / 2;
28170 imageContext.translate(center, center);
28172 imageContext.rotate(this.rotate * Math.PI / 180);
28174 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28176 var canvas = document.createElement("canvas");
28178 var context = canvas.getContext("2d");
28180 canvas.width = this.minWidth;
28181 canvas.height = this.minHeight;
28183 switch (this.rotate) {
28186 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28187 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28189 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28190 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28192 var targetWidth = this.minWidth - 2 * x;
28193 var targetHeight = this.minHeight - 2 * y;
28197 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28198 scale = targetWidth / width;
28201 if(x > 0 && y == 0){
28202 scale = targetHeight / height;
28205 if(x > 0 && y > 0){
28206 scale = targetWidth / width;
28208 if(width < height){
28209 scale = targetHeight / height;
28213 context.scale(scale, scale);
28215 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28216 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28218 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28219 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28221 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28226 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28227 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28229 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28230 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28232 var targetWidth = this.minWidth - 2 * x;
28233 var targetHeight = this.minHeight - 2 * y;
28237 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28238 scale = targetWidth / width;
28241 if(x > 0 && y == 0){
28242 scale = targetHeight / height;
28245 if(x > 0 && y > 0){
28246 scale = targetWidth / width;
28248 if(width < height){
28249 scale = targetHeight / height;
28253 context.scale(scale, scale);
28255 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28256 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28258 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28259 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28261 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28263 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28268 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28269 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28271 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28272 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28274 var targetWidth = this.minWidth - 2 * x;
28275 var targetHeight = this.minHeight - 2 * y;
28279 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28280 scale = targetWidth / width;
28283 if(x > 0 && y == 0){
28284 scale = targetHeight / height;
28287 if(x > 0 && y > 0){
28288 scale = targetWidth / width;
28290 if(width < height){
28291 scale = targetHeight / height;
28295 context.scale(scale, scale);
28297 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28298 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28300 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28301 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28303 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28304 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28306 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28311 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28312 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28314 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28315 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28317 var targetWidth = this.minWidth - 2 * x;
28318 var targetHeight = this.minHeight - 2 * y;
28322 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28323 scale = targetWidth / width;
28326 if(x > 0 && y == 0){
28327 scale = targetHeight / height;
28330 if(x > 0 && y > 0){
28331 scale = targetWidth / width;
28333 if(width < height){
28334 scale = targetHeight / height;
28338 context.scale(scale, scale);
28340 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28341 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28343 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28344 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28346 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28348 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28355 this.cropData = canvas.toDataURL(this.cropType);
28357 if(this.fireEvent('crop', this, this.cropData) !== false){
28358 this.process(this.file, this.cropData);
28365 setThumbBoxSize : function()
28369 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28370 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28371 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28373 this.minWidth = width;
28374 this.minHeight = height;
28376 if(this.rotate == 90 || this.rotate == 270){
28377 this.minWidth = height;
28378 this.minHeight = width;
28383 width = Math.ceil(this.minWidth * height / this.minHeight);
28385 if(this.minWidth > this.minHeight){
28387 height = Math.ceil(this.minHeight * width / this.minWidth);
28390 this.thumbEl.setStyle({
28391 width : width + 'px',
28392 height : height + 'px'
28399 setThumbBoxPosition : function()
28401 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28402 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28404 this.thumbEl.setLeft(x);
28405 this.thumbEl.setTop(y);
28409 baseRotateLevel : function()
28411 this.baseRotate = 1;
28414 typeof(this.exif) != 'undefined' &&
28415 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28416 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28418 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28421 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28425 baseScaleLevel : function()
28429 if(this.isDocument){
28431 if(this.baseRotate == 6 || this.baseRotate == 8){
28433 height = this.thumbEl.getHeight();
28434 this.baseScale = height / this.imageEl.OriginWidth;
28436 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28437 width = this.thumbEl.getWidth();
28438 this.baseScale = width / this.imageEl.OriginHeight;
28444 height = this.thumbEl.getHeight();
28445 this.baseScale = height / this.imageEl.OriginHeight;
28447 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28448 width = this.thumbEl.getWidth();
28449 this.baseScale = width / this.imageEl.OriginWidth;
28455 if(this.baseRotate == 6 || this.baseRotate == 8){
28457 width = this.thumbEl.getHeight();
28458 this.baseScale = width / this.imageEl.OriginHeight;
28460 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28461 height = this.thumbEl.getWidth();
28462 this.baseScale = height / this.imageEl.OriginHeight;
28465 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28466 height = this.thumbEl.getWidth();
28467 this.baseScale = height / this.imageEl.OriginHeight;
28469 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28470 width = this.thumbEl.getHeight();
28471 this.baseScale = width / this.imageEl.OriginWidth;
28478 width = this.thumbEl.getWidth();
28479 this.baseScale = width / this.imageEl.OriginWidth;
28481 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28482 height = this.thumbEl.getHeight();
28483 this.baseScale = height / this.imageEl.OriginHeight;
28486 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28488 height = this.thumbEl.getHeight();
28489 this.baseScale = height / this.imageEl.OriginHeight;
28491 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28492 width = this.thumbEl.getWidth();
28493 this.baseScale = width / this.imageEl.OriginWidth;
28501 getScaleLevel : function()
28503 return this.baseScale * Math.pow(1.1, this.scale);
28506 onTouchStart : function(e)
28508 if(!this.canvasLoaded){
28509 this.beforeSelectFile(e);
28513 var touches = e.browserEvent.touches;
28519 if(touches.length == 1){
28520 this.onMouseDown(e);
28524 if(touches.length != 2){
28530 for(var i = 0, finger; finger = touches[i]; i++){
28531 coords.push(finger.pageX, finger.pageY);
28534 var x = Math.pow(coords[0] - coords[2], 2);
28535 var y = Math.pow(coords[1] - coords[3], 2);
28537 this.startDistance = Math.sqrt(x + y);
28539 this.startScale = this.scale;
28541 this.pinching = true;
28542 this.dragable = false;
28546 onTouchMove : function(e)
28548 if(!this.pinching && !this.dragable){
28552 var touches = e.browserEvent.touches;
28559 this.onMouseMove(e);
28565 for(var i = 0, finger; finger = touches[i]; i++){
28566 coords.push(finger.pageX, finger.pageY);
28569 var x = Math.pow(coords[0] - coords[2], 2);
28570 var y = Math.pow(coords[1] - coords[3], 2);
28572 this.endDistance = Math.sqrt(x + y);
28574 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28576 if(!this.zoomable()){
28577 this.scale = this.startScale;
28585 onTouchEnd : function(e)
28587 this.pinching = false;
28588 this.dragable = false;
28592 process : function(file, crop)
28595 this.maskEl.mask(this.loadingText);
28598 this.xhr = new XMLHttpRequest();
28600 file.xhr = this.xhr;
28602 this.xhr.open(this.method, this.url, true);
28605 "Accept": "application/json",
28606 "Cache-Control": "no-cache",
28607 "X-Requested-With": "XMLHttpRequest"
28610 for (var headerName in headers) {
28611 var headerValue = headers[headerName];
28613 this.xhr.setRequestHeader(headerName, headerValue);
28619 this.xhr.onload = function()
28621 _this.xhrOnLoad(_this.xhr);
28624 this.xhr.onerror = function()
28626 _this.xhrOnError(_this.xhr);
28629 var formData = new FormData();
28631 formData.append('returnHTML', 'NO');
28634 formData.append('crop', crop);
28637 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28638 formData.append(this.paramName, file, file.name);
28641 if(typeof(file.filename) != 'undefined'){
28642 formData.append('filename', file.filename);
28645 if(typeof(file.mimetype) != 'undefined'){
28646 formData.append('mimetype', file.mimetype);
28649 if(this.fireEvent('arrange', this, formData) != false){
28650 this.xhr.send(formData);
28654 xhrOnLoad : function(xhr)
28657 this.maskEl.unmask();
28660 if (xhr.readyState !== 4) {
28661 this.fireEvent('exception', this, xhr);
28665 var response = Roo.decode(xhr.responseText);
28667 if(!response.success){
28668 this.fireEvent('exception', this, xhr);
28672 var response = Roo.decode(xhr.responseText);
28674 this.fireEvent('upload', this, response);
28678 xhrOnError : function()
28681 this.maskEl.unmask();
28684 Roo.log('xhr on error');
28686 var response = Roo.decode(xhr.responseText);
28692 prepare : function(file)
28695 this.maskEl.mask(this.loadingText);
28701 if(typeof(file) === 'string'){
28702 this.loadCanvas(file);
28706 if(!file || !this.urlAPI){
28711 this.cropType = file.type;
28715 if(this.fireEvent('prepare', this, this.file) != false){
28717 var reader = new FileReader();
28719 reader.onload = function (e) {
28720 if (e.target.error) {
28721 Roo.log(e.target.error);
28725 var buffer = e.target.result,
28726 dataView = new DataView(buffer),
28728 maxOffset = dataView.byteLength - 4,
28732 if (dataView.getUint16(0) === 0xffd8) {
28733 while (offset < maxOffset) {
28734 markerBytes = dataView.getUint16(offset);
28736 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28737 markerLength = dataView.getUint16(offset + 2) + 2;
28738 if (offset + markerLength > dataView.byteLength) {
28739 Roo.log('Invalid meta data: Invalid segment size.');
28743 if(markerBytes == 0xffe1){
28744 _this.parseExifData(
28751 offset += markerLength;
28761 var url = _this.urlAPI.createObjectURL(_this.file);
28763 _this.loadCanvas(url);
28768 reader.readAsArrayBuffer(this.file);
28774 parseExifData : function(dataView, offset, length)
28776 var tiffOffset = offset + 10,
28780 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28781 // No Exif data, might be XMP data instead
28785 // Check for the ASCII code for "Exif" (0x45786966):
28786 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28787 // No Exif data, might be XMP data instead
28790 if (tiffOffset + 8 > dataView.byteLength) {
28791 Roo.log('Invalid Exif data: Invalid segment size.');
28794 // Check for the two null bytes:
28795 if (dataView.getUint16(offset + 8) !== 0x0000) {
28796 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28799 // Check the byte alignment:
28800 switch (dataView.getUint16(tiffOffset)) {
28802 littleEndian = true;
28805 littleEndian = false;
28808 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28811 // Check for the TIFF tag marker (0x002A):
28812 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28813 Roo.log('Invalid Exif data: Missing TIFF marker.');
28816 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28817 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28819 this.parseExifTags(
28822 tiffOffset + dirOffset,
28827 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28832 if (dirOffset + 6 > dataView.byteLength) {
28833 Roo.log('Invalid Exif data: Invalid directory offset.');
28836 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28837 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28838 if (dirEndOffset + 4 > dataView.byteLength) {
28839 Roo.log('Invalid Exif data: Invalid directory size.');
28842 for (i = 0; i < tagsNumber; i += 1) {
28846 dirOffset + 2 + 12 * i, // tag offset
28850 // Return the offset to the next directory:
28851 return dataView.getUint32(dirEndOffset, littleEndian);
28854 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28856 var tag = dataView.getUint16(offset, littleEndian);
28858 this.exif[tag] = this.getExifValue(
28862 dataView.getUint16(offset + 2, littleEndian), // tag type
28863 dataView.getUint32(offset + 4, littleEndian), // tag length
28868 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28870 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28879 Roo.log('Invalid Exif data: Invalid tag type.');
28883 tagSize = tagType.size * length;
28884 // Determine if the value is contained in the dataOffset bytes,
28885 // or if the value at the dataOffset is a pointer to the actual data:
28886 dataOffset = tagSize > 4 ?
28887 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28888 if (dataOffset + tagSize > dataView.byteLength) {
28889 Roo.log('Invalid Exif data: Invalid data offset.');
28892 if (length === 1) {
28893 return tagType.getValue(dataView, dataOffset, littleEndian);
28896 for (i = 0; i < length; i += 1) {
28897 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28900 if (tagType.ascii) {
28902 // Concatenate the chars:
28903 for (i = 0; i < values.length; i += 1) {
28905 // Ignore the terminating NULL byte(s):
28906 if (c === '\u0000') {
28918 Roo.apply(Roo.bootstrap.UploadCropbox, {
28920 'Orientation': 0x0112
28924 1: 0, //'top-left',
28926 3: 180, //'bottom-right',
28927 // 4: 'bottom-left',
28929 6: 90, //'right-top',
28930 // 7: 'right-bottom',
28931 8: 270 //'left-bottom'
28935 // byte, 8-bit unsigned int:
28937 getValue: function (dataView, dataOffset) {
28938 return dataView.getUint8(dataOffset);
28942 // ascii, 8-bit byte:
28944 getValue: function (dataView, dataOffset) {
28945 return String.fromCharCode(dataView.getUint8(dataOffset));
28950 // short, 16 bit int:
28952 getValue: function (dataView, dataOffset, littleEndian) {
28953 return dataView.getUint16(dataOffset, littleEndian);
28957 // long, 32 bit int:
28959 getValue: function (dataView, dataOffset, littleEndian) {
28960 return dataView.getUint32(dataOffset, littleEndian);
28964 // rational = two long values, first is numerator, second is denominator:
28966 getValue: function (dataView, dataOffset, littleEndian) {
28967 return dataView.getUint32(dataOffset, littleEndian) /
28968 dataView.getUint32(dataOffset + 4, littleEndian);
28972 // slong, 32 bit signed int:
28974 getValue: function (dataView, dataOffset, littleEndian) {
28975 return dataView.getInt32(dataOffset, littleEndian);
28979 // srational, two slongs, first is numerator, second is denominator:
28981 getValue: function (dataView, dataOffset, littleEndian) {
28982 return dataView.getInt32(dataOffset, littleEndian) /
28983 dataView.getInt32(dataOffset + 4, littleEndian);
28993 cls : 'btn-group roo-upload-cropbox-rotate-left',
28994 action : 'rotate-left',
28998 cls : 'btn btn-default',
28999 html : '<i class="fa fa-undo"></i>'
29005 cls : 'btn-group roo-upload-cropbox-picture',
29006 action : 'picture',
29010 cls : 'btn btn-default',
29011 html : '<i class="fa fa-picture-o"></i>'
29017 cls : 'btn-group roo-upload-cropbox-rotate-right',
29018 action : 'rotate-right',
29022 cls : 'btn btn-default',
29023 html : '<i class="fa fa-repeat"></i>'
29031 cls : 'btn-group roo-upload-cropbox-rotate-left',
29032 action : 'rotate-left',
29036 cls : 'btn btn-default',
29037 html : '<i class="fa fa-undo"></i>'
29043 cls : 'btn-group roo-upload-cropbox-download',
29044 action : 'download',
29048 cls : 'btn btn-default',
29049 html : '<i class="fa fa-download"></i>'
29055 cls : 'btn-group roo-upload-cropbox-crop',
29060 cls : 'btn btn-default',
29061 html : '<i class="fa fa-crop"></i>'
29067 cls : 'btn-group roo-upload-cropbox-trash',
29072 cls : 'btn btn-default',
29073 html : '<i class="fa fa-trash"></i>'
29079 cls : 'btn-group roo-upload-cropbox-rotate-right',
29080 action : 'rotate-right',
29084 cls : 'btn btn-default',
29085 html : '<i class="fa fa-repeat"></i>'
29093 cls : 'btn-group roo-upload-cropbox-rotate-left',
29094 action : 'rotate-left',
29098 cls : 'btn btn-default',
29099 html : '<i class="fa fa-undo"></i>'
29105 cls : 'btn-group roo-upload-cropbox-rotate-right',
29106 action : 'rotate-right',
29110 cls : 'btn btn-default',
29111 html : '<i class="fa fa-repeat"></i>'
29124 * @class Roo.bootstrap.DocumentManager
29125 * @extends Roo.bootstrap.Component
29126 * Bootstrap DocumentManager class
29127 * @cfg {String} paramName default 'imageUpload'
29128 * @cfg {String} toolTipName default 'filename'
29129 * @cfg {String} method default POST
29130 * @cfg {String} url action url
29131 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29132 * @cfg {Boolean} multiple multiple upload default true
29133 * @cfg {Number} thumbSize default 300
29134 * @cfg {String} fieldLabel
29135 * @cfg {Number} labelWidth default 4
29136 * @cfg {String} labelAlign (left|top) default left
29137 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29138 * @cfg {Number} labellg set the width of label (1-12)
29139 * @cfg {Number} labelmd set the width of label (1-12)
29140 * @cfg {Number} labelsm set the width of label (1-12)
29141 * @cfg {Number} labelxs set the width of label (1-12)
29144 * Create a new DocumentManager
29145 * @param {Object} config The config object
29148 Roo.bootstrap.DocumentManager = function(config){
29149 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29152 this.delegates = [];
29157 * Fire when initial the DocumentManager
29158 * @param {Roo.bootstrap.DocumentManager} this
29163 * inspect selected file
29164 * @param {Roo.bootstrap.DocumentManager} this
29165 * @param {File} file
29170 * Fire when xhr load exception
29171 * @param {Roo.bootstrap.DocumentManager} this
29172 * @param {XMLHttpRequest} xhr
29174 "exception" : true,
29176 * @event afterupload
29177 * Fire when xhr load exception
29178 * @param {Roo.bootstrap.DocumentManager} this
29179 * @param {XMLHttpRequest} xhr
29181 "afterupload" : true,
29184 * prepare the form data
29185 * @param {Roo.bootstrap.DocumentManager} this
29186 * @param {Object} formData
29191 * Fire when remove the file
29192 * @param {Roo.bootstrap.DocumentManager} this
29193 * @param {Object} file
29198 * Fire after refresh the file
29199 * @param {Roo.bootstrap.DocumentManager} this
29204 * Fire after click the image
29205 * @param {Roo.bootstrap.DocumentManager} this
29206 * @param {Object} file
29211 * Fire when upload a image and editable set to true
29212 * @param {Roo.bootstrap.DocumentManager} this
29213 * @param {Object} file
29217 * @event beforeselectfile
29218 * Fire before select file
29219 * @param {Roo.bootstrap.DocumentManager} this
29221 "beforeselectfile" : true,
29224 * Fire before process file
29225 * @param {Roo.bootstrap.DocumentManager} this
29226 * @param {Object} file
29230 * @event previewrendered
29231 * Fire when preview rendered
29232 * @param {Roo.bootstrap.DocumentManager} this
29233 * @param {Object} file
29235 "previewrendered" : true,
29238 "previewResize" : true
29243 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29252 paramName : 'imageUpload',
29253 toolTipName : 'filename',
29256 labelAlign : 'left',
29266 getAutoCreate : function()
29268 var managerWidget = {
29270 cls : 'roo-document-manager',
29274 cls : 'roo-document-manager-selector',
29279 cls : 'roo-document-manager-uploader',
29283 cls : 'roo-document-manager-upload-btn',
29284 html : '<i class="fa fa-plus"></i>'
29295 cls : 'column col-md-12',
29300 if(this.fieldLabel.length){
29305 cls : 'column col-md-12',
29306 html : this.fieldLabel
29310 cls : 'column col-md-12',
29315 if(this.labelAlign == 'left'){
29320 html : this.fieldLabel
29329 if(this.labelWidth > 12){
29330 content[0].style = "width: " + this.labelWidth + 'px';
29333 if(this.labelWidth < 13 && this.labelmd == 0){
29334 this.labelmd = this.labelWidth;
29337 if(this.labellg > 0){
29338 content[0].cls += ' col-lg-' + this.labellg;
29339 content[1].cls += ' col-lg-' + (12 - this.labellg);
29342 if(this.labelmd > 0){
29343 content[0].cls += ' col-md-' + this.labelmd;
29344 content[1].cls += ' col-md-' + (12 - this.labelmd);
29347 if(this.labelsm > 0){
29348 content[0].cls += ' col-sm-' + this.labelsm;
29349 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29352 if(this.labelxs > 0){
29353 content[0].cls += ' col-xs-' + this.labelxs;
29354 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29362 cls : 'row clearfix',
29370 initEvents : function()
29372 this.managerEl = this.el.select('.roo-document-manager', true).first();
29373 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29375 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29376 this.selectorEl.hide();
29379 this.selectorEl.attr('multiple', 'multiple');
29382 this.selectorEl.on('change', this.onFileSelected, this);
29384 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29385 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29387 this.uploader.on('click', this.onUploaderClick, this);
29389 this.renderProgressDialog();
29393 window.addEventListener("resize", function() { _this.refresh(); } );
29395 this.fireEvent('initial', this);
29398 renderProgressDialog : function()
29402 this.progressDialog = new Roo.bootstrap.Modal({
29403 cls : 'roo-document-manager-progress-dialog',
29404 allow_close : false,
29415 btnclick : function() {
29416 _this.uploadCancel();
29422 this.progressDialog.render(Roo.get(document.body));
29424 this.progress = new Roo.bootstrap.Progress({
29425 cls : 'roo-document-manager-progress',
29430 this.progress.render(this.progressDialog.getChildContainer());
29432 this.progressBar = new Roo.bootstrap.ProgressBar({
29433 cls : 'roo-document-manager-progress-bar',
29436 aria_valuemax : 12,
29440 this.progressBar.render(this.progress.getChildContainer());
29443 onUploaderClick : function(e)
29445 e.preventDefault();
29447 if(this.fireEvent('beforeselectfile', this) != false){
29448 this.selectorEl.dom.click();
29453 onFileSelected : function(e)
29455 e.preventDefault();
29457 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29461 Roo.each(this.selectorEl.dom.files, function(file){
29462 if(this.fireEvent('inspect', this, file) != false){
29463 this.files.push(file);
29473 this.selectorEl.dom.value = '';
29475 if(!this.files || !this.files.length){
29479 if(this.boxes > 0 && this.files.length > this.boxes){
29480 this.files = this.files.slice(0, this.boxes);
29483 this.uploader.show();
29485 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29486 this.uploader.hide();
29495 Roo.each(this.files, function(file){
29497 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29498 var f = this.renderPreview(file);
29503 if(file.type.indexOf('image') != -1){
29504 this.delegates.push(
29506 _this.process(file);
29507 }).createDelegate(this)
29515 _this.process(file);
29516 }).createDelegate(this)
29521 this.files = files;
29523 this.delegates = this.delegates.concat(docs);
29525 if(!this.delegates.length){
29530 this.progressBar.aria_valuemax = this.delegates.length;
29537 arrange : function()
29539 if(!this.delegates.length){
29540 this.progressDialog.hide();
29545 var delegate = this.delegates.shift();
29547 this.progressDialog.show();
29549 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29551 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29556 refresh : function()
29558 this.uploader.show();
29560 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29561 this.uploader.hide();
29564 Roo.isTouch ? this.closable(false) : this.closable(true);
29566 this.fireEvent('refresh', this);
29569 onRemove : function(e, el, o)
29571 e.preventDefault();
29573 this.fireEvent('remove', this, o);
29577 remove : function(o)
29581 Roo.each(this.files, function(file){
29582 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29591 this.files = files;
29598 Roo.each(this.files, function(file){
29603 file.target.remove();
29612 onClick : function(e, el, o)
29614 e.preventDefault();
29616 this.fireEvent('click', this, o);
29620 closable : function(closable)
29622 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29624 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29636 xhrOnLoad : function(xhr)
29638 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29642 if (xhr.readyState !== 4) {
29644 this.fireEvent('exception', this, xhr);
29648 var response = Roo.decode(xhr.responseText);
29650 if(!response.success){
29652 this.fireEvent('exception', this, xhr);
29656 var file = this.renderPreview(response.data);
29658 this.files.push(file);
29662 this.fireEvent('afterupload', this, xhr);
29666 xhrOnError : function(xhr)
29668 Roo.log('xhr on error');
29670 var response = Roo.decode(xhr.responseText);
29677 process : function(file)
29679 if(this.fireEvent('process', this, file) !== false){
29680 if(this.editable && file.type.indexOf('image') != -1){
29681 this.fireEvent('edit', this, file);
29685 this.uploadStart(file, false);
29692 uploadStart : function(file, crop)
29694 this.xhr = new XMLHttpRequest();
29696 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29701 file.xhr = this.xhr;
29703 this.managerEl.createChild({
29705 cls : 'roo-document-manager-loading',
29709 tooltip : file.name,
29710 cls : 'roo-document-manager-thumb',
29711 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29717 this.xhr.open(this.method, this.url, true);
29720 "Accept": "application/json",
29721 "Cache-Control": "no-cache",
29722 "X-Requested-With": "XMLHttpRequest"
29725 for (var headerName in headers) {
29726 var headerValue = headers[headerName];
29728 this.xhr.setRequestHeader(headerName, headerValue);
29734 this.xhr.onload = function()
29736 _this.xhrOnLoad(_this.xhr);
29739 this.xhr.onerror = function()
29741 _this.xhrOnError(_this.xhr);
29744 var formData = new FormData();
29746 formData.append('returnHTML', 'NO');
29749 formData.append('crop', crop);
29752 formData.append(this.paramName, file, file.name);
29759 if(this.fireEvent('prepare', this, formData, options) != false){
29761 if(options.manually){
29765 this.xhr.send(formData);
29769 this.uploadCancel();
29772 uploadCancel : function()
29778 this.delegates = [];
29780 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29787 renderPreview : function(file)
29789 if(typeof(file.target) != 'undefined' && file.target){
29793 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29795 var previewEl = this.managerEl.createChild({
29797 cls : 'roo-document-manager-preview',
29801 tooltip : file[this.toolTipName],
29802 cls : 'roo-document-manager-thumb',
29803 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29808 html : '<i class="fa fa-times-circle"></i>'
29813 var close = previewEl.select('button.close', true).first();
29815 close.on('click', this.onRemove, this, file);
29817 file.target = previewEl;
29819 var image = previewEl.select('img', true).first();
29823 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29825 image.on('click', this.onClick, this, file);
29827 this.fireEvent('previewrendered', this, file);
29833 onPreviewLoad : function(file, image)
29835 if(typeof(file.target) == 'undefined' || !file.target){
29839 var width = image.dom.naturalWidth || image.dom.width;
29840 var height = image.dom.naturalHeight || image.dom.height;
29842 if(!this.previewResize) {
29846 if(width > height){
29847 file.target.addClass('wide');
29851 file.target.addClass('tall');
29856 uploadFromSource : function(file, crop)
29858 this.xhr = new XMLHttpRequest();
29860 this.managerEl.createChild({
29862 cls : 'roo-document-manager-loading',
29866 tooltip : file.name,
29867 cls : 'roo-document-manager-thumb',
29868 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29874 this.xhr.open(this.method, this.url, true);
29877 "Accept": "application/json",
29878 "Cache-Control": "no-cache",
29879 "X-Requested-With": "XMLHttpRequest"
29882 for (var headerName in headers) {
29883 var headerValue = headers[headerName];
29885 this.xhr.setRequestHeader(headerName, headerValue);
29891 this.xhr.onload = function()
29893 _this.xhrOnLoad(_this.xhr);
29896 this.xhr.onerror = function()
29898 _this.xhrOnError(_this.xhr);
29901 var formData = new FormData();
29903 formData.append('returnHTML', 'NO');
29905 formData.append('crop', crop);
29907 if(typeof(file.filename) != 'undefined'){
29908 formData.append('filename', file.filename);
29911 if(typeof(file.mimetype) != 'undefined'){
29912 formData.append('mimetype', file.mimetype);
29917 if(this.fireEvent('prepare', this, formData) != false){
29918 this.xhr.send(formData);
29928 * @class Roo.bootstrap.DocumentViewer
29929 * @extends Roo.bootstrap.Component
29930 * Bootstrap DocumentViewer class
29931 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29932 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29935 * Create a new DocumentViewer
29936 * @param {Object} config The config object
29939 Roo.bootstrap.DocumentViewer = function(config){
29940 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29945 * Fire after initEvent
29946 * @param {Roo.bootstrap.DocumentViewer} this
29952 * @param {Roo.bootstrap.DocumentViewer} this
29957 * Fire after download button
29958 * @param {Roo.bootstrap.DocumentViewer} this
29963 * Fire after trash button
29964 * @param {Roo.bootstrap.DocumentViewer} this
29971 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29973 showDownload : true,
29977 getAutoCreate : function()
29981 cls : 'roo-document-viewer',
29985 cls : 'roo-document-viewer-body',
29989 cls : 'roo-document-viewer-thumb',
29993 cls : 'roo-document-viewer-image'
30001 cls : 'roo-document-viewer-footer',
30004 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30008 cls : 'btn-group roo-document-viewer-download',
30012 cls : 'btn btn-default',
30013 html : '<i class="fa fa-download"></i>'
30019 cls : 'btn-group roo-document-viewer-trash',
30023 cls : 'btn btn-default',
30024 html : '<i class="fa fa-trash"></i>'
30037 initEvents : function()
30039 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30040 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30042 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30043 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30045 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30046 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30048 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30049 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30051 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30052 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30054 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30055 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30057 this.bodyEl.on('click', this.onClick, this);
30058 this.downloadBtn.on('click', this.onDownload, this);
30059 this.trashBtn.on('click', this.onTrash, this);
30061 this.downloadBtn.hide();
30062 this.trashBtn.hide();
30064 if(this.showDownload){
30065 this.downloadBtn.show();
30068 if(this.showTrash){
30069 this.trashBtn.show();
30072 if(!this.showDownload && !this.showTrash) {
30073 this.footerEl.hide();
30078 initial : function()
30080 this.fireEvent('initial', this);
30084 onClick : function(e)
30086 e.preventDefault();
30088 this.fireEvent('click', this);
30091 onDownload : function(e)
30093 e.preventDefault();
30095 this.fireEvent('download', this);
30098 onTrash : function(e)
30100 e.preventDefault();
30102 this.fireEvent('trash', this);
30114 * @class Roo.bootstrap.NavProgressBar
30115 * @extends Roo.bootstrap.Component
30116 * Bootstrap NavProgressBar class
30119 * Create a new nav progress bar
30120 * @param {Object} config The config object
30123 Roo.bootstrap.NavProgressBar = function(config){
30124 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30126 this.bullets = this.bullets || [];
30128 // Roo.bootstrap.NavProgressBar.register(this);
30132 * Fires when the active item changes
30133 * @param {Roo.bootstrap.NavProgressBar} this
30134 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30135 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30142 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30147 getAutoCreate : function()
30149 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30153 cls : 'roo-navigation-bar-group',
30157 cls : 'roo-navigation-top-bar'
30161 cls : 'roo-navigation-bullets-bar',
30165 cls : 'roo-navigation-bar'
30172 cls : 'roo-navigation-bottom-bar'
30182 initEvents: function()
30187 onRender : function(ct, position)
30189 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30191 if(this.bullets.length){
30192 Roo.each(this.bullets, function(b){
30201 addItem : function(cfg)
30203 var item = new Roo.bootstrap.NavProgressItem(cfg);
30205 item.parentId = this.id;
30206 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30209 var top = new Roo.bootstrap.Element({
30211 cls : 'roo-navigation-bar-text'
30214 var bottom = new Roo.bootstrap.Element({
30216 cls : 'roo-navigation-bar-text'
30219 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30220 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30222 var topText = new Roo.bootstrap.Element({
30224 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30227 var bottomText = new Roo.bootstrap.Element({
30229 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30232 topText.onRender(top.el, null);
30233 bottomText.onRender(bottom.el, null);
30236 item.bottomEl = bottom;
30239 this.barItems.push(item);
30244 getActive : function()
30246 var active = false;
30248 Roo.each(this.barItems, function(v){
30250 if (!v.isActive()) {
30262 setActiveItem : function(item)
30266 Roo.each(this.barItems, function(v){
30267 if (v.rid == item.rid) {
30271 if (v.isActive()) {
30272 v.setActive(false);
30277 item.setActive(true);
30279 this.fireEvent('changed', this, item, prev);
30282 getBarItem: function(rid)
30286 Roo.each(this.barItems, function(e) {
30287 if (e.rid != rid) {
30298 indexOfItem : function(item)
30302 Roo.each(this.barItems, function(v, i){
30304 if (v.rid != item.rid) {
30315 setActiveNext : function()
30317 var i = this.indexOfItem(this.getActive());
30319 if (i > this.barItems.length) {
30323 this.setActiveItem(this.barItems[i+1]);
30326 setActivePrev : function()
30328 var i = this.indexOfItem(this.getActive());
30334 this.setActiveItem(this.barItems[i-1]);
30337 format : function()
30339 if(!this.barItems.length){
30343 var width = 100 / this.barItems.length;
30345 Roo.each(this.barItems, function(i){
30346 i.el.setStyle('width', width + '%');
30347 i.topEl.el.setStyle('width', width + '%');
30348 i.bottomEl.el.setStyle('width', width + '%');
30357 * Nav Progress Item
30362 * @class Roo.bootstrap.NavProgressItem
30363 * @extends Roo.bootstrap.Component
30364 * Bootstrap NavProgressItem class
30365 * @cfg {String} rid the reference id
30366 * @cfg {Boolean} active (true|false) Is item active default false
30367 * @cfg {Boolean} disabled (true|false) Is item active default false
30368 * @cfg {String} html
30369 * @cfg {String} position (top|bottom) text position default bottom
30370 * @cfg {String} icon show icon instead of number
30373 * Create a new NavProgressItem
30374 * @param {Object} config The config object
30376 Roo.bootstrap.NavProgressItem = function(config){
30377 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30382 * The raw click event for the entire grid.
30383 * @param {Roo.bootstrap.NavProgressItem} this
30384 * @param {Roo.EventObject} e
30391 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30397 position : 'bottom',
30400 getAutoCreate : function()
30402 var iconCls = 'roo-navigation-bar-item-icon';
30404 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30408 cls: 'roo-navigation-bar-item',
30418 cfg.cls += ' active';
30421 cfg.cls += ' disabled';
30427 disable : function()
30429 this.setDisabled(true);
30432 enable : function()
30434 this.setDisabled(false);
30437 initEvents: function()
30439 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30441 this.iconEl.on('click', this.onClick, this);
30444 onClick : function(e)
30446 e.preventDefault();
30452 if(this.fireEvent('click', this, e) === false){
30456 this.parent().setActiveItem(this);
30459 isActive: function ()
30461 return this.active;
30464 setActive : function(state)
30466 if(this.active == state){
30470 this.active = state;
30473 this.el.addClass('active');
30477 this.el.removeClass('active');
30482 setDisabled : function(state)
30484 if(this.disabled == state){
30488 this.disabled = state;
30491 this.el.addClass('disabled');
30495 this.el.removeClass('disabled');
30498 tooltipEl : function()
30500 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30513 * @class Roo.bootstrap.FieldLabel
30514 * @extends Roo.bootstrap.Component
30515 * Bootstrap FieldLabel class
30516 * @cfg {String} html contents of the element
30517 * @cfg {String} tag tag of the element default label
30518 * @cfg {String} cls class of the element
30519 * @cfg {String} target label target
30520 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30521 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30522 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30523 * @cfg {String} iconTooltip default "This field is required"
30524 * @cfg {String} indicatorpos (left|right) default left
30527 * Create a new FieldLabel
30528 * @param {Object} config The config object
30531 Roo.bootstrap.FieldLabel = function(config){
30532 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30537 * Fires after the field has been marked as invalid.
30538 * @param {Roo.form.FieldLabel} this
30539 * @param {String} msg The validation message
30544 * Fires after the field has been validated with no errors.
30545 * @param {Roo.form.FieldLabel} this
30551 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30558 invalidClass : 'has-warning',
30559 validClass : 'has-success',
30560 iconTooltip : 'This field is required',
30561 indicatorpos : 'left',
30563 getAutoCreate : function(){
30566 if (!this.allowBlank) {
30572 cls : 'roo-bootstrap-field-label ' + this.cls,
30577 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30578 tooltip : this.iconTooltip
30587 if(this.indicatorpos == 'right'){
30590 cls : 'roo-bootstrap-field-label ' + this.cls,
30599 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30600 tooltip : this.iconTooltip
30609 initEvents: function()
30611 Roo.bootstrap.Element.superclass.initEvents.call(this);
30613 this.indicator = this.indicatorEl();
30615 if(this.indicator){
30616 this.indicator.removeClass('visible');
30617 this.indicator.addClass('invisible');
30620 Roo.bootstrap.FieldLabel.register(this);
30623 indicatorEl : function()
30625 var indicator = this.el.select('i.roo-required-indicator',true).first();
30636 * Mark this field as valid
30638 markValid : function()
30640 if(this.indicator){
30641 this.indicator.removeClass('visible');
30642 this.indicator.addClass('invisible');
30644 if (Roo.bootstrap.version == 3) {
30645 this.el.removeClass(this.invalidClass);
30646 this.el.addClass(this.validClass);
30648 this.el.removeClass('is-invalid');
30649 this.el.addClass('is-valid');
30653 this.fireEvent('valid', this);
30657 * Mark this field as invalid
30658 * @param {String} msg The validation message
30660 markInvalid : function(msg)
30662 if(this.indicator){
30663 this.indicator.removeClass('invisible');
30664 this.indicator.addClass('visible');
30666 if (Roo.bootstrap.version == 3) {
30667 this.el.removeClass(this.validClass);
30668 this.el.addClass(this.invalidClass);
30670 this.el.removeClass('is-valid');
30671 this.el.addClass('is-invalid');
30675 this.fireEvent('invalid', this, msg);
30681 Roo.apply(Roo.bootstrap.FieldLabel, {
30686 * register a FieldLabel Group
30687 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30689 register : function(label)
30691 if(this.groups.hasOwnProperty(label.target)){
30695 this.groups[label.target] = label;
30699 * fetch a FieldLabel Group based on the target
30700 * @param {string} target
30701 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30703 get: function(target) {
30704 if (typeof(this.groups[target]) == 'undefined') {
30708 return this.groups[target] ;
30717 * page DateSplitField.
30723 * @class Roo.bootstrap.DateSplitField
30724 * @extends Roo.bootstrap.Component
30725 * Bootstrap DateSplitField class
30726 * @cfg {string} fieldLabel - the label associated
30727 * @cfg {Number} labelWidth set the width of label (0-12)
30728 * @cfg {String} labelAlign (top|left)
30729 * @cfg {Boolean} dayAllowBlank (true|false) default false
30730 * @cfg {Boolean} monthAllowBlank (true|false) default false
30731 * @cfg {Boolean} yearAllowBlank (true|false) default false
30732 * @cfg {string} dayPlaceholder
30733 * @cfg {string} monthPlaceholder
30734 * @cfg {string} yearPlaceholder
30735 * @cfg {string} dayFormat default 'd'
30736 * @cfg {string} monthFormat default 'm'
30737 * @cfg {string} yearFormat default 'Y'
30738 * @cfg {Number} labellg set the width of label (1-12)
30739 * @cfg {Number} labelmd set the width of label (1-12)
30740 * @cfg {Number} labelsm set the width of label (1-12)
30741 * @cfg {Number} labelxs set the width of label (1-12)
30745 * Create a new DateSplitField
30746 * @param {Object} config The config object
30749 Roo.bootstrap.DateSplitField = function(config){
30750 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30756 * getting the data of years
30757 * @param {Roo.bootstrap.DateSplitField} this
30758 * @param {Object} years
30763 * getting the data of days
30764 * @param {Roo.bootstrap.DateSplitField} this
30765 * @param {Object} days
30770 * Fires after the field has been marked as invalid.
30771 * @param {Roo.form.Field} this
30772 * @param {String} msg The validation message
30777 * Fires after the field has been validated with no errors.
30778 * @param {Roo.form.Field} this
30784 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30787 labelAlign : 'top',
30789 dayAllowBlank : false,
30790 monthAllowBlank : false,
30791 yearAllowBlank : false,
30792 dayPlaceholder : '',
30793 monthPlaceholder : '',
30794 yearPlaceholder : '',
30798 isFormField : true,
30804 getAutoCreate : function()
30808 cls : 'row roo-date-split-field-group',
30813 cls : 'form-hidden-field roo-date-split-field-group-value',
30819 var labelCls = 'col-md-12';
30820 var contentCls = 'col-md-4';
30822 if(this.fieldLabel){
30826 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30830 html : this.fieldLabel
30835 if(this.labelAlign == 'left'){
30837 if(this.labelWidth > 12){
30838 label.style = "width: " + this.labelWidth + 'px';
30841 if(this.labelWidth < 13 && this.labelmd == 0){
30842 this.labelmd = this.labelWidth;
30845 if(this.labellg > 0){
30846 labelCls = ' col-lg-' + this.labellg;
30847 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30850 if(this.labelmd > 0){
30851 labelCls = ' col-md-' + this.labelmd;
30852 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30855 if(this.labelsm > 0){
30856 labelCls = ' col-sm-' + this.labelsm;
30857 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30860 if(this.labelxs > 0){
30861 labelCls = ' col-xs-' + this.labelxs;
30862 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30866 label.cls += ' ' + labelCls;
30868 cfg.cn.push(label);
30871 Roo.each(['day', 'month', 'year'], function(t){
30874 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30881 inputEl: function ()
30883 return this.el.select('.roo-date-split-field-group-value', true).first();
30886 onRender : function(ct, position)
30890 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30892 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30894 this.dayField = new Roo.bootstrap.ComboBox({
30895 allowBlank : this.dayAllowBlank,
30896 alwaysQuery : true,
30897 displayField : 'value',
30900 forceSelection : true,
30902 placeholder : this.dayPlaceholder,
30903 selectOnFocus : true,
30904 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30905 triggerAction : 'all',
30907 valueField : 'value',
30908 store : new Roo.data.SimpleStore({
30909 data : (function() {
30911 _this.fireEvent('days', _this, days);
30914 fields : [ 'value' ]
30917 select : function (_self, record, index)
30919 _this.setValue(_this.getValue());
30924 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30926 this.monthField = new Roo.bootstrap.MonthField({
30927 after : '<i class=\"fa fa-calendar\"></i>',
30928 allowBlank : this.monthAllowBlank,
30929 placeholder : this.monthPlaceholder,
30932 render : function (_self)
30934 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30935 e.preventDefault();
30939 select : function (_self, oldvalue, newvalue)
30941 _this.setValue(_this.getValue());
30946 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30948 this.yearField = new Roo.bootstrap.ComboBox({
30949 allowBlank : this.yearAllowBlank,
30950 alwaysQuery : true,
30951 displayField : 'value',
30954 forceSelection : true,
30956 placeholder : this.yearPlaceholder,
30957 selectOnFocus : true,
30958 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30959 triggerAction : 'all',
30961 valueField : 'value',
30962 store : new Roo.data.SimpleStore({
30963 data : (function() {
30965 _this.fireEvent('years', _this, years);
30968 fields : [ 'value' ]
30971 select : function (_self, record, index)
30973 _this.setValue(_this.getValue());
30978 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30981 setValue : function(v, format)
30983 this.inputEl.dom.value = v;
30985 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30987 var d = Date.parseDate(v, f);
30994 this.setDay(d.format(this.dayFormat));
30995 this.setMonth(d.format(this.monthFormat));
30996 this.setYear(d.format(this.yearFormat));
31003 setDay : function(v)
31005 this.dayField.setValue(v);
31006 this.inputEl.dom.value = this.getValue();
31011 setMonth : function(v)
31013 this.monthField.setValue(v, true);
31014 this.inputEl.dom.value = this.getValue();
31019 setYear : function(v)
31021 this.yearField.setValue(v);
31022 this.inputEl.dom.value = this.getValue();
31027 getDay : function()
31029 return this.dayField.getValue();
31032 getMonth : function()
31034 return this.monthField.getValue();
31037 getYear : function()
31039 return this.yearField.getValue();
31042 getValue : function()
31044 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31046 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31056 this.inputEl.dom.value = '';
31061 validate : function()
31063 var d = this.dayField.validate();
31064 var m = this.monthField.validate();
31065 var y = this.yearField.validate();
31070 (!this.dayAllowBlank && !d) ||
31071 (!this.monthAllowBlank && !m) ||
31072 (!this.yearAllowBlank && !y)
31077 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31086 this.markInvalid();
31091 markValid : function()
31094 var label = this.el.select('label', true).first();
31095 var icon = this.el.select('i.fa-star', true).first();
31101 this.fireEvent('valid', this);
31105 * Mark this field as invalid
31106 * @param {String} msg The validation message
31108 markInvalid : function(msg)
31111 var label = this.el.select('label', true).first();
31112 var icon = this.el.select('i.fa-star', true).first();
31114 if(label && !icon){
31115 this.el.select('.roo-date-split-field-label', true).createChild({
31117 cls : 'text-danger fa fa-lg fa-star',
31118 tooltip : 'This field is required',
31119 style : 'margin-right:5px;'
31123 this.fireEvent('invalid', this, msg);
31126 clearInvalid : function()
31128 var label = this.el.select('label', true).first();
31129 var icon = this.el.select('i.fa-star', true).first();
31135 this.fireEvent('valid', this);
31138 getName: function()
31148 * http://masonry.desandro.com
31150 * The idea is to render all the bricks based on vertical width...
31152 * The original code extends 'outlayer' - we might need to use that....
31158 * @class Roo.bootstrap.LayoutMasonry
31159 * @extends Roo.bootstrap.Component
31160 * Bootstrap Layout Masonry class
31163 * Create a new Element
31164 * @param {Object} config The config object
31167 Roo.bootstrap.LayoutMasonry = function(config){
31169 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31173 Roo.bootstrap.LayoutMasonry.register(this);
31179 * Fire after layout the items
31180 * @param {Roo.bootstrap.LayoutMasonry} this
31181 * @param {Roo.EventObject} e
31188 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31191 * @cfg {Boolean} isLayoutInstant = no animation?
31193 isLayoutInstant : false, // needed?
31196 * @cfg {Number} boxWidth width of the columns
31201 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31206 * @cfg {Number} padWidth padding below box..
31211 * @cfg {Number} gutter gutter width..
31216 * @cfg {Number} maxCols maximum number of columns
31222 * @cfg {Boolean} isAutoInitial defalut true
31224 isAutoInitial : true,
31229 * @cfg {Boolean} isHorizontal defalut false
31231 isHorizontal : false,
31233 currentSize : null,
31239 bricks: null, //CompositeElement
31243 _isLayoutInited : false,
31245 // isAlternative : false, // only use for vertical layout...
31248 * @cfg {Number} alternativePadWidth padding below box..
31250 alternativePadWidth : 50,
31252 selectedBrick : [],
31254 getAutoCreate : function(){
31256 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31260 cls: 'blog-masonary-wrapper ' + this.cls,
31262 cls : 'mas-boxes masonary'
31269 getChildContainer: function( )
31271 if (this.boxesEl) {
31272 return this.boxesEl;
31275 this.boxesEl = this.el.select('.mas-boxes').first();
31277 return this.boxesEl;
31281 initEvents : function()
31285 if(this.isAutoInitial){
31286 Roo.log('hook children rendered');
31287 this.on('childrenrendered', function() {
31288 Roo.log('children rendered');
31294 initial : function()
31296 this.selectedBrick = [];
31298 this.currentSize = this.el.getBox(true);
31300 Roo.EventManager.onWindowResize(this.resize, this);
31302 if(!this.isAutoInitial){
31310 //this.layout.defer(500,this);
31314 resize : function()
31316 var cs = this.el.getBox(true);
31319 this.currentSize.width == cs.width &&
31320 this.currentSize.x == cs.x &&
31321 this.currentSize.height == cs.height &&
31322 this.currentSize.y == cs.y
31324 Roo.log("no change in with or X or Y");
31328 this.currentSize = cs;
31334 layout : function()
31336 this._resetLayout();
31338 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31340 this.layoutItems( isInstant );
31342 this._isLayoutInited = true;
31344 this.fireEvent('layout', this);
31348 _resetLayout : function()
31350 if(this.isHorizontal){
31351 this.horizontalMeasureColumns();
31355 this.verticalMeasureColumns();
31359 verticalMeasureColumns : function()
31361 this.getContainerWidth();
31363 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31364 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31368 var boxWidth = this.boxWidth + this.padWidth;
31370 if(this.containerWidth < this.boxWidth){
31371 boxWidth = this.containerWidth
31374 var containerWidth = this.containerWidth;
31376 var cols = Math.floor(containerWidth / boxWidth);
31378 this.cols = Math.max( cols, 1 );
31380 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31382 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31384 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31386 this.colWidth = boxWidth + avail - this.padWidth;
31388 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31389 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31392 horizontalMeasureColumns : function()
31394 this.getContainerWidth();
31396 var boxWidth = this.boxWidth;
31398 if(this.containerWidth < boxWidth){
31399 boxWidth = this.containerWidth;
31402 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31404 this.el.setHeight(boxWidth);
31408 getContainerWidth : function()
31410 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31413 layoutItems : function( isInstant )
31415 Roo.log(this.bricks);
31417 var items = Roo.apply([], this.bricks);
31419 if(this.isHorizontal){
31420 this._horizontalLayoutItems( items , isInstant );
31424 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31425 // this._verticalAlternativeLayoutItems( items , isInstant );
31429 this._verticalLayoutItems( items , isInstant );
31433 _verticalLayoutItems : function ( items , isInstant)
31435 if ( !items || !items.length ) {
31440 ['xs', 'xs', 'xs', 'tall'],
31441 ['xs', 'xs', 'tall'],
31442 ['xs', 'xs', 'sm'],
31443 ['xs', 'xs', 'xs'],
31449 ['sm', 'xs', 'xs'],
31453 ['tall', 'xs', 'xs', 'xs'],
31454 ['tall', 'xs', 'xs'],
31466 Roo.each(items, function(item, k){
31468 switch (item.size) {
31469 // these layouts take up a full box,
31480 boxes.push([item]);
31503 var filterPattern = function(box, length)
31511 var pattern = box.slice(0, length);
31515 Roo.each(pattern, function(i){
31516 format.push(i.size);
31519 Roo.each(standard, function(s){
31521 if(String(s) != String(format)){
31530 if(!match && length == 1){
31535 filterPattern(box, length - 1);
31539 queue.push(pattern);
31541 box = box.slice(length, box.length);
31543 filterPattern(box, 4);
31549 Roo.each(boxes, function(box, k){
31555 if(box.length == 1){
31560 filterPattern(box, 4);
31564 this._processVerticalLayoutQueue( queue, isInstant );
31568 // _verticalAlternativeLayoutItems : function( items , isInstant )
31570 // if ( !items || !items.length ) {
31574 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31578 _horizontalLayoutItems : function ( items , isInstant)
31580 if ( !items || !items.length || items.length < 3) {
31586 var eItems = items.slice(0, 3);
31588 items = items.slice(3, items.length);
31591 ['xs', 'xs', 'xs', 'wide'],
31592 ['xs', 'xs', 'wide'],
31593 ['xs', 'xs', 'sm'],
31594 ['xs', 'xs', 'xs'],
31600 ['sm', 'xs', 'xs'],
31604 ['wide', 'xs', 'xs', 'xs'],
31605 ['wide', 'xs', 'xs'],
31618 Roo.each(items, function(item, k){
31620 switch (item.size) {
31631 boxes.push([item]);
31655 var filterPattern = function(box, length)
31663 var pattern = box.slice(0, length);
31667 Roo.each(pattern, function(i){
31668 format.push(i.size);
31671 Roo.each(standard, function(s){
31673 if(String(s) != String(format)){
31682 if(!match && length == 1){
31687 filterPattern(box, length - 1);
31691 queue.push(pattern);
31693 box = box.slice(length, box.length);
31695 filterPattern(box, 4);
31701 Roo.each(boxes, function(box, k){
31707 if(box.length == 1){
31712 filterPattern(box, 4);
31719 var pos = this.el.getBox(true);
31723 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31725 var hit_end = false;
31727 Roo.each(queue, function(box){
31731 Roo.each(box, function(b){
31733 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31743 Roo.each(box, function(b){
31745 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31748 mx = Math.max(mx, b.x);
31752 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31756 Roo.each(box, function(b){
31758 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31772 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31775 /** Sets position of item in DOM
31776 * @param {Element} item
31777 * @param {Number} x - horizontal position
31778 * @param {Number} y - vertical position
31779 * @param {Boolean} isInstant - disables transitions
31781 _processVerticalLayoutQueue : function( queue, isInstant )
31783 var pos = this.el.getBox(true);
31788 for (var i = 0; i < this.cols; i++){
31792 Roo.each(queue, function(box, k){
31794 var col = k % this.cols;
31796 Roo.each(box, function(b,kk){
31798 b.el.position('absolute');
31800 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31801 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31803 if(b.size == 'md-left' || b.size == 'md-right'){
31804 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31805 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31808 b.el.setWidth(width);
31809 b.el.setHeight(height);
31811 b.el.select('iframe',true).setSize(width,height);
31815 for (var i = 0; i < this.cols; i++){
31817 if(maxY[i] < maxY[col]){
31822 col = Math.min(col, i);
31826 x = pos.x + col * (this.colWidth + this.padWidth);
31830 var positions = [];
31832 switch (box.length){
31834 positions = this.getVerticalOneBoxColPositions(x, y, box);
31837 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31840 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31843 positions = this.getVerticalFourBoxColPositions(x, y, box);
31849 Roo.each(box, function(b,kk){
31851 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31853 var sz = b.el.getSize();
31855 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31863 for (var i = 0; i < this.cols; i++){
31864 mY = Math.max(mY, maxY[i]);
31867 this.el.setHeight(mY - pos.y);
31871 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31873 // var pos = this.el.getBox(true);
31876 // var maxX = pos.right;
31878 // var maxHeight = 0;
31880 // Roo.each(items, function(item, k){
31884 // item.el.position('absolute');
31886 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31888 // item.el.setWidth(width);
31890 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31892 // item.el.setHeight(height);
31895 // item.el.setXY([x, y], isInstant ? false : true);
31897 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31900 // y = y + height + this.alternativePadWidth;
31902 // maxHeight = maxHeight + height + this.alternativePadWidth;
31906 // this.el.setHeight(maxHeight);
31910 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31912 var pos = this.el.getBox(true);
31917 var maxX = pos.right;
31919 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31921 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31923 Roo.each(queue, function(box, k){
31925 Roo.each(box, function(b, kk){
31927 b.el.position('absolute');
31929 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31930 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31932 if(b.size == 'md-left' || b.size == 'md-right'){
31933 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31934 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31937 b.el.setWidth(width);
31938 b.el.setHeight(height);
31946 var positions = [];
31948 switch (box.length){
31950 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31953 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31956 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31959 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31965 Roo.each(box, function(b,kk){
31967 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31969 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31977 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31979 Roo.each(eItems, function(b,k){
31981 b.size = (k == 0) ? 'sm' : 'xs';
31982 b.x = (k == 0) ? 2 : 1;
31983 b.y = (k == 0) ? 2 : 1;
31985 b.el.position('absolute');
31987 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31989 b.el.setWidth(width);
31991 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31993 b.el.setHeight(height);
31997 var positions = [];
32000 x : maxX - this.unitWidth * 2 - this.gutter,
32005 x : maxX - this.unitWidth,
32006 y : minY + (this.unitWidth + this.gutter) * 2
32010 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32014 Roo.each(eItems, function(b,k){
32016 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32022 getVerticalOneBoxColPositions : function(x, y, box)
32026 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32028 if(box[0].size == 'md-left'){
32032 if(box[0].size == 'md-right'){
32037 x : x + (this.unitWidth + this.gutter) * rand,
32044 getVerticalTwoBoxColPositions : function(x, y, box)
32048 if(box[0].size == 'xs'){
32052 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32056 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32070 x : x + (this.unitWidth + this.gutter) * 2,
32071 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32078 getVerticalThreeBoxColPositions : function(x, y, box)
32082 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32090 x : x + (this.unitWidth + this.gutter) * 1,
32095 x : x + (this.unitWidth + this.gutter) * 2,
32103 if(box[0].size == 'xs' && box[1].size == 'xs'){
32112 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32116 x : x + (this.unitWidth + this.gutter) * 1,
32130 x : x + (this.unitWidth + this.gutter) * 2,
32135 x : x + (this.unitWidth + this.gutter) * 2,
32136 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32143 getVerticalFourBoxColPositions : function(x, y, box)
32147 if(box[0].size == 'xs'){
32156 y : y + (this.unitHeight + this.gutter) * 1
32161 y : y + (this.unitHeight + this.gutter) * 2
32165 x : x + (this.unitWidth + this.gutter) * 1,
32179 x : x + (this.unitWidth + this.gutter) * 2,
32184 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32185 y : y + (this.unitHeight + this.gutter) * 1
32189 x : x + (this.unitWidth + this.gutter) * 2,
32190 y : y + (this.unitWidth + this.gutter) * 2
32197 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32201 if(box[0].size == 'md-left'){
32203 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32210 if(box[0].size == 'md-right'){
32212 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32213 y : minY + (this.unitWidth + this.gutter) * 1
32219 var rand = Math.floor(Math.random() * (4 - box[0].y));
32222 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32223 y : minY + (this.unitWidth + this.gutter) * rand
32230 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32234 if(box[0].size == 'xs'){
32237 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32242 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32243 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32251 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32256 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32257 y : minY + (this.unitWidth + this.gutter) * 2
32264 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32268 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32271 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32276 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32277 y : minY + (this.unitWidth + this.gutter) * 1
32281 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32282 y : minY + (this.unitWidth + this.gutter) * 2
32289 if(box[0].size == 'xs' && box[1].size == 'xs'){
32292 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32297 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32302 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32303 y : minY + (this.unitWidth + this.gutter) * 1
32311 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32316 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32317 y : minY + (this.unitWidth + this.gutter) * 2
32321 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32322 y : minY + (this.unitWidth + this.gutter) * 2
32329 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32333 if(box[0].size == 'xs'){
32336 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32341 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32346 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),
32351 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32352 y : minY + (this.unitWidth + this.gutter) * 1
32360 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32365 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32366 y : minY + (this.unitWidth + this.gutter) * 2
32370 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32371 y : minY + (this.unitWidth + this.gutter) * 2
32375 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),
32376 y : minY + (this.unitWidth + this.gutter) * 2
32384 * remove a Masonry Brick
32385 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32387 removeBrick : function(brick_id)
32393 for (var i = 0; i<this.bricks.length; i++) {
32394 if (this.bricks[i].id == brick_id) {
32395 this.bricks.splice(i,1);
32396 this.el.dom.removeChild(Roo.get(brick_id).dom);
32403 * adds a Masonry Brick
32404 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32406 addBrick : function(cfg)
32408 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32409 //this.register(cn);
32410 cn.parentId = this.id;
32411 cn.render(this.el);
32416 * register a Masonry Brick
32417 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32420 register : function(brick)
32422 this.bricks.push(brick);
32423 brick.masonryId = this.id;
32427 * clear all the Masonry Brick
32429 clearAll : function()
32432 //this.getChildContainer().dom.innerHTML = "";
32433 this.el.dom.innerHTML = '';
32436 getSelected : function()
32438 if (!this.selectedBrick) {
32442 return this.selectedBrick;
32446 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32450 * register a Masonry Layout
32451 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32454 register : function(layout)
32456 this.groups[layout.id] = layout;
32459 * fetch a Masonry Layout based on the masonry layout ID
32460 * @param {string} the masonry layout to add
32461 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32464 get: function(layout_id) {
32465 if (typeof(this.groups[layout_id]) == 'undefined') {
32468 return this.groups[layout_id] ;
32480 * http://masonry.desandro.com
32482 * The idea is to render all the bricks based on vertical width...
32484 * The original code extends 'outlayer' - we might need to use that....
32490 * @class Roo.bootstrap.LayoutMasonryAuto
32491 * @extends Roo.bootstrap.Component
32492 * Bootstrap Layout Masonry class
32495 * Create a new Element
32496 * @param {Object} config The config object
32499 Roo.bootstrap.LayoutMasonryAuto = function(config){
32500 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32503 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32506 * @cfg {Boolean} isFitWidth - resize the width..
32508 isFitWidth : false, // options..
32510 * @cfg {Boolean} isOriginLeft = left align?
32512 isOriginLeft : true,
32514 * @cfg {Boolean} isOriginTop = top align?
32516 isOriginTop : false,
32518 * @cfg {Boolean} isLayoutInstant = no animation?
32520 isLayoutInstant : false, // needed?
32522 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32524 isResizingContainer : true,
32526 * @cfg {Number} columnWidth width of the columns
32532 * @cfg {Number} maxCols maximum number of columns
32537 * @cfg {Number} padHeight padding below box..
32543 * @cfg {Boolean} isAutoInitial defalut true
32546 isAutoInitial : true,
32552 initialColumnWidth : 0,
32553 currentSize : null,
32555 colYs : null, // array.
32562 bricks: null, //CompositeElement
32563 cols : 0, // array?
32564 // element : null, // wrapped now this.el
32565 _isLayoutInited : null,
32568 getAutoCreate : function(){
32572 cls: 'blog-masonary-wrapper ' + this.cls,
32574 cls : 'mas-boxes masonary'
32581 getChildContainer: function( )
32583 if (this.boxesEl) {
32584 return this.boxesEl;
32587 this.boxesEl = this.el.select('.mas-boxes').first();
32589 return this.boxesEl;
32593 initEvents : function()
32597 if(this.isAutoInitial){
32598 Roo.log('hook children rendered');
32599 this.on('childrenrendered', function() {
32600 Roo.log('children rendered');
32607 initial : function()
32609 this.reloadItems();
32611 this.currentSize = this.el.getBox(true);
32613 /// was window resize... - let's see if this works..
32614 Roo.EventManager.onWindowResize(this.resize, this);
32616 if(!this.isAutoInitial){
32621 this.layout.defer(500,this);
32624 reloadItems: function()
32626 this.bricks = this.el.select('.masonry-brick', true);
32628 this.bricks.each(function(b) {
32629 //Roo.log(b.getSize());
32630 if (!b.attr('originalwidth')) {
32631 b.attr('originalwidth', b.getSize().width);
32636 Roo.log(this.bricks.elements.length);
32639 resize : function()
32642 var cs = this.el.getBox(true);
32644 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32645 Roo.log("no change in with or X");
32648 this.currentSize = cs;
32652 layout : function()
32655 this._resetLayout();
32656 //this._manageStamps();
32658 // don't animate first layout
32659 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32660 this.layoutItems( isInstant );
32662 // flag for initalized
32663 this._isLayoutInited = true;
32666 layoutItems : function( isInstant )
32668 //var items = this._getItemsForLayout( this.items );
32669 // original code supports filtering layout items.. we just ignore it..
32671 this._layoutItems( this.bricks , isInstant );
32673 this._postLayout();
32675 _layoutItems : function ( items , isInstant)
32677 //this.fireEvent( 'layout', this, items );
32680 if ( !items || !items.elements.length ) {
32681 // no items, emit event with empty array
32686 items.each(function(item) {
32687 Roo.log("layout item");
32689 // get x/y object from method
32690 var position = this._getItemLayoutPosition( item );
32692 position.item = item;
32693 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32694 queue.push( position );
32697 this._processLayoutQueue( queue );
32699 /** Sets position of item in DOM
32700 * @param {Element} item
32701 * @param {Number} x - horizontal position
32702 * @param {Number} y - vertical position
32703 * @param {Boolean} isInstant - disables transitions
32705 _processLayoutQueue : function( queue )
32707 for ( var i=0, len = queue.length; i < len; i++ ) {
32708 var obj = queue[i];
32709 obj.item.position('absolute');
32710 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32716 * Any logic you want to do after each layout,
32717 * i.e. size the container
32719 _postLayout : function()
32721 this.resizeContainer();
32724 resizeContainer : function()
32726 if ( !this.isResizingContainer ) {
32729 var size = this._getContainerSize();
32731 this.el.setSize(size.width,size.height);
32732 this.boxesEl.setSize(size.width,size.height);
32738 _resetLayout : function()
32740 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32741 this.colWidth = this.el.getWidth();
32742 //this.gutter = this.el.getWidth();
32744 this.measureColumns();
32750 this.colYs.push( 0 );
32756 measureColumns : function()
32758 this.getContainerWidth();
32759 // if columnWidth is 0, default to outerWidth of first item
32760 if ( !this.columnWidth ) {
32761 var firstItem = this.bricks.first();
32762 Roo.log(firstItem);
32763 this.columnWidth = this.containerWidth;
32764 if (firstItem && firstItem.attr('originalwidth') ) {
32765 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32767 // columnWidth fall back to item of first element
32768 Roo.log("set column width?");
32769 this.initialColumnWidth = this.columnWidth ;
32771 // if first elem has no width, default to size of container
32776 if (this.initialColumnWidth) {
32777 this.columnWidth = this.initialColumnWidth;
32782 // column width is fixed at the top - however if container width get's smaller we should
32785 // this bit calcs how man columns..
32787 var columnWidth = this.columnWidth += this.gutter;
32789 // calculate columns
32790 var containerWidth = this.containerWidth + this.gutter;
32792 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32793 // fix rounding errors, typically with gutters
32794 var excess = columnWidth - containerWidth % columnWidth;
32797 // if overshoot is less than a pixel, round up, otherwise floor it
32798 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32799 cols = Math[ mathMethod ]( cols );
32800 this.cols = Math.max( cols, 1 );
32801 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32803 // padding positioning..
32804 var totalColWidth = this.cols * this.columnWidth;
32805 var padavail = this.containerWidth - totalColWidth;
32806 // so for 2 columns - we need 3 'pads'
32808 var padNeeded = (1+this.cols) * this.padWidth;
32810 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32812 this.columnWidth += padExtra
32813 //this.padWidth = Math.floor(padavail / ( this.cols));
32815 // adjust colum width so that padding is fixed??
32817 // we have 3 columns ... total = width * 3
32818 // we have X left over... that should be used by
32820 //if (this.expandC) {
32828 getContainerWidth : function()
32830 /* // container is parent if fit width
32831 var container = this.isFitWidth ? this.element.parentNode : this.element;
32832 // check that this.size and size are there
32833 // IE8 triggers resize on body size change, so they might not be
32835 var size = getSize( container ); //FIXME
32836 this.containerWidth = size && size.innerWidth; //FIXME
32839 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32843 _getItemLayoutPosition : function( item ) // what is item?
32845 // we resize the item to our columnWidth..
32847 item.setWidth(this.columnWidth);
32848 item.autoBoxAdjust = false;
32850 var sz = item.getSize();
32852 // how many columns does this brick span
32853 var remainder = this.containerWidth % this.columnWidth;
32855 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32856 // round if off by 1 pixel, otherwise use ceil
32857 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32858 colSpan = Math.min( colSpan, this.cols );
32860 // normally this should be '1' as we dont' currently allow multi width columns..
32862 var colGroup = this._getColGroup( colSpan );
32863 // get the minimum Y value from the columns
32864 var minimumY = Math.min.apply( Math, colGroup );
32865 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32867 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32869 // position the brick
32871 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32872 y: this.currentSize.y + minimumY + this.padHeight
32876 // apply setHeight to necessary columns
32877 var setHeight = minimumY + sz.height + this.padHeight;
32878 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32880 var setSpan = this.cols + 1 - colGroup.length;
32881 for ( var i = 0; i < setSpan; i++ ) {
32882 this.colYs[ shortColIndex + i ] = setHeight ;
32889 * @param {Number} colSpan - number of columns the element spans
32890 * @returns {Array} colGroup
32892 _getColGroup : function( colSpan )
32894 if ( colSpan < 2 ) {
32895 // if brick spans only one column, use all the column Ys
32900 // how many different places could this brick fit horizontally
32901 var groupCount = this.cols + 1 - colSpan;
32902 // for each group potential horizontal position
32903 for ( var i = 0; i < groupCount; i++ ) {
32904 // make an array of colY values for that one group
32905 var groupColYs = this.colYs.slice( i, i + colSpan );
32906 // and get the max value of the array
32907 colGroup[i] = Math.max.apply( Math, groupColYs );
32912 _manageStamp : function( stamp )
32914 var stampSize = stamp.getSize();
32915 var offset = stamp.getBox();
32916 // get the columns that this stamp affects
32917 var firstX = this.isOriginLeft ? offset.x : offset.right;
32918 var lastX = firstX + stampSize.width;
32919 var firstCol = Math.floor( firstX / this.columnWidth );
32920 firstCol = Math.max( 0, firstCol );
32922 var lastCol = Math.floor( lastX / this.columnWidth );
32923 // lastCol should not go over if multiple of columnWidth #425
32924 lastCol -= lastX % this.columnWidth ? 0 : 1;
32925 lastCol = Math.min( this.cols - 1, lastCol );
32927 // set colYs to bottom of the stamp
32928 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32931 for ( var i = firstCol; i <= lastCol; i++ ) {
32932 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32937 _getContainerSize : function()
32939 this.maxY = Math.max.apply( Math, this.colYs );
32944 if ( this.isFitWidth ) {
32945 size.width = this._getContainerFitWidth();
32951 _getContainerFitWidth : function()
32953 var unusedCols = 0;
32954 // count unused columns
32957 if ( this.colYs[i] !== 0 ) {
32962 // fit container to columns that have been used
32963 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32966 needsResizeLayout : function()
32968 var previousWidth = this.containerWidth;
32969 this.getContainerWidth();
32970 return previousWidth !== this.containerWidth;
32985 * @class Roo.bootstrap.MasonryBrick
32986 * @extends Roo.bootstrap.Component
32987 * Bootstrap MasonryBrick class
32990 * Create a new MasonryBrick
32991 * @param {Object} config The config object
32994 Roo.bootstrap.MasonryBrick = function(config){
32996 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32998 Roo.bootstrap.MasonryBrick.register(this);
33004 * When a MasonryBrick is clcik
33005 * @param {Roo.bootstrap.MasonryBrick} this
33006 * @param {Roo.EventObject} e
33012 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33015 * @cfg {String} title
33019 * @cfg {String} html
33023 * @cfg {String} bgimage
33027 * @cfg {String} videourl
33031 * @cfg {String} cls
33035 * @cfg {String} href
33039 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33044 * @cfg {String} placetitle (center|bottom)
33049 * @cfg {Boolean} isFitContainer defalut true
33051 isFitContainer : true,
33054 * @cfg {Boolean} preventDefault defalut false
33056 preventDefault : false,
33059 * @cfg {Boolean} inverse defalut false
33061 maskInverse : false,
33063 getAutoCreate : function()
33065 if(!this.isFitContainer){
33066 return this.getSplitAutoCreate();
33069 var cls = 'masonry-brick masonry-brick-full';
33071 if(this.href.length){
33072 cls += ' masonry-brick-link';
33075 if(this.bgimage.length){
33076 cls += ' masonry-brick-image';
33079 if(this.maskInverse){
33080 cls += ' mask-inverse';
33083 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33084 cls += ' enable-mask';
33088 cls += ' masonry-' + this.size + '-brick';
33091 if(this.placetitle.length){
33093 switch (this.placetitle) {
33095 cls += ' masonry-center-title';
33098 cls += ' masonry-bottom-title';
33105 if(!this.html.length && !this.bgimage.length){
33106 cls += ' masonry-center-title';
33109 if(!this.html.length && this.bgimage.length){
33110 cls += ' masonry-bottom-title';
33115 cls += ' ' + this.cls;
33119 tag: (this.href.length) ? 'a' : 'div',
33124 cls: 'masonry-brick-mask'
33128 cls: 'masonry-brick-paragraph',
33134 if(this.href.length){
33135 cfg.href = this.href;
33138 var cn = cfg.cn[1].cn;
33140 if(this.title.length){
33143 cls: 'masonry-brick-title',
33148 if(this.html.length){
33151 cls: 'masonry-brick-text',
33156 if (!this.title.length && !this.html.length) {
33157 cfg.cn[1].cls += ' hide';
33160 if(this.bgimage.length){
33163 cls: 'masonry-brick-image-view',
33168 if(this.videourl.length){
33169 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33170 // youtube support only?
33173 cls: 'masonry-brick-image-view',
33176 allowfullscreen : true
33184 getSplitAutoCreate : function()
33186 var cls = 'masonry-brick masonry-brick-split';
33188 if(this.href.length){
33189 cls += ' masonry-brick-link';
33192 if(this.bgimage.length){
33193 cls += ' masonry-brick-image';
33197 cls += ' masonry-' + this.size + '-brick';
33200 switch (this.placetitle) {
33202 cls += ' masonry-center-title';
33205 cls += ' masonry-bottom-title';
33208 if(!this.bgimage.length){
33209 cls += ' masonry-center-title';
33212 if(this.bgimage.length){
33213 cls += ' masonry-bottom-title';
33219 cls += ' ' + this.cls;
33223 tag: (this.href.length) ? 'a' : 'div',
33228 cls: 'masonry-brick-split-head',
33232 cls: 'masonry-brick-paragraph',
33239 cls: 'masonry-brick-split-body',
33245 if(this.href.length){
33246 cfg.href = this.href;
33249 if(this.title.length){
33250 cfg.cn[0].cn[0].cn.push({
33252 cls: 'masonry-brick-title',
33257 if(this.html.length){
33258 cfg.cn[1].cn.push({
33260 cls: 'masonry-brick-text',
33265 if(this.bgimage.length){
33266 cfg.cn[0].cn.push({
33268 cls: 'masonry-brick-image-view',
33273 if(this.videourl.length){
33274 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33275 // youtube support only?
33276 cfg.cn[0].cn.cn.push({
33278 cls: 'masonry-brick-image-view',
33281 allowfullscreen : true
33288 initEvents: function()
33290 switch (this.size) {
33323 this.el.on('touchstart', this.onTouchStart, this);
33324 this.el.on('touchmove', this.onTouchMove, this);
33325 this.el.on('touchend', this.onTouchEnd, this);
33326 this.el.on('contextmenu', this.onContextMenu, this);
33328 this.el.on('mouseenter' ,this.enter, this);
33329 this.el.on('mouseleave', this.leave, this);
33330 this.el.on('click', this.onClick, this);
33333 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33334 this.parent().bricks.push(this);
33339 onClick: function(e, el)
33341 var time = this.endTimer - this.startTimer;
33342 // Roo.log(e.preventDefault());
33345 e.preventDefault();
33350 if(!this.preventDefault){
33354 e.preventDefault();
33356 if (this.activeClass != '') {
33357 this.selectBrick();
33360 this.fireEvent('click', this, e);
33363 enter: function(e, el)
33365 e.preventDefault();
33367 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33371 if(this.bgimage.length && this.html.length){
33372 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33376 leave: function(e, el)
33378 e.preventDefault();
33380 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33384 if(this.bgimage.length && this.html.length){
33385 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33389 onTouchStart: function(e, el)
33391 // e.preventDefault();
33393 this.touchmoved = false;
33395 if(!this.isFitContainer){
33399 if(!this.bgimage.length || !this.html.length){
33403 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33405 this.timer = new Date().getTime();
33409 onTouchMove: function(e, el)
33411 this.touchmoved = true;
33414 onContextMenu : function(e,el)
33416 e.preventDefault();
33417 e.stopPropagation();
33421 onTouchEnd: function(e, el)
33423 // e.preventDefault();
33425 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33432 if(!this.bgimage.length || !this.html.length){
33434 if(this.href.length){
33435 window.location.href = this.href;
33441 if(!this.isFitContainer){
33445 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33447 window.location.href = this.href;
33450 //selection on single brick only
33451 selectBrick : function() {
33453 if (!this.parentId) {
33457 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33458 var index = m.selectedBrick.indexOf(this.id);
33461 m.selectedBrick.splice(index,1);
33462 this.el.removeClass(this.activeClass);
33466 for(var i = 0; i < m.selectedBrick.length; i++) {
33467 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33468 b.el.removeClass(b.activeClass);
33471 m.selectedBrick = [];
33473 m.selectedBrick.push(this.id);
33474 this.el.addClass(this.activeClass);
33478 isSelected : function(){
33479 return this.el.hasClass(this.activeClass);
33484 Roo.apply(Roo.bootstrap.MasonryBrick, {
33487 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33489 * register a Masonry Brick
33490 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33493 register : function(brick)
33495 //this.groups[brick.id] = brick;
33496 this.groups.add(brick.id, brick);
33499 * fetch a masonry brick based on the masonry brick ID
33500 * @param {string} the masonry brick to add
33501 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33504 get: function(brick_id)
33506 // if (typeof(this.groups[brick_id]) == 'undefined') {
33509 // return this.groups[brick_id] ;
33511 if(this.groups.key(brick_id)) {
33512 return this.groups.key(brick_id);
33530 * @class Roo.bootstrap.Brick
33531 * @extends Roo.bootstrap.Component
33532 * Bootstrap Brick class
33535 * Create a new Brick
33536 * @param {Object} config The config object
33539 Roo.bootstrap.Brick = function(config){
33540 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33546 * When a Brick is click
33547 * @param {Roo.bootstrap.Brick} this
33548 * @param {Roo.EventObject} e
33554 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33557 * @cfg {String} title
33561 * @cfg {String} html
33565 * @cfg {String} bgimage
33569 * @cfg {String} cls
33573 * @cfg {String} href
33577 * @cfg {String} video
33581 * @cfg {Boolean} square
33585 getAutoCreate : function()
33587 var cls = 'roo-brick';
33589 if(this.href.length){
33590 cls += ' roo-brick-link';
33593 if(this.bgimage.length){
33594 cls += ' roo-brick-image';
33597 if(!this.html.length && !this.bgimage.length){
33598 cls += ' roo-brick-center-title';
33601 if(!this.html.length && this.bgimage.length){
33602 cls += ' roo-brick-bottom-title';
33606 cls += ' ' + this.cls;
33610 tag: (this.href.length) ? 'a' : 'div',
33615 cls: 'roo-brick-paragraph',
33621 if(this.href.length){
33622 cfg.href = this.href;
33625 var cn = cfg.cn[0].cn;
33627 if(this.title.length){
33630 cls: 'roo-brick-title',
33635 if(this.html.length){
33638 cls: 'roo-brick-text',
33645 if(this.bgimage.length){
33648 cls: 'roo-brick-image-view',
33656 initEvents: function()
33658 if(this.title.length || this.html.length){
33659 this.el.on('mouseenter' ,this.enter, this);
33660 this.el.on('mouseleave', this.leave, this);
33663 Roo.EventManager.onWindowResize(this.resize, this);
33665 if(this.bgimage.length){
33666 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33667 this.imageEl.on('load', this.onImageLoad, this);
33674 onImageLoad : function()
33679 resize : function()
33681 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33683 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33685 if(this.bgimage.length){
33686 var image = this.el.select('.roo-brick-image-view', true).first();
33688 image.setWidth(paragraph.getWidth());
33691 image.setHeight(paragraph.getWidth());
33694 this.el.setHeight(image.getHeight());
33695 paragraph.setHeight(image.getHeight());
33701 enter: function(e, el)
33703 e.preventDefault();
33705 if(this.bgimage.length){
33706 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33707 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33711 leave: function(e, el)
33713 e.preventDefault();
33715 if(this.bgimage.length){
33716 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33717 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33732 * @class Roo.bootstrap.NumberField
33733 * @extends Roo.bootstrap.Input
33734 * Bootstrap NumberField class
33740 * Create a new NumberField
33741 * @param {Object} config The config object
33744 Roo.bootstrap.NumberField = function(config){
33745 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33748 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33751 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33753 allowDecimals : true,
33755 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33757 decimalSeparator : ".",
33759 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33761 decimalPrecision : 2,
33763 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33765 allowNegative : true,
33768 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33772 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33774 minValue : Number.NEGATIVE_INFINITY,
33776 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33778 maxValue : Number.MAX_VALUE,
33780 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33782 minText : "The minimum value for this field is {0}",
33784 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33786 maxText : "The maximum value for this field is {0}",
33788 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33789 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33791 nanText : "{0} is not a valid number",
33793 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33795 thousandsDelimiter : false,
33797 * @cfg {String} valueAlign alignment of value
33799 valueAlign : "left",
33801 getAutoCreate : function()
33803 var hiddenInput = {
33807 cls: 'hidden-number-input'
33811 hiddenInput.name = this.name;
33816 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33818 this.name = hiddenInput.name;
33820 if(cfg.cn.length > 0) {
33821 cfg.cn.push(hiddenInput);
33828 initEvents : function()
33830 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33832 var allowed = "0123456789";
33834 if(this.allowDecimals){
33835 allowed += this.decimalSeparator;
33838 if(this.allowNegative){
33842 if(this.thousandsDelimiter) {
33846 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33848 var keyPress = function(e){
33850 var k = e.getKey();
33852 var c = e.getCharCode();
33855 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33856 allowed.indexOf(String.fromCharCode(c)) === -1
33862 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33866 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33871 this.el.on("keypress", keyPress, this);
33874 validateValue : function(value)
33877 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33881 var num = this.parseValue(value);
33884 this.markInvalid(String.format(this.nanText, value));
33888 if(num < this.minValue){
33889 this.markInvalid(String.format(this.minText, this.minValue));
33893 if(num > this.maxValue){
33894 this.markInvalid(String.format(this.maxText, this.maxValue));
33901 getValue : function()
33903 var v = this.hiddenEl().getValue();
33905 return this.fixPrecision(this.parseValue(v));
33908 parseValue : function(value)
33910 if(this.thousandsDelimiter) {
33912 r = new RegExp(",", "g");
33913 value = value.replace(r, "");
33916 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33917 return isNaN(value) ? '' : value;
33920 fixPrecision : function(value)
33922 if(this.thousandsDelimiter) {
33924 r = new RegExp(",", "g");
33925 value = value.replace(r, "");
33928 var nan = isNaN(value);
33930 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33931 return nan ? '' : value;
33933 return parseFloat(value).toFixed(this.decimalPrecision);
33936 setValue : function(v)
33938 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33944 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33946 this.inputEl().dom.value = (v == '') ? '' :
33947 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33949 if(!this.allowZero && v === '0') {
33950 this.hiddenEl().dom.value = '';
33951 this.inputEl().dom.value = '';
33958 decimalPrecisionFcn : function(v)
33960 return Math.floor(v);
33963 beforeBlur : function()
33965 var v = this.parseValue(this.getRawValue());
33967 if(v || v === 0 || v === ''){
33972 hiddenEl : function()
33974 return this.el.select('input.hidden-number-input',true).first();
33986 * @class Roo.bootstrap.DocumentSlider
33987 * @extends Roo.bootstrap.Component
33988 * Bootstrap DocumentSlider class
33991 * Create a new DocumentViewer
33992 * @param {Object} config The config object
33995 Roo.bootstrap.DocumentSlider = function(config){
33996 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34003 * Fire after initEvent
34004 * @param {Roo.bootstrap.DocumentSlider} this
34009 * Fire after update
34010 * @param {Roo.bootstrap.DocumentSlider} this
34016 * @param {Roo.bootstrap.DocumentSlider} this
34022 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34028 getAutoCreate : function()
34032 cls : 'roo-document-slider',
34036 cls : 'roo-document-slider-header',
34040 cls : 'roo-document-slider-header-title'
34046 cls : 'roo-document-slider-body',
34050 cls : 'roo-document-slider-prev',
34054 cls : 'fa fa-chevron-left'
34060 cls : 'roo-document-slider-thumb',
34064 cls : 'roo-document-slider-image'
34070 cls : 'roo-document-slider-next',
34074 cls : 'fa fa-chevron-right'
34086 initEvents : function()
34088 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34089 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34091 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34092 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34094 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34095 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34097 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34098 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34100 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34101 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34103 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34104 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34106 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34107 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34109 this.thumbEl.on('click', this.onClick, this);
34111 this.prevIndicator.on('click', this.prev, this);
34113 this.nextIndicator.on('click', this.next, this);
34117 initial : function()
34119 if(this.files.length){
34120 this.indicator = 1;
34124 this.fireEvent('initial', this);
34127 update : function()
34129 this.imageEl.attr('src', this.files[this.indicator - 1]);
34131 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34133 this.prevIndicator.show();
34135 if(this.indicator == 1){
34136 this.prevIndicator.hide();
34139 this.nextIndicator.show();
34141 if(this.indicator == this.files.length){
34142 this.nextIndicator.hide();
34145 this.thumbEl.scrollTo('top');
34147 this.fireEvent('update', this);
34150 onClick : function(e)
34152 e.preventDefault();
34154 this.fireEvent('click', this);
34159 e.preventDefault();
34161 this.indicator = Math.max(1, this.indicator - 1);
34168 e.preventDefault();
34170 this.indicator = Math.min(this.files.length, this.indicator + 1);
34184 * @class Roo.bootstrap.RadioSet
34185 * @extends Roo.bootstrap.Input
34186 * Bootstrap RadioSet class
34187 * @cfg {String} indicatorpos (left|right) default left
34188 * @cfg {Boolean} inline (true|false) inline the element (default true)
34189 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34191 * Create a new RadioSet
34192 * @param {Object} config The config object
34195 Roo.bootstrap.RadioSet = function(config){
34197 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34201 Roo.bootstrap.RadioSet.register(this);
34206 * Fires when the element is checked or unchecked.
34207 * @param {Roo.bootstrap.RadioSet} this This radio
34208 * @param {Roo.bootstrap.Radio} item The checked item
34213 * Fires when the element is click.
34214 * @param {Roo.bootstrap.RadioSet} this This radio set
34215 * @param {Roo.bootstrap.Radio} item The checked item
34216 * @param {Roo.EventObject} e The event object
34223 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34231 indicatorpos : 'left',
34233 getAutoCreate : function()
34237 cls : 'roo-radio-set-label',
34241 html : this.fieldLabel
34245 if (Roo.bootstrap.version == 3) {
34248 if(this.indicatorpos == 'left'){
34251 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34252 tooltip : 'This field is required'
34257 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34258 tooltip : 'This field is required'
34264 cls : 'roo-radio-set-items'
34267 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34269 if (align === 'left' && this.fieldLabel.length) {
34272 cls : "roo-radio-set-right",
34278 if(this.labelWidth > 12){
34279 label.style = "width: " + this.labelWidth + 'px';
34282 if(this.labelWidth < 13 && this.labelmd == 0){
34283 this.labelmd = this.labelWidth;
34286 if(this.labellg > 0){
34287 label.cls += ' col-lg-' + this.labellg;
34288 items.cls += ' col-lg-' + (12 - this.labellg);
34291 if(this.labelmd > 0){
34292 label.cls += ' col-md-' + this.labelmd;
34293 items.cls += ' col-md-' + (12 - this.labelmd);
34296 if(this.labelsm > 0){
34297 label.cls += ' col-sm-' + this.labelsm;
34298 items.cls += ' col-sm-' + (12 - this.labelsm);
34301 if(this.labelxs > 0){
34302 label.cls += ' col-xs-' + this.labelxs;
34303 items.cls += ' col-xs-' + (12 - this.labelxs);
34309 cls : 'roo-radio-set',
34313 cls : 'roo-radio-set-input',
34316 value : this.value ? this.value : ''
34323 if(this.weight.length){
34324 cfg.cls += ' roo-radio-' + this.weight;
34328 cfg.cls += ' roo-radio-set-inline';
34332 ['xs','sm','md','lg'].map(function(size){
34333 if (settings[size]) {
34334 cfg.cls += ' col-' + size + '-' + settings[size];
34342 initEvents : function()
34344 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34345 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34347 if(!this.fieldLabel.length){
34348 this.labelEl.hide();
34351 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34352 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34354 this.indicator = this.indicatorEl();
34356 if(this.indicator){
34357 this.indicator.addClass('invisible');
34360 this.originalValue = this.getValue();
34364 inputEl: function ()
34366 return this.el.select('.roo-radio-set-input', true).first();
34369 getChildContainer : function()
34371 return this.itemsEl;
34374 register : function(item)
34376 this.radioes.push(item);
34380 validate : function()
34382 if(this.getVisibilityEl().hasClass('hidden')){
34388 Roo.each(this.radioes, function(i){
34397 if(this.allowBlank) {
34401 if(this.disabled || valid){
34406 this.markInvalid();
34411 markValid : function()
34413 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34414 this.indicatorEl().removeClass('visible');
34415 this.indicatorEl().addClass('invisible');
34419 if (Roo.bootstrap.version == 3) {
34420 this.el.removeClass([this.invalidClass, this.validClass]);
34421 this.el.addClass(this.validClass);
34423 this.el.removeClass(['is-invalid','is-valid']);
34424 this.el.addClass(['is-valid']);
34426 this.fireEvent('valid', this);
34429 markInvalid : function(msg)
34431 if(this.allowBlank || this.disabled){
34435 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34436 this.indicatorEl().removeClass('invisible');
34437 this.indicatorEl().addClass('visible');
34439 if (Roo.bootstrap.version == 3) {
34440 this.el.removeClass([this.invalidClass, this.validClass]);
34441 this.el.addClass(this.invalidClass);
34443 this.el.removeClass(['is-invalid','is-valid']);
34444 this.el.addClass(['is-invalid']);
34447 this.fireEvent('invalid', this, msg);
34451 setValue : function(v, suppressEvent)
34453 if(this.value === v){
34460 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34463 Roo.each(this.radioes, function(i){
34465 i.el.removeClass('checked');
34468 Roo.each(this.radioes, function(i){
34470 if(i.value === v || i.value.toString() === v.toString()){
34472 i.el.addClass('checked');
34474 if(suppressEvent !== true){
34475 this.fireEvent('check', this, i);
34486 clearInvalid : function(){
34488 if(!this.el || this.preventMark){
34492 this.el.removeClass([this.invalidClass]);
34494 this.fireEvent('valid', this);
34499 Roo.apply(Roo.bootstrap.RadioSet, {
34503 register : function(set)
34505 this.groups[set.name] = set;
34508 get: function(name)
34510 if (typeof(this.groups[name]) == 'undefined') {
34514 return this.groups[name] ;
34520 * Ext JS Library 1.1.1
34521 * Copyright(c) 2006-2007, Ext JS, LLC.
34523 * Originally Released Under LGPL - original licence link has changed is not relivant.
34526 * <script type="text/javascript">
34531 * @class Roo.bootstrap.SplitBar
34532 * @extends Roo.util.Observable
34533 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34537 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34538 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34539 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34540 split.minSize = 100;
34541 split.maxSize = 600;
34542 split.animate = true;
34543 split.on('moved', splitterMoved);
34546 * Create a new SplitBar
34547 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34548 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34549 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34550 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34551 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34552 position of the SplitBar).
34554 Roo.bootstrap.SplitBar = function(cfg){
34559 // dragElement : elm
34560 // resizingElement: el,
34562 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34563 // placement : Roo.bootstrap.SplitBar.LEFT ,
34564 // existingProxy ???
34567 this.el = Roo.get(cfg.dragElement, true);
34568 this.el.dom.unselectable = "on";
34570 this.resizingEl = Roo.get(cfg.resizingElement, true);
34574 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34575 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34578 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34581 * The minimum size of the resizing element. (Defaults to 0)
34587 * The maximum size of the resizing element. (Defaults to 2000)
34590 this.maxSize = 2000;
34593 * Whether to animate the transition to the new size
34596 this.animate = false;
34599 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34602 this.useShim = false;
34607 if(!cfg.existingProxy){
34609 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34611 this.proxy = Roo.get(cfg.existingProxy).dom;
34614 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34617 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34620 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34623 this.dragSpecs = {};
34626 * @private The adapter to use to positon and resize elements
34628 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34629 this.adapter.init(this);
34631 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34633 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34634 this.el.addClass("roo-splitbar-h");
34637 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34638 this.el.addClass("roo-splitbar-v");
34644 * Fires when the splitter is moved (alias for {@link #event-moved})
34645 * @param {Roo.bootstrap.SplitBar} this
34646 * @param {Number} newSize the new width or height
34651 * Fires when the splitter is moved
34652 * @param {Roo.bootstrap.SplitBar} this
34653 * @param {Number} newSize the new width or height
34657 * @event beforeresize
34658 * Fires before the splitter is dragged
34659 * @param {Roo.bootstrap.SplitBar} this
34661 "beforeresize" : true,
34663 "beforeapply" : true
34666 Roo.util.Observable.call(this);
34669 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34670 onStartProxyDrag : function(x, y){
34671 this.fireEvent("beforeresize", this);
34673 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34675 o.enableDisplayMode("block");
34676 // all splitbars share the same overlay
34677 Roo.bootstrap.SplitBar.prototype.overlay = o;
34679 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34680 this.overlay.show();
34681 Roo.get(this.proxy).setDisplayed("block");
34682 var size = this.adapter.getElementSize(this);
34683 this.activeMinSize = this.getMinimumSize();;
34684 this.activeMaxSize = this.getMaximumSize();;
34685 var c1 = size - this.activeMinSize;
34686 var c2 = Math.max(this.activeMaxSize - size, 0);
34687 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34688 this.dd.resetConstraints();
34689 this.dd.setXConstraint(
34690 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34691 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34693 this.dd.setYConstraint(0, 0);
34695 this.dd.resetConstraints();
34696 this.dd.setXConstraint(0, 0);
34697 this.dd.setYConstraint(
34698 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34699 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34702 this.dragSpecs.startSize = size;
34703 this.dragSpecs.startPoint = [x, y];
34704 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34708 * @private Called after the drag operation by the DDProxy
34710 onEndProxyDrag : function(e){
34711 Roo.get(this.proxy).setDisplayed(false);
34712 var endPoint = Roo.lib.Event.getXY(e);
34714 this.overlay.hide();
34717 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34718 newSize = this.dragSpecs.startSize +
34719 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34720 endPoint[0] - this.dragSpecs.startPoint[0] :
34721 this.dragSpecs.startPoint[0] - endPoint[0]
34724 newSize = this.dragSpecs.startSize +
34725 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34726 endPoint[1] - this.dragSpecs.startPoint[1] :
34727 this.dragSpecs.startPoint[1] - endPoint[1]
34730 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34731 if(newSize != this.dragSpecs.startSize){
34732 if(this.fireEvent('beforeapply', this, newSize) !== false){
34733 this.adapter.setElementSize(this, newSize);
34734 this.fireEvent("moved", this, newSize);
34735 this.fireEvent("resize", this, newSize);
34741 * Get the adapter this SplitBar uses
34742 * @return The adapter object
34744 getAdapter : function(){
34745 return this.adapter;
34749 * Set the adapter this SplitBar uses
34750 * @param {Object} adapter A SplitBar adapter object
34752 setAdapter : function(adapter){
34753 this.adapter = adapter;
34754 this.adapter.init(this);
34758 * Gets the minimum size for the resizing element
34759 * @return {Number} The minimum size
34761 getMinimumSize : function(){
34762 return this.minSize;
34766 * Sets the minimum size for the resizing element
34767 * @param {Number} minSize The minimum size
34769 setMinimumSize : function(minSize){
34770 this.minSize = minSize;
34774 * Gets the maximum size for the resizing element
34775 * @return {Number} The maximum size
34777 getMaximumSize : function(){
34778 return this.maxSize;
34782 * Sets the maximum size for the resizing element
34783 * @param {Number} maxSize The maximum size
34785 setMaximumSize : function(maxSize){
34786 this.maxSize = maxSize;
34790 * Sets the initialize size for the resizing element
34791 * @param {Number} size The initial size
34793 setCurrentSize : function(size){
34794 var oldAnimate = this.animate;
34795 this.animate = false;
34796 this.adapter.setElementSize(this, size);
34797 this.animate = oldAnimate;
34801 * Destroy this splitbar.
34802 * @param {Boolean} removeEl True to remove the element
34804 destroy : function(removeEl){
34806 this.shim.remove();
34809 this.proxy.parentNode.removeChild(this.proxy);
34817 * @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.
34819 Roo.bootstrap.SplitBar.createProxy = function(dir){
34820 var proxy = new Roo.Element(document.createElement("div"));
34821 proxy.unselectable();
34822 var cls = 'roo-splitbar-proxy';
34823 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34824 document.body.appendChild(proxy.dom);
34829 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34830 * Default Adapter. It assumes the splitter and resizing element are not positioned
34831 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34833 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34836 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34837 // do nothing for now
34838 init : function(s){
34842 * Called before drag operations to get the current size of the resizing element.
34843 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34845 getElementSize : function(s){
34846 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34847 return s.resizingEl.getWidth();
34849 return s.resizingEl.getHeight();
34854 * Called after drag operations to set the size of the resizing element.
34855 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34856 * @param {Number} newSize The new size to set
34857 * @param {Function} onComplete A function to be invoked when resizing is complete
34859 setElementSize : function(s, newSize, onComplete){
34860 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34862 s.resizingEl.setWidth(newSize);
34864 onComplete(s, newSize);
34867 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34872 s.resizingEl.setHeight(newSize);
34874 onComplete(s, newSize);
34877 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34884 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34885 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34886 * Adapter that moves the splitter element to align with the resized sizing element.
34887 * Used with an absolute positioned SplitBar.
34888 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34889 * document.body, make sure you assign an id to the body element.
34891 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34892 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34893 this.container = Roo.get(container);
34896 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34897 init : function(s){
34898 this.basic.init(s);
34901 getElementSize : function(s){
34902 return this.basic.getElementSize(s);
34905 setElementSize : function(s, newSize, onComplete){
34906 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34909 moveSplitter : function(s){
34910 var yes = Roo.bootstrap.SplitBar;
34911 switch(s.placement){
34913 s.el.setX(s.resizingEl.getRight());
34916 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34919 s.el.setY(s.resizingEl.getBottom());
34922 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34929 * Orientation constant - Create a vertical SplitBar
34933 Roo.bootstrap.SplitBar.VERTICAL = 1;
34936 * Orientation constant - Create a horizontal SplitBar
34940 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34943 * Placement constant - The resizing element is to the left of the splitter element
34947 Roo.bootstrap.SplitBar.LEFT = 1;
34950 * Placement constant - The resizing element is to the right of the splitter element
34954 Roo.bootstrap.SplitBar.RIGHT = 2;
34957 * Placement constant - The resizing element is positioned above the splitter element
34961 Roo.bootstrap.SplitBar.TOP = 3;
34964 * Placement constant - The resizing element is positioned under splitter element
34968 Roo.bootstrap.SplitBar.BOTTOM = 4;
34969 Roo.namespace("Roo.bootstrap.layout");/*
34971 * Ext JS Library 1.1.1
34972 * Copyright(c) 2006-2007, Ext JS, LLC.
34974 * Originally Released Under LGPL - original licence link has changed is not relivant.
34977 * <script type="text/javascript">
34981 * @class Roo.bootstrap.layout.Manager
34982 * @extends Roo.bootstrap.Component
34983 * Base class for layout managers.
34985 Roo.bootstrap.layout.Manager = function(config)
34987 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34993 /** false to disable window resize monitoring @type Boolean */
34994 this.monitorWindowResize = true;
34999 * Fires when a layout is performed.
35000 * @param {Roo.LayoutManager} this
35004 * @event regionresized
35005 * Fires when the user resizes a region.
35006 * @param {Roo.LayoutRegion} region The resized region
35007 * @param {Number} newSize The new size (width for east/west, height for north/south)
35009 "regionresized" : true,
35011 * @event regioncollapsed
35012 * Fires when a region is collapsed.
35013 * @param {Roo.LayoutRegion} region The collapsed region
35015 "regioncollapsed" : true,
35017 * @event regionexpanded
35018 * Fires when a region is expanded.
35019 * @param {Roo.LayoutRegion} region The expanded region
35021 "regionexpanded" : true
35023 this.updating = false;
35026 this.el = Roo.get(config.el);
35032 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35037 monitorWindowResize : true,
35043 onRender : function(ct, position)
35046 this.el = Roo.get(ct);
35049 //this.fireEvent('render',this);
35053 initEvents: function()
35057 // ie scrollbar fix
35058 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35059 document.body.scroll = "no";
35060 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35061 this.el.position('relative');
35063 this.id = this.el.id;
35064 this.el.addClass("roo-layout-container");
35065 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35066 if(this.el.dom != document.body ) {
35067 this.el.on('resize', this.layout,this);
35068 this.el.on('show', this.layout,this);
35074 * Returns true if this layout is currently being updated
35075 * @return {Boolean}
35077 isUpdating : function(){
35078 return this.updating;
35082 * Suspend the LayoutManager from doing auto-layouts while
35083 * making multiple add or remove calls
35085 beginUpdate : function(){
35086 this.updating = true;
35090 * Restore auto-layouts and optionally disable the manager from performing a layout
35091 * @param {Boolean} noLayout true to disable a layout update
35093 endUpdate : function(noLayout){
35094 this.updating = false;
35100 layout: function(){
35104 onRegionResized : function(region, newSize){
35105 this.fireEvent("regionresized", region, newSize);
35109 onRegionCollapsed : function(region){
35110 this.fireEvent("regioncollapsed", region);
35113 onRegionExpanded : function(region){
35114 this.fireEvent("regionexpanded", region);
35118 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35119 * performs box-model adjustments.
35120 * @return {Object} The size as an object {width: (the width), height: (the height)}
35122 getViewSize : function()
35125 if(this.el.dom != document.body){
35126 size = this.el.getSize();
35128 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35130 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35131 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35136 * Returns the Element this layout is bound to.
35137 * @return {Roo.Element}
35139 getEl : function(){
35144 * Returns the specified region.
35145 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35146 * @return {Roo.LayoutRegion}
35148 getRegion : function(target){
35149 return this.regions[target.toLowerCase()];
35152 onWindowResize : function(){
35153 if(this.monitorWindowResize){
35160 * Ext JS Library 1.1.1
35161 * Copyright(c) 2006-2007, Ext JS, LLC.
35163 * Originally Released Under LGPL - original licence link has changed is not relivant.
35166 * <script type="text/javascript">
35169 * @class Roo.bootstrap.layout.Border
35170 * @extends Roo.bootstrap.layout.Manager
35171 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35172 * please see: examples/bootstrap/nested.html<br><br>
35174 <b>The container the layout is rendered into can be either the body element or any other element.
35175 If it is not the body element, the container needs to either be an absolute positioned element,
35176 or you will need to add "position:relative" to the css of the container. You will also need to specify
35177 the container size if it is not the body element.</b>
35180 * Create a new Border
35181 * @param {Object} config Configuration options
35183 Roo.bootstrap.layout.Border = function(config){
35184 config = config || {};
35185 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35189 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35190 if(config[region]){
35191 config[region].region = region;
35192 this.addRegion(config[region]);
35198 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35200 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35202 parent : false, // this might point to a 'nest' or a ???
35205 * Creates and adds a new region if it doesn't already exist.
35206 * @param {String} target The target region key (north, south, east, west or center).
35207 * @param {Object} config The regions config object
35208 * @return {BorderLayoutRegion} The new region
35210 addRegion : function(config)
35212 if(!this.regions[config.region]){
35213 var r = this.factory(config);
35214 this.bindRegion(r);
35216 return this.regions[config.region];
35220 bindRegion : function(r){
35221 this.regions[r.config.region] = r;
35223 r.on("visibilitychange", this.layout, this);
35224 r.on("paneladded", this.layout, this);
35225 r.on("panelremoved", this.layout, this);
35226 r.on("invalidated", this.layout, this);
35227 r.on("resized", this.onRegionResized, this);
35228 r.on("collapsed", this.onRegionCollapsed, this);
35229 r.on("expanded", this.onRegionExpanded, this);
35233 * Performs a layout update.
35235 layout : function()
35237 if(this.updating) {
35241 // render all the rebions if they have not been done alreayd?
35242 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35243 if(this.regions[region] && !this.regions[region].bodyEl){
35244 this.regions[region].onRender(this.el)
35248 var size = this.getViewSize();
35249 var w = size.width;
35250 var h = size.height;
35255 //var x = 0, y = 0;
35257 var rs = this.regions;
35258 var north = rs["north"];
35259 var south = rs["south"];
35260 var west = rs["west"];
35261 var east = rs["east"];
35262 var center = rs["center"];
35263 //if(this.hideOnLayout){ // not supported anymore
35264 //c.el.setStyle("display", "none");
35266 if(north && north.isVisible()){
35267 var b = north.getBox();
35268 var m = north.getMargins();
35269 b.width = w - (m.left+m.right);
35272 centerY = b.height + b.y + m.bottom;
35273 centerH -= centerY;
35274 north.updateBox(this.safeBox(b));
35276 if(south && south.isVisible()){
35277 var b = south.getBox();
35278 var m = south.getMargins();
35279 b.width = w - (m.left+m.right);
35281 var totalHeight = (b.height + m.top + m.bottom);
35282 b.y = h - totalHeight + m.top;
35283 centerH -= totalHeight;
35284 south.updateBox(this.safeBox(b));
35286 if(west && west.isVisible()){
35287 var b = west.getBox();
35288 var m = west.getMargins();
35289 b.height = centerH - (m.top+m.bottom);
35291 b.y = centerY + m.top;
35292 var totalWidth = (b.width + m.left + m.right);
35293 centerX += totalWidth;
35294 centerW -= totalWidth;
35295 west.updateBox(this.safeBox(b));
35297 if(east && east.isVisible()){
35298 var b = east.getBox();
35299 var m = east.getMargins();
35300 b.height = centerH - (m.top+m.bottom);
35301 var totalWidth = (b.width + m.left + m.right);
35302 b.x = w - totalWidth + m.left;
35303 b.y = centerY + m.top;
35304 centerW -= totalWidth;
35305 east.updateBox(this.safeBox(b));
35308 var m = center.getMargins();
35310 x: centerX + m.left,
35311 y: centerY + m.top,
35312 width: centerW - (m.left+m.right),
35313 height: centerH - (m.top+m.bottom)
35315 //if(this.hideOnLayout){
35316 //center.el.setStyle("display", "block");
35318 center.updateBox(this.safeBox(centerBox));
35321 this.fireEvent("layout", this);
35325 safeBox : function(box){
35326 box.width = Math.max(0, box.width);
35327 box.height = Math.max(0, box.height);
35332 * Adds a ContentPanel (or subclass) to this layout.
35333 * @param {String} target The target region key (north, south, east, west or center).
35334 * @param {Roo.ContentPanel} panel The panel to add
35335 * @return {Roo.ContentPanel} The added panel
35337 add : function(target, panel){
35339 target = target.toLowerCase();
35340 return this.regions[target].add(panel);
35344 * Remove a ContentPanel (or subclass) to this layout.
35345 * @param {String} target The target region key (north, south, east, west or center).
35346 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35347 * @return {Roo.ContentPanel} The removed panel
35349 remove : function(target, panel){
35350 target = target.toLowerCase();
35351 return this.regions[target].remove(panel);
35355 * Searches all regions for a panel with the specified id
35356 * @param {String} panelId
35357 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35359 findPanel : function(panelId){
35360 var rs = this.regions;
35361 for(var target in rs){
35362 if(typeof rs[target] != "function"){
35363 var p = rs[target].getPanel(panelId);
35373 * Searches all regions for a panel with the specified id and activates (shows) it.
35374 * @param {String/ContentPanel} panelId The panels id or the panel itself
35375 * @return {Roo.ContentPanel} The shown panel or null
35377 showPanel : function(panelId) {
35378 var rs = this.regions;
35379 for(var target in rs){
35380 var r = rs[target];
35381 if(typeof r != "function"){
35382 if(r.hasPanel(panelId)){
35383 return r.showPanel(panelId);
35391 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35392 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35395 restoreState : function(provider){
35397 provider = Roo.state.Manager;
35399 var sm = new Roo.LayoutStateManager();
35400 sm.init(this, provider);
35406 * Adds a xtype elements to the layout.
35410 xtype : 'ContentPanel',
35417 xtype : 'NestedLayoutPanel',
35423 items : [ ... list of content panels or nested layout panels.. ]
35427 * @param {Object} cfg Xtype definition of item to add.
35429 addxtype : function(cfg)
35431 // basically accepts a pannel...
35432 // can accept a layout region..!?!?
35433 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35436 // theory? children can only be panels??
35438 //if (!cfg.xtype.match(/Panel$/)) {
35443 if (typeof(cfg.region) == 'undefined') {
35444 Roo.log("Failed to add Panel, region was not set");
35448 var region = cfg.region;
35454 xitems = cfg.items;
35459 if ( region == 'center') {
35460 Roo.log("Center: " + cfg.title);
35466 case 'Content': // ContentPanel (el, cfg)
35467 case 'Scroll': // ContentPanel (el, cfg)
35469 cfg.autoCreate = cfg.autoCreate || true;
35470 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35472 // var el = this.el.createChild();
35473 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35476 this.add(region, ret);
35480 case 'TreePanel': // our new panel!
35481 cfg.el = this.el.createChild();
35482 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35483 this.add(region, ret);
35488 // create a new Layout (which is a Border Layout...
35490 var clayout = cfg.layout;
35491 clayout.el = this.el.createChild();
35492 clayout.items = clayout.items || [];
35496 // replace this exitems with the clayout ones..
35497 xitems = clayout.items;
35499 // force background off if it's in center...
35500 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35501 cfg.background = false;
35503 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35506 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35507 //console.log('adding nested layout panel ' + cfg.toSource());
35508 this.add(region, ret);
35509 nb = {}; /// find first...
35514 // needs grid and region
35516 //var el = this.getRegion(region).el.createChild();
35518 *var el = this.el.createChild();
35519 // create the grid first...
35520 cfg.grid.container = el;
35521 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35524 if (region == 'center' && this.active ) {
35525 cfg.background = false;
35528 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35530 this.add(region, ret);
35532 if (cfg.background) {
35533 // render grid on panel activation (if panel background)
35534 ret.on('activate', function(gp) {
35535 if (!gp.grid.rendered) {
35536 // gp.grid.render(el);
35540 // cfg.grid.render(el);
35546 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35547 // it was the old xcomponent building that caused this before.
35548 // espeically if border is the top element in the tree.
35558 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35560 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35561 this.add(region, ret);
35565 throw "Can not add '" + cfg.xtype + "' to Border";
35571 this.beginUpdate();
35575 Roo.each(xitems, function(i) {
35576 region = nb && i.region ? i.region : false;
35578 var add = ret.addxtype(i);
35581 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35582 if (!i.background) {
35583 abn[region] = nb[region] ;
35590 // make the last non-background panel active..
35591 //if (nb) { Roo.log(abn); }
35594 for(var r in abn) {
35595 region = this.getRegion(r);
35597 // tried using nb[r], but it does not work..
35599 region.showPanel(abn[r]);
35610 factory : function(cfg)
35613 var validRegions = Roo.bootstrap.layout.Border.regions;
35615 var target = cfg.region;
35618 var r = Roo.bootstrap.layout;
35622 return new r.North(cfg);
35624 return new r.South(cfg);
35626 return new r.East(cfg);
35628 return new r.West(cfg);
35630 return new r.Center(cfg);
35632 throw 'Layout region "'+target+'" not supported.';
35639 * Ext JS Library 1.1.1
35640 * Copyright(c) 2006-2007, Ext JS, LLC.
35642 * Originally Released Under LGPL - original licence link has changed is not relivant.
35645 * <script type="text/javascript">
35649 * @class Roo.bootstrap.layout.Basic
35650 * @extends Roo.util.Observable
35651 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35652 * and does not have a titlebar, tabs or any other features. All it does is size and position
35653 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35654 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35655 * @cfg {string} region the region that it inhabits..
35656 * @cfg {bool} skipConfig skip config?
35660 Roo.bootstrap.layout.Basic = function(config){
35662 this.mgr = config.mgr;
35664 this.position = config.region;
35666 var skipConfig = config.skipConfig;
35670 * @scope Roo.BasicLayoutRegion
35674 * @event beforeremove
35675 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35676 * @param {Roo.LayoutRegion} this
35677 * @param {Roo.ContentPanel} panel The panel
35678 * @param {Object} e The cancel event object
35680 "beforeremove" : true,
35682 * @event invalidated
35683 * Fires when the layout for this region is changed.
35684 * @param {Roo.LayoutRegion} this
35686 "invalidated" : true,
35688 * @event visibilitychange
35689 * Fires when this region is shown or hidden
35690 * @param {Roo.LayoutRegion} this
35691 * @param {Boolean} visibility true or false
35693 "visibilitychange" : true,
35695 * @event paneladded
35696 * Fires when a panel is added.
35697 * @param {Roo.LayoutRegion} this
35698 * @param {Roo.ContentPanel} panel The panel
35700 "paneladded" : true,
35702 * @event panelremoved
35703 * Fires when a panel is removed.
35704 * @param {Roo.LayoutRegion} this
35705 * @param {Roo.ContentPanel} panel The panel
35707 "panelremoved" : true,
35709 * @event beforecollapse
35710 * Fires when this region before collapse.
35711 * @param {Roo.LayoutRegion} this
35713 "beforecollapse" : true,
35716 * Fires when this region is collapsed.
35717 * @param {Roo.LayoutRegion} this
35719 "collapsed" : true,
35722 * Fires when this region is expanded.
35723 * @param {Roo.LayoutRegion} this
35728 * Fires when this region is slid into view.
35729 * @param {Roo.LayoutRegion} this
35731 "slideshow" : true,
35734 * Fires when this region slides out of view.
35735 * @param {Roo.LayoutRegion} this
35737 "slidehide" : true,
35739 * @event panelactivated
35740 * Fires when a panel is activated.
35741 * @param {Roo.LayoutRegion} this
35742 * @param {Roo.ContentPanel} panel The activated panel
35744 "panelactivated" : true,
35747 * Fires when the user resizes this region.
35748 * @param {Roo.LayoutRegion} this
35749 * @param {Number} newSize The new size (width for east/west, height for north/south)
35753 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35754 this.panels = new Roo.util.MixedCollection();
35755 this.panels.getKey = this.getPanelId.createDelegate(this);
35757 this.activePanel = null;
35758 // ensure listeners are added...
35760 if (config.listeners || config.events) {
35761 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35762 listeners : config.listeners || {},
35763 events : config.events || {}
35767 if(skipConfig !== true){
35768 this.applyConfig(config);
35772 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35774 getPanelId : function(p){
35778 applyConfig : function(config){
35779 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35780 this.config = config;
35785 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35786 * the width, for horizontal (north, south) the height.
35787 * @param {Number} newSize The new width or height
35789 resizeTo : function(newSize){
35790 var el = this.el ? this.el :
35791 (this.activePanel ? this.activePanel.getEl() : null);
35793 switch(this.position){
35796 el.setWidth(newSize);
35797 this.fireEvent("resized", this, newSize);
35801 el.setHeight(newSize);
35802 this.fireEvent("resized", this, newSize);
35808 getBox : function(){
35809 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35812 getMargins : function(){
35813 return this.margins;
35816 updateBox : function(box){
35818 var el = this.activePanel.getEl();
35819 el.dom.style.left = box.x + "px";
35820 el.dom.style.top = box.y + "px";
35821 this.activePanel.setSize(box.width, box.height);
35825 * Returns the container element for this region.
35826 * @return {Roo.Element}
35828 getEl : function(){
35829 return this.activePanel;
35833 * Returns true if this region is currently visible.
35834 * @return {Boolean}
35836 isVisible : function(){
35837 return this.activePanel ? true : false;
35840 setActivePanel : function(panel){
35841 panel = this.getPanel(panel);
35842 if(this.activePanel && this.activePanel != panel){
35843 this.activePanel.setActiveState(false);
35844 this.activePanel.getEl().setLeftTop(-10000,-10000);
35846 this.activePanel = panel;
35847 panel.setActiveState(true);
35849 panel.setSize(this.box.width, this.box.height);
35851 this.fireEvent("panelactivated", this, panel);
35852 this.fireEvent("invalidated");
35856 * Show the specified panel.
35857 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35858 * @return {Roo.ContentPanel} The shown panel or null
35860 showPanel : function(panel){
35861 panel = this.getPanel(panel);
35863 this.setActivePanel(panel);
35869 * Get the active panel for this region.
35870 * @return {Roo.ContentPanel} The active panel or null
35872 getActivePanel : function(){
35873 return this.activePanel;
35877 * Add the passed ContentPanel(s)
35878 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35879 * @return {Roo.ContentPanel} The panel added (if only one was added)
35881 add : function(panel){
35882 if(arguments.length > 1){
35883 for(var i = 0, len = arguments.length; i < len; i++) {
35884 this.add(arguments[i]);
35888 if(this.hasPanel(panel)){
35889 this.showPanel(panel);
35892 var el = panel.getEl();
35893 if(el.dom.parentNode != this.mgr.el.dom){
35894 this.mgr.el.dom.appendChild(el.dom);
35896 if(panel.setRegion){
35897 panel.setRegion(this);
35899 this.panels.add(panel);
35900 el.setStyle("position", "absolute");
35901 if(!panel.background){
35902 this.setActivePanel(panel);
35903 if(this.config.initialSize && this.panels.getCount()==1){
35904 this.resizeTo(this.config.initialSize);
35907 this.fireEvent("paneladded", this, panel);
35912 * Returns true if the panel is in this region.
35913 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35914 * @return {Boolean}
35916 hasPanel : function(panel){
35917 if(typeof panel == "object"){ // must be panel obj
35918 panel = panel.getId();
35920 return this.getPanel(panel) ? true : false;
35924 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35925 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35926 * @param {Boolean} preservePanel Overrides the config preservePanel option
35927 * @return {Roo.ContentPanel} The panel that was removed
35929 remove : function(panel, preservePanel){
35930 panel = this.getPanel(panel);
35935 this.fireEvent("beforeremove", this, panel, e);
35936 if(e.cancel === true){
35939 var panelId = panel.getId();
35940 this.panels.removeKey(panelId);
35945 * Returns the panel specified or null if it's not in this region.
35946 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35947 * @return {Roo.ContentPanel}
35949 getPanel : function(id){
35950 if(typeof id == "object"){ // must be panel obj
35953 return this.panels.get(id);
35957 * Returns this regions position (north/south/east/west/center).
35960 getPosition: function(){
35961 return this.position;
35965 * Ext JS Library 1.1.1
35966 * Copyright(c) 2006-2007, Ext JS, LLC.
35968 * Originally Released Under LGPL - original licence link has changed is not relivant.
35971 * <script type="text/javascript">
35975 * @class Roo.bootstrap.layout.Region
35976 * @extends Roo.bootstrap.layout.Basic
35977 * This class represents a region in a layout manager.
35979 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35980 * @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})
35981 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35982 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35983 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35984 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35985 * @cfg {String} title The title for the region (overrides panel titles)
35986 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35987 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35988 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35989 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35990 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35991 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35992 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35993 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35994 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35995 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35997 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35998 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35999 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36000 * @cfg {Number} width For East/West panels
36001 * @cfg {Number} height For North/South panels
36002 * @cfg {Boolean} split To show the splitter
36003 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36005 * @cfg {string} cls Extra CSS classes to add to region
36007 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36008 * @cfg {string} region the region that it inhabits..
36011 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36012 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36014 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36015 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36016 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36018 Roo.bootstrap.layout.Region = function(config)
36020 this.applyConfig(config);
36022 var mgr = config.mgr;
36023 var pos = config.region;
36024 config.skipConfig = true;
36025 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36028 this.onRender(mgr.el);
36031 this.visible = true;
36032 this.collapsed = false;
36033 this.unrendered_panels = [];
36036 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36038 position: '', // set by wrapper (eg. north/south etc..)
36039 unrendered_panels : null, // unrendered panels.
36041 tabPosition : false,
36043 mgr: false, // points to 'Border'
36046 createBody : function(){
36047 /** This region's body element
36048 * @type Roo.Element */
36049 this.bodyEl = this.el.createChild({
36051 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36055 onRender: function(ctr, pos)
36057 var dh = Roo.DomHelper;
36058 /** This region's container element
36059 * @type Roo.Element */
36060 this.el = dh.append(ctr.dom, {
36062 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36064 /** This region's title element
36065 * @type Roo.Element */
36067 this.titleEl = dh.append(this.el.dom, {
36069 unselectable: "on",
36070 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36072 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36073 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36077 this.titleEl.enableDisplayMode();
36078 /** This region's title text element
36079 * @type HTMLElement */
36080 this.titleTextEl = this.titleEl.dom.firstChild;
36081 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36083 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36084 this.closeBtn.enableDisplayMode();
36085 this.closeBtn.on("click", this.closeClicked, this);
36086 this.closeBtn.hide();
36088 this.createBody(this.config);
36089 if(this.config.hideWhenEmpty){
36091 this.on("paneladded", this.validateVisibility, this);
36092 this.on("panelremoved", this.validateVisibility, this);
36094 if(this.autoScroll){
36095 this.bodyEl.setStyle("overflow", "auto");
36097 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36099 //if(c.titlebar !== false){
36100 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36101 this.titleEl.hide();
36103 this.titleEl.show();
36104 if(this.config.title){
36105 this.titleTextEl.innerHTML = this.config.title;
36109 if(this.config.collapsed){
36110 this.collapse(true);
36112 if(this.config.hidden){
36116 if (this.unrendered_panels && this.unrendered_panels.length) {
36117 for (var i =0;i< this.unrendered_panels.length; i++) {
36118 this.add(this.unrendered_panels[i]);
36120 this.unrendered_panels = null;
36126 applyConfig : function(c)
36129 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36130 var dh = Roo.DomHelper;
36131 if(c.titlebar !== false){
36132 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36133 this.collapseBtn.on("click", this.collapse, this);
36134 this.collapseBtn.enableDisplayMode();
36136 if(c.showPin === true || this.showPin){
36137 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36138 this.stickBtn.enableDisplayMode();
36139 this.stickBtn.on("click", this.expand, this);
36140 this.stickBtn.hide();
36145 /** This region's collapsed element
36146 * @type Roo.Element */
36149 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36150 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36153 if(c.floatable !== false){
36154 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36155 this.collapsedEl.on("click", this.collapseClick, this);
36158 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36159 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36160 id: "message", unselectable: "on", style:{"float":"left"}});
36161 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36163 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36164 this.expandBtn.on("click", this.expand, this);
36168 if(this.collapseBtn){
36169 this.collapseBtn.setVisible(c.collapsible == true);
36172 this.cmargins = c.cmargins || this.cmargins ||
36173 (this.position == "west" || this.position == "east" ?
36174 {top: 0, left: 2, right:2, bottom: 0} :
36175 {top: 2, left: 0, right:0, bottom: 2});
36177 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36180 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36182 this.autoScroll = c.autoScroll || false;
36187 this.duration = c.duration || .30;
36188 this.slideDuration = c.slideDuration || .45;
36193 * Returns true if this region is currently visible.
36194 * @return {Boolean}
36196 isVisible : function(){
36197 return this.visible;
36201 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36202 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36204 //setCollapsedTitle : function(title){
36205 // title = title || " ";
36206 // if(this.collapsedTitleTextEl){
36207 // this.collapsedTitleTextEl.innerHTML = title;
36211 getBox : function(){
36213 // if(!this.collapsed){
36214 b = this.el.getBox(false, true);
36216 // b = this.collapsedEl.getBox(false, true);
36221 getMargins : function(){
36222 return this.margins;
36223 //return this.collapsed ? this.cmargins : this.margins;
36226 highlight : function(){
36227 this.el.addClass("x-layout-panel-dragover");
36230 unhighlight : function(){
36231 this.el.removeClass("x-layout-panel-dragover");
36234 updateBox : function(box)
36236 if (!this.bodyEl) {
36237 return; // not rendered yet..
36241 if(!this.collapsed){
36242 this.el.dom.style.left = box.x + "px";
36243 this.el.dom.style.top = box.y + "px";
36244 this.updateBody(box.width, box.height);
36246 this.collapsedEl.dom.style.left = box.x + "px";
36247 this.collapsedEl.dom.style.top = box.y + "px";
36248 this.collapsedEl.setSize(box.width, box.height);
36251 this.tabs.autoSizeTabs();
36255 updateBody : function(w, h)
36258 this.el.setWidth(w);
36259 w -= this.el.getBorderWidth("rl");
36260 if(this.config.adjustments){
36261 w += this.config.adjustments[0];
36264 if(h !== null && h > 0){
36265 this.el.setHeight(h);
36266 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36267 h -= this.el.getBorderWidth("tb");
36268 if(this.config.adjustments){
36269 h += this.config.adjustments[1];
36271 this.bodyEl.setHeight(h);
36273 h = this.tabs.syncHeight(h);
36276 if(this.panelSize){
36277 w = w !== null ? w : this.panelSize.width;
36278 h = h !== null ? h : this.panelSize.height;
36280 if(this.activePanel){
36281 var el = this.activePanel.getEl();
36282 w = w !== null ? w : el.getWidth();
36283 h = h !== null ? h : el.getHeight();
36284 this.panelSize = {width: w, height: h};
36285 this.activePanel.setSize(w, h);
36287 if(Roo.isIE && this.tabs){
36288 this.tabs.el.repaint();
36293 * Returns the container element for this region.
36294 * @return {Roo.Element}
36296 getEl : function(){
36301 * Hides this region.
36304 //if(!this.collapsed){
36305 this.el.dom.style.left = "-2000px";
36308 // this.collapsedEl.dom.style.left = "-2000px";
36309 // this.collapsedEl.hide();
36311 this.visible = false;
36312 this.fireEvent("visibilitychange", this, false);
36316 * Shows this region if it was previously hidden.
36319 //if(!this.collapsed){
36322 // this.collapsedEl.show();
36324 this.visible = true;
36325 this.fireEvent("visibilitychange", this, true);
36328 closeClicked : function(){
36329 if(this.activePanel){
36330 this.remove(this.activePanel);
36334 collapseClick : function(e){
36336 e.stopPropagation();
36339 e.stopPropagation();
36345 * Collapses this region.
36346 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36349 collapse : function(skipAnim, skipCheck = false){
36350 if(this.collapsed) {
36354 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36356 this.collapsed = true;
36358 this.split.el.hide();
36360 if(this.config.animate && skipAnim !== true){
36361 this.fireEvent("invalidated", this);
36362 this.animateCollapse();
36364 this.el.setLocation(-20000,-20000);
36366 this.collapsedEl.show();
36367 this.fireEvent("collapsed", this);
36368 this.fireEvent("invalidated", this);
36374 animateCollapse : function(){
36379 * Expands this region if it was previously collapsed.
36380 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36381 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36384 expand : function(e, skipAnim){
36386 e.stopPropagation();
36388 if(!this.collapsed || this.el.hasActiveFx()) {
36392 this.afterSlideIn();
36395 this.collapsed = false;
36396 if(this.config.animate && skipAnim !== true){
36397 this.animateExpand();
36401 this.split.el.show();
36403 this.collapsedEl.setLocation(-2000,-2000);
36404 this.collapsedEl.hide();
36405 this.fireEvent("invalidated", this);
36406 this.fireEvent("expanded", this);
36410 animateExpand : function(){
36414 initTabs : function()
36416 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36418 var ts = new Roo.bootstrap.panel.Tabs({
36419 el: this.bodyEl.dom,
36421 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36422 disableTooltips: this.config.disableTabTips,
36423 toolbar : this.config.toolbar
36426 if(this.config.hideTabs){
36427 ts.stripWrap.setDisplayed(false);
36430 ts.resizeTabs = this.config.resizeTabs === true;
36431 ts.minTabWidth = this.config.minTabWidth || 40;
36432 ts.maxTabWidth = this.config.maxTabWidth || 250;
36433 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36434 ts.monitorResize = false;
36435 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36436 ts.bodyEl.addClass('roo-layout-tabs-body');
36437 this.panels.each(this.initPanelAsTab, this);
36440 initPanelAsTab : function(panel){
36441 var ti = this.tabs.addTab(
36445 this.config.closeOnTab && panel.isClosable(),
36448 if(panel.tabTip !== undefined){
36449 ti.setTooltip(panel.tabTip);
36451 ti.on("activate", function(){
36452 this.setActivePanel(panel);
36455 if(this.config.closeOnTab){
36456 ti.on("beforeclose", function(t, e){
36458 this.remove(panel);
36462 panel.tabItem = ti;
36467 updatePanelTitle : function(panel, title)
36469 if(this.activePanel == panel){
36470 this.updateTitle(title);
36473 var ti = this.tabs.getTab(panel.getEl().id);
36475 if(panel.tabTip !== undefined){
36476 ti.setTooltip(panel.tabTip);
36481 updateTitle : function(title){
36482 if(this.titleTextEl && !this.config.title){
36483 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36487 setActivePanel : function(panel)
36489 panel = this.getPanel(panel);
36490 if(this.activePanel && this.activePanel != panel){
36491 if(this.activePanel.setActiveState(false) === false){
36495 this.activePanel = panel;
36496 panel.setActiveState(true);
36497 if(this.panelSize){
36498 panel.setSize(this.panelSize.width, this.panelSize.height);
36501 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36503 this.updateTitle(panel.getTitle());
36505 this.fireEvent("invalidated", this);
36507 this.fireEvent("panelactivated", this, panel);
36511 * Shows the specified panel.
36512 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36513 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36515 showPanel : function(panel)
36517 panel = this.getPanel(panel);
36520 var tab = this.tabs.getTab(panel.getEl().id);
36521 if(tab.isHidden()){
36522 this.tabs.unhideTab(tab.id);
36526 this.setActivePanel(panel);
36533 * Get the active panel for this region.
36534 * @return {Roo.ContentPanel} The active panel or null
36536 getActivePanel : function(){
36537 return this.activePanel;
36540 validateVisibility : function(){
36541 if(this.panels.getCount() < 1){
36542 this.updateTitle(" ");
36543 this.closeBtn.hide();
36546 if(!this.isVisible()){
36553 * Adds the passed ContentPanel(s) to this region.
36554 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36555 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36557 add : function(panel)
36559 if(arguments.length > 1){
36560 for(var i = 0, len = arguments.length; i < len; i++) {
36561 this.add(arguments[i]);
36566 // if we have not been rendered yet, then we can not really do much of this..
36567 if (!this.bodyEl) {
36568 this.unrendered_panels.push(panel);
36575 if(this.hasPanel(panel)){
36576 this.showPanel(panel);
36579 panel.setRegion(this);
36580 this.panels.add(panel);
36581 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36582 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36583 // and hide them... ???
36584 this.bodyEl.dom.appendChild(panel.getEl().dom);
36585 if(panel.background !== true){
36586 this.setActivePanel(panel);
36588 this.fireEvent("paneladded", this, panel);
36595 this.initPanelAsTab(panel);
36599 if(panel.background !== true){
36600 this.tabs.activate(panel.getEl().id);
36602 this.fireEvent("paneladded", this, panel);
36607 * Hides the tab for the specified panel.
36608 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36610 hidePanel : function(panel){
36611 if(this.tabs && (panel = this.getPanel(panel))){
36612 this.tabs.hideTab(panel.getEl().id);
36617 * Unhides the tab for a previously hidden panel.
36618 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36620 unhidePanel : function(panel){
36621 if(this.tabs && (panel = this.getPanel(panel))){
36622 this.tabs.unhideTab(panel.getEl().id);
36626 clearPanels : function(){
36627 while(this.panels.getCount() > 0){
36628 this.remove(this.panels.first());
36633 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36634 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36635 * @param {Boolean} preservePanel Overrides the config preservePanel option
36636 * @return {Roo.ContentPanel} The panel that was removed
36638 remove : function(panel, preservePanel)
36640 panel = this.getPanel(panel);
36645 this.fireEvent("beforeremove", this, panel, e);
36646 if(e.cancel === true){
36649 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36650 var panelId = panel.getId();
36651 this.panels.removeKey(panelId);
36653 document.body.appendChild(panel.getEl().dom);
36656 this.tabs.removeTab(panel.getEl().id);
36657 }else if (!preservePanel){
36658 this.bodyEl.dom.removeChild(panel.getEl().dom);
36660 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36661 var p = this.panels.first();
36662 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36663 tempEl.appendChild(p.getEl().dom);
36664 this.bodyEl.update("");
36665 this.bodyEl.dom.appendChild(p.getEl().dom);
36667 this.updateTitle(p.getTitle());
36669 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36670 this.setActivePanel(p);
36672 panel.setRegion(null);
36673 if(this.activePanel == panel){
36674 this.activePanel = null;
36676 if(this.config.autoDestroy !== false && preservePanel !== true){
36677 try{panel.destroy();}catch(e){}
36679 this.fireEvent("panelremoved", this, panel);
36684 * Returns the TabPanel component used by this region
36685 * @return {Roo.TabPanel}
36687 getTabs : function(){
36691 createTool : function(parentEl, className){
36692 var btn = Roo.DomHelper.append(parentEl, {
36694 cls: "x-layout-tools-button",
36697 cls: "roo-layout-tools-button-inner " + className,
36701 btn.addClassOnOver("roo-layout-tools-button-over");
36706 * Ext JS Library 1.1.1
36707 * Copyright(c) 2006-2007, Ext JS, LLC.
36709 * Originally Released Under LGPL - original licence link has changed is not relivant.
36712 * <script type="text/javascript">
36718 * @class Roo.SplitLayoutRegion
36719 * @extends Roo.LayoutRegion
36720 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36722 Roo.bootstrap.layout.Split = function(config){
36723 this.cursor = config.cursor;
36724 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36727 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36729 splitTip : "Drag to resize.",
36730 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36731 useSplitTips : false,
36733 applyConfig : function(config){
36734 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36737 onRender : function(ctr,pos) {
36739 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36740 if(!this.config.split){
36745 var splitEl = Roo.DomHelper.append(ctr.dom, {
36747 id: this.el.id + "-split",
36748 cls: "roo-layout-split roo-layout-split-"+this.position,
36751 /** The SplitBar for this region
36752 * @type Roo.SplitBar */
36753 // does not exist yet...
36754 Roo.log([this.position, this.orientation]);
36756 this.split = new Roo.bootstrap.SplitBar({
36757 dragElement : splitEl,
36758 resizingElement: this.el,
36759 orientation : this.orientation
36762 this.split.on("moved", this.onSplitMove, this);
36763 this.split.useShim = this.config.useShim === true;
36764 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36765 if(this.useSplitTips){
36766 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36768 //if(config.collapsible){
36769 // this.split.el.on("dblclick", this.collapse, this);
36772 if(typeof this.config.minSize != "undefined"){
36773 this.split.minSize = this.config.minSize;
36775 if(typeof this.config.maxSize != "undefined"){
36776 this.split.maxSize = this.config.maxSize;
36778 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36779 this.hideSplitter();
36784 getHMaxSize : function(){
36785 var cmax = this.config.maxSize || 10000;
36786 var center = this.mgr.getRegion("center");
36787 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36790 getVMaxSize : function(){
36791 var cmax = this.config.maxSize || 10000;
36792 var center = this.mgr.getRegion("center");
36793 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36796 onSplitMove : function(split, newSize){
36797 this.fireEvent("resized", this, newSize);
36801 * Returns the {@link Roo.SplitBar} for this region.
36802 * @return {Roo.SplitBar}
36804 getSplitBar : function(){
36809 this.hideSplitter();
36810 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36813 hideSplitter : function(){
36815 this.split.el.setLocation(-2000,-2000);
36816 this.split.el.hide();
36822 this.split.el.show();
36824 Roo.bootstrap.layout.Split.superclass.show.call(this);
36827 beforeSlide: function(){
36828 if(Roo.isGecko){// firefox overflow auto bug workaround
36829 this.bodyEl.clip();
36831 this.tabs.bodyEl.clip();
36833 if(this.activePanel){
36834 this.activePanel.getEl().clip();
36836 if(this.activePanel.beforeSlide){
36837 this.activePanel.beforeSlide();
36843 afterSlide : function(){
36844 if(Roo.isGecko){// firefox overflow auto bug workaround
36845 this.bodyEl.unclip();
36847 this.tabs.bodyEl.unclip();
36849 if(this.activePanel){
36850 this.activePanel.getEl().unclip();
36851 if(this.activePanel.afterSlide){
36852 this.activePanel.afterSlide();
36858 initAutoHide : function(){
36859 if(this.autoHide !== false){
36860 if(!this.autoHideHd){
36861 var st = new Roo.util.DelayedTask(this.slideIn, this);
36862 this.autoHideHd = {
36863 "mouseout": function(e){
36864 if(!e.within(this.el, true)){
36868 "mouseover" : function(e){
36874 this.el.on(this.autoHideHd);
36878 clearAutoHide : function(){
36879 if(this.autoHide !== false){
36880 this.el.un("mouseout", this.autoHideHd.mouseout);
36881 this.el.un("mouseover", this.autoHideHd.mouseover);
36885 clearMonitor : function(){
36886 Roo.get(document).un("click", this.slideInIf, this);
36889 // these names are backwards but not changed for compat
36890 slideOut : function(){
36891 if(this.isSlid || this.el.hasActiveFx()){
36894 this.isSlid = true;
36895 if(this.collapseBtn){
36896 this.collapseBtn.hide();
36898 this.closeBtnState = this.closeBtn.getStyle('display');
36899 this.closeBtn.hide();
36901 this.stickBtn.show();
36904 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36905 this.beforeSlide();
36906 this.el.setStyle("z-index", 10001);
36907 this.el.slideIn(this.getSlideAnchor(), {
36908 callback: function(){
36910 this.initAutoHide();
36911 Roo.get(document).on("click", this.slideInIf, this);
36912 this.fireEvent("slideshow", this);
36919 afterSlideIn : function(){
36920 this.clearAutoHide();
36921 this.isSlid = false;
36922 this.clearMonitor();
36923 this.el.setStyle("z-index", "");
36924 if(this.collapseBtn){
36925 this.collapseBtn.show();
36927 this.closeBtn.setStyle('display', this.closeBtnState);
36929 this.stickBtn.hide();
36931 this.fireEvent("slidehide", this);
36934 slideIn : function(cb){
36935 if(!this.isSlid || this.el.hasActiveFx()){
36939 this.isSlid = false;
36940 this.beforeSlide();
36941 this.el.slideOut(this.getSlideAnchor(), {
36942 callback: function(){
36943 this.el.setLeftTop(-10000, -10000);
36945 this.afterSlideIn();
36953 slideInIf : function(e){
36954 if(!e.within(this.el)){
36959 animateCollapse : function(){
36960 this.beforeSlide();
36961 this.el.setStyle("z-index", 20000);
36962 var anchor = this.getSlideAnchor();
36963 this.el.slideOut(anchor, {
36964 callback : function(){
36965 this.el.setStyle("z-index", "");
36966 this.collapsedEl.slideIn(anchor, {duration:.3});
36968 this.el.setLocation(-10000,-10000);
36970 this.fireEvent("collapsed", this);
36977 animateExpand : function(){
36978 this.beforeSlide();
36979 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36980 this.el.setStyle("z-index", 20000);
36981 this.collapsedEl.hide({
36984 this.el.slideIn(this.getSlideAnchor(), {
36985 callback : function(){
36986 this.el.setStyle("z-index", "");
36989 this.split.el.show();
36991 this.fireEvent("invalidated", this);
36992 this.fireEvent("expanded", this);
37020 getAnchor : function(){
37021 return this.anchors[this.position];
37024 getCollapseAnchor : function(){
37025 return this.canchors[this.position];
37028 getSlideAnchor : function(){
37029 return this.sanchors[this.position];
37032 getAlignAdj : function(){
37033 var cm = this.cmargins;
37034 switch(this.position){
37050 getExpandAdj : function(){
37051 var c = this.collapsedEl, cm = this.cmargins;
37052 switch(this.position){
37054 return [-(cm.right+c.getWidth()+cm.left), 0];
37057 return [cm.right+c.getWidth()+cm.left, 0];
37060 return [0, -(cm.top+cm.bottom+c.getHeight())];
37063 return [0, cm.top+cm.bottom+c.getHeight()];
37069 * Ext JS Library 1.1.1
37070 * Copyright(c) 2006-2007, Ext JS, LLC.
37072 * Originally Released Under LGPL - original licence link has changed is not relivant.
37075 * <script type="text/javascript">
37078 * These classes are private internal classes
37080 Roo.bootstrap.layout.Center = function(config){
37081 config.region = "center";
37082 Roo.bootstrap.layout.Region.call(this, config);
37083 this.visible = true;
37084 this.minWidth = config.minWidth || 20;
37085 this.minHeight = config.minHeight || 20;
37088 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37090 // center panel can't be hidden
37094 // center panel can't be hidden
37097 getMinWidth: function(){
37098 return this.minWidth;
37101 getMinHeight: function(){
37102 return this.minHeight;
37116 Roo.bootstrap.layout.North = function(config)
37118 config.region = 'north';
37119 config.cursor = 'n-resize';
37121 Roo.bootstrap.layout.Split.call(this, config);
37125 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37126 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37127 this.split.el.addClass("roo-layout-split-v");
37129 var size = config.initialSize || config.height;
37130 if(typeof size != "undefined"){
37131 this.el.setHeight(size);
37134 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37136 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37140 getBox : function(){
37141 if(this.collapsed){
37142 return this.collapsedEl.getBox();
37144 var box = this.el.getBox();
37146 box.height += this.split.el.getHeight();
37151 updateBox : function(box){
37152 if(this.split && !this.collapsed){
37153 box.height -= this.split.el.getHeight();
37154 this.split.el.setLeft(box.x);
37155 this.split.el.setTop(box.y+box.height);
37156 this.split.el.setWidth(box.width);
37158 if(this.collapsed){
37159 this.updateBody(box.width, null);
37161 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37169 Roo.bootstrap.layout.South = function(config){
37170 config.region = 'south';
37171 config.cursor = 's-resize';
37172 Roo.bootstrap.layout.Split.call(this, config);
37174 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37175 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37176 this.split.el.addClass("roo-layout-split-v");
37178 var size = config.initialSize || config.height;
37179 if(typeof size != "undefined"){
37180 this.el.setHeight(size);
37184 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37185 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37186 getBox : function(){
37187 if(this.collapsed){
37188 return this.collapsedEl.getBox();
37190 var box = this.el.getBox();
37192 var sh = this.split.el.getHeight();
37199 updateBox : function(box){
37200 if(this.split && !this.collapsed){
37201 var sh = this.split.el.getHeight();
37204 this.split.el.setLeft(box.x);
37205 this.split.el.setTop(box.y-sh);
37206 this.split.el.setWidth(box.width);
37208 if(this.collapsed){
37209 this.updateBody(box.width, null);
37211 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37215 Roo.bootstrap.layout.East = function(config){
37216 config.region = "east";
37217 config.cursor = "e-resize";
37218 Roo.bootstrap.layout.Split.call(this, config);
37220 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37221 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37222 this.split.el.addClass("roo-layout-split-h");
37224 var size = config.initialSize || config.width;
37225 if(typeof size != "undefined"){
37226 this.el.setWidth(size);
37229 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37230 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37231 getBox : function(){
37232 if(this.collapsed){
37233 return this.collapsedEl.getBox();
37235 var box = this.el.getBox();
37237 var sw = this.split.el.getWidth();
37244 updateBox : function(box){
37245 if(this.split && !this.collapsed){
37246 var sw = this.split.el.getWidth();
37248 this.split.el.setLeft(box.x);
37249 this.split.el.setTop(box.y);
37250 this.split.el.setHeight(box.height);
37253 if(this.collapsed){
37254 this.updateBody(null, box.height);
37256 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37260 Roo.bootstrap.layout.West = function(config){
37261 config.region = "west";
37262 config.cursor = "w-resize";
37264 Roo.bootstrap.layout.Split.call(this, config);
37266 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37267 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37268 this.split.el.addClass("roo-layout-split-h");
37272 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37273 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37275 onRender: function(ctr, pos)
37277 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37278 var size = this.config.initialSize || this.config.width;
37279 if(typeof size != "undefined"){
37280 this.el.setWidth(size);
37284 getBox : function(){
37285 if(this.collapsed){
37286 return this.collapsedEl.getBox();
37288 var box = this.el.getBox();
37290 box.width += this.split.el.getWidth();
37295 updateBox : function(box){
37296 if(this.split && !this.collapsed){
37297 var sw = this.split.el.getWidth();
37299 this.split.el.setLeft(box.x+box.width);
37300 this.split.el.setTop(box.y);
37301 this.split.el.setHeight(box.height);
37303 if(this.collapsed){
37304 this.updateBody(null, box.height);
37306 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37308 });Roo.namespace("Roo.bootstrap.panel");/*
37310 * Ext JS Library 1.1.1
37311 * Copyright(c) 2006-2007, Ext JS, LLC.
37313 * Originally Released Under LGPL - original licence link has changed is not relivant.
37316 * <script type="text/javascript">
37319 * @class Roo.ContentPanel
37320 * @extends Roo.util.Observable
37321 * A basic ContentPanel element.
37322 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37323 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37324 * @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
37325 * @cfg {Boolean} closable True if the panel can be closed/removed
37326 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37327 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37328 * @cfg {Toolbar} toolbar A toolbar for this panel
37329 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37330 * @cfg {String} title The title for this panel
37331 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37332 * @cfg {String} url Calls {@link #setUrl} with this value
37333 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37334 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37335 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37336 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37337 * @cfg {Boolean} badges render the badges
37340 * Create a new ContentPanel.
37341 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37342 * @param {String/Object} config A string to set only the title or a config object
37343 * @param {String} content (optional) Set the HTML content for this panel
37344 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37346 Roo.bootstrap.panel.Content = function( config){
37348 this.tpl = config.tpl || false;
37350 var el = config.el;
37351 var content = config.content;
37353 if(config.autoCreate){ // xtype is available if this is called from factory
37356 this.el = Roo.get(el);
37357 if(!this.el && config && config.autoCreate){
37358 if(typeof config.autoCreate == "object"){
37359 if(!config.autoCreate.id){
37360 config.autoCreate.id = config.id||el;
37362 this.el = Roo.DomHelper.append(document.body,
37363 config.autoCreate, true);
37365 var elcfg = { tag: "div",
37366 cls: "roo-layout-inactive-content",
37370 elcfg.html = config.html;
37374 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37377 this.closable = false;
37378 this.loaded = false;
37379 this.active = false;
37382 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37384 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37386 this.wrapEl = this.el; //this.el.wrap();
37388 if (config.toolbar.items) {
37389 ti = config.toolbar.items ;
37390 delete config.toolbar.items ;
37394 this.toolbar.render(this.wrapEl, 'before');
37395 for(var i =0;i < ti.length;i++) {
37396 // Roo.log(['add child', items[i]]);
37397 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37399 this.toolbar.items = nitems;
37400 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37401 delete config.toolbar;
37405 // xtype created footer. - not sure if will work as we normally have to render first..
37406 if (this.footer && !this.footer.el && this.footer.xtype) {
37407 if (!this.wrapEl) {
37408 this.wrapEl = this.el.wrap();
37411 this.footer.container = this.wrapEl.createChild();
37413 this.footer = Roo.factory(this.footer, Roo);
37418 if(typeof config == "string"){
37419 this.title = config;
37421 Roo.apply(this, config);
37425 this.resizeEl = Roo.get(this.resizeEl, true);
37427 this.resizeEl = this.el;
37429 // handle view.xtype
37437 * Fires when this panel is activated.
37438 * @param {Roo.ContentPanel} this
37442 * @event deactivate
37443 * Fires when this panel is activated.
37444 * @param {Roo.ContentPanel} this
37446 "deactivate" : true,
37450 * Fires when this panel is resized if fitToFrame is true.
37451 * @param {Roo.ContentPanel} this
37452 * @param {Number} width The width after any component adjustments
37453 * @param {Number} height The height after any component adjustments
37459 * Fires when this tab is created
37460 * @param {Roo.ContentPanel} this
37471 if(this.autoScroll){
37472 this.resizeEl.setStyle("overflow", "auto");
37474 // fix randome scrolling
37475 //this.el.on('scroll', function() {
37476 // Roo.log('fix random scolling');
37477 // this.scrollTo('top',0);
37480 content = content || this.content;
37482 this.setContent(content);
37484 if(config && config.url){
37485 this.setUrl(this.url, this.params, this.loadOnce);
37490 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37492 if (this.view && typeof(this.view.xtype) != 'undefined') {
37493 this.view.el = this.el.appendChild(document.createElement("div"));
37494 this.view = Roo.factory(this.view);
37495 this.view.render && this.view.render(false, '');
37499 this.fireEvent('render', this);
37502 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37506 setRegion : function(region){
37507 this.region = region;
37508 this.setActiveClass(region && !this.background);
37512 setActiveClass: function(state)
37515 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37516 this.el.setStyle('position','relative');
37518 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37519 this.el.setStyle('position', 'absolute');
37524 * Returns the toolbar for this Panel if one was configured.
37525 * @return {Roo.Toolbar}
37527 getToolbar : function(){
37528 return this.toolbar;
37531 setActiveState : function(active)
37533 this.active = active;
37534 this.setActiveClass(active);
37536 if(this.fireEvent("deactivate", this) === false){
37541 this.fireEvent("activate", this);
37545 * Updates this panel's element
37546 * @param {String} content The new content
37547 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37549 setContent : function(content, loadScripts){
37550 this.el.update(content, loadScripts);
37553 ignoreResize : function(w, h){
37554 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37557 this.lastSize = {width: w, height: h};
37562 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37563 * @return {Roo.UpdateManager} The UpdateManager
37565 getUpdateManager : function(){
37566 return this.el.getUpdateManager();
37569 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37570 * @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:
37573 url: "your-url.php",
37574 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37575 callback: yourFunction,
37576 scope: yourObject, //(optional scope)
37579 text: "Loading...",
37584 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37585 * 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.
37586 * @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}
37587 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37588 * @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.
37589 * @return {Roo.ContentPanel} this
37592 var um = this.el.getUpdateManager();
37593 um.update.apply(um, arguments);
37599 * 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.
37600 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37601 * @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)
37602 * @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)
37603 * @return {Roo.UpdateManager} The UpdateManager
37605 setUrl : function(url, params, loadOnce){
37606 if(this.refreshDelegate){
37607 this.removeListener("activate", this.refreshDelegate);
37609 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37610 this.on("activate", this.refreshDelegate);
37611 return this.el.getUpdateManager();
37614 _handleRefresh : function(url, params, loadOnce){
37615 if(!loadOnce || !this.loaded){
37616 var updater = this.el.getUpdateManager();
37617 updater.update(url, params, this._setLoaded.createDelegate(this));
37621 _setLoaded : function(){
37622 this.loaded = true;
37626 * Returns this panel's id
37629 getId : function(){
37634 * Returns this panel's element - used by regiosn to add.
37635 * @return {Roo.Element}
37637 getEl : function(){
37638 return this.wrapEl || this.el;
37643 adjustForComponents : function(width, height)
37645 //Roo.log('adjustForComponents ');
37646 if(this.resizeEl != this.el){
37647 width -= this.el.getFrameWidth('lr');
37648 height -= this.el.getFrameWidth('tb');
37651 var te = this.toolbar.getEl();
37652 te.setWidth(width);
37653 height -= te.getHeight();
37656 var te = this.footer.getEl();
37657 te.setWidth(width);
37658 height -= te.getHeight();
37662 if(this.adjustments){
37663 width += this.adjustments[0];
37664 height += this.adjustments[1];
37666 return {"width": width, "height": height};
37669 setSize : function(width, height){
37670 if(this.fitToFrame && !this.ignoreResize(width, height)){
37671 if(this.fitContainer && this.resizeEl != this.el){
37672 this.el.setSize(width, height);
37674 var size = this.adjustForComponents(width, height);
37675 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37676 this.fireEvent('resize', this, size.width, size.height);
37681 * Returns this panel's title
37684 getTitle : function(){
37686 if (typeof(this.title) != 'object') {
37691 for (var k in this.title) {
37692 if (!this.title.hasOwnProperty(k)) {
37696 if (k.indexOf('-') >= 0) {
37697 var s = k.split('-');
37698 for (var i = 0; i<s.length; i++) {
37699 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37702 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37709 * Set this panel's title
37710 * @param {String} title
37712 setTitle : function(title){
37713 this.title = title;
37715 this.region.updatePanelTitle(this, title);
37720 * Returns true is this panel was configured to be closable
37721 * @return {Boolean}
37723 isClosable : function(){
37724 return this.closable;
37727 beforeSlide : function(){
37729 this.resizeEl.clip();
37732 afterSlide : function(){
37734 this.resizeEl.unclip();
37738 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37739 * Will fail silently if the {@link #setUrl} method has not been called.
37740 * This does not activate the panel, just updates its content.
37742 refresh : function(){
37743 if(this.refreshDelegate){
37744 this.loaded = false;
37745 this.refreshDelegate();
37750 * Destroys this panel
37752 destroy : function(){
37753 this.el.removeAllListeners();
37754 var tempEl = document.createElement("span");
37755 tempEl.appendChild(this.el.dom);
37756 tempEl.innerHTML = "";
37762 * form - if the content panel contains a form - this is a reference to it.
37763 * @type {Roo.form.Form}
37767 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37768 * This contains a reference to it.
37774 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37784 * @param {Object} cfg Xtype definition of item to add.
37788 getChildContainer: function () {
37789 return this.getEl();
37794 var ret = new Roo.factory(cfg);
37799 if (cfg.xtype.match(/^Form$/)) {
37802 //if (this.footer) {
37803 // el = this.footer.container.insertSibling(false, 'before');
37805 el = this.el.createChild();
37808 this.form = new Roo.form.Form(cfg);
37811 if ( this.form.allItems.length) {
37812 this.form.render(el.dom);
37816 // should only have one of theses..
37817 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37818 // views.. should not be just added - used named prop 'view''
37820 cfg.el = this.el.appendChild(document.createElement("div"));
37823 var ret = new Roo.factory(cfg);
37825 ret.render && ret.render(false, ''); // render blank..
37835 * @class Roo.bootstrap.panel.Grid
37836 * @extends Roo.bootstrap.panel.Content
37838 * Create a new GridPanel.
37839 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37840 * @param {Object} config A the config object
37846 Roo.bootstrap.panel.Grid = function(config)
37850 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37851 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37853 config.el = this.wrapper;
37854 //this.el = this.wrapper;
37856 if (config.container) {
37857 // ctor'ed from a Border/panel.grid
37860 this.wrapper.setStyle("overflow", "hidden");
37861 this.wrapper.addClass('roo-grid-container');
37866 if(config.toolbar){
37867 var tool_el = this.wrapper.createChild();
37868 this.toolbar = Roo.factory(config.toolbar);
37870 if (config.toolbar.items) {
37871 ti = config.toolbar.items ;
37872 delete config.toolbar.items ;
37876 this.toolbar.render(tool_el);
37877 for(var i =0;i < ti.length;i++) {
37878 // Roo.log(['add child', items[i]]);
37879 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37881 this.toolbar.items = nitems;
37883 delete config.toolbar;
37886 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37887 config.grid.scrollBody = true;;
37888 config.grid.monitorWindowResize = false; // turn off autosizing
37889 config.grid.autoHeight = false;
37890 config.grid.autoWidth = false;
37892 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37894 if (config.background) {
37895 // render grid on panel activation (if panel background)
37896 this.on('activate', function(gp) {
37897 if (!gp.grid.rendered) {
37898 gp.grid.render(this.wrapper);
37899 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37904 this.grid.render(this.wrapper);
37905 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37908 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37909 // ??? needed ??? config.el = this.wrapper;
37914 // xtype created footer. - not sure if will work as we normally have to render first..
37915 if (this.footer && !this.footer.el && this.footer.xtype) {
37917 var ctr = this.grid.getView().getFooterPanel(true);
37918 this.footer.dataSource = this.grid.dataSource;
37919 this.footer = Roo.factory(this.footer, Roo);
37920 this.footer.render(ctr);
37930 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37931 getId : function(){
37932 return this.grid.id;
37936 * Returns the grid for this panel
37937 * @return {Roo.bootstrap.Table}
37939 getGrid : function(){
37943 setSize : function(width, height){
37944 if(!this.ignoreResize(width, height)){
37945 var grid = this.grid;
37946 var size = this.adjustForComponents(width, height);
37947 var gridel = grid.getGridEl();
37948 gridel.setSize(size.width, size.height);
37950 var thd = grid.getGridEl().select('thead',true).first();
37951 var tbd = grid.getGridEl().select('tbody', true).first();
37953 tbd.setSize(width, height - thd.getHeight());
37962 beforeSlide : function(){
37963 this.grid.getView().scroller.clip();
37966 afterSlide : function(){
37967 this.grid.getView().scroller.unclip();
37970 destroy : function(){
37971 this.grid.destroy();
37973 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37978 * @class Roo.bootstrap.panel.Nest
37979 * @extends Roo.bootstrap.panel.Content
37981 * Create a new Panel, that can contain a layout.Border.
37984 * @param {Roo.BorderLayout} layout The layout for this panel
37985 * @param {String/Object} config A string to set only the title or a config object
37987 Roo.bootstrap.panel.Nest = function(config)
37989 // construct with only one argument..
37990 /* FIXME - implement nicer consturctors
37991 if (layout.layout) {
37993 layout = config.layout;
37994 delete config.layout;
37996 if (layout.xtype && !layout.getEl) {
37997 // then layout needs constructing..
37998 layout = Roo.factory(layout, Roo);
38002 config.el = config.layout.getEl();
38004 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38006 config.layout.monitorWindowResize = false; // turn off autosizing
38007 this.layout = config.layout;
38008 this.layout.getEl().addClass("roo-layout-nested-layout");
38009 this.layout.parent = this;
38016 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38018 setSize : function(width, height){
38019 if(!this.ignoreResize(width, height)){
38020 var size = this.adjustForComponents(width, height);
38021 var el = this.layout.getEl();
38022 if (size.height < 1) {
38023 el.setWidth(size.width);
38025 el.setSize(size.width, size.height);
38027 var touch = el.dom.offsetWidth;
38028 this.layout.layout();
38029 // ie requires a double layout on the first pass
38030 if(Roo.isIE && !this.initialized){
38031 this.initialized = true;
38032 this.layout.layout();
38037 // activate all subpanels if not currently active..
38039 setActiveState : function(active){
38040 this.active = active;
38041 this.setActiveClass(active);
38044 this.fireEvent("deactivate", this);
38048 this.fireEvent("activate", this);
38049 // not sure if this should happen before or after..
38050 if (!this.layout) {
38051 return; // should not happen..
38054 for (var r in this.layout.regions) {
38055 reg = this.layout.getRegion(r);
38056 if (reg.getActivePanel()) {
38057 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38058 reg.setActivePanel(reg.getActivePanel());
38061 if (!reg.panels.length) {
38064 reg.showPanel(reg.getPanel(0));
38073 * Returns the nested BorderLayout for this panel
38074 * @return {Roo.BorderLayout}
38076 getLayout : function(){
38077 return this.layout;
38081 * Adds a xtype elements to the layout of the nested panel
38085 xtype : 'ContentPanel',
38092 xtype : 'NestedLayoutPanel',
38098 items : [ ... list of content panels or nested layout panels.. ]
38102 * @param {Object} cfg Xtype definition of item to add.
38104 addxtype : function(cfg) {
38105 return this.layout.addxtype(cfg);
38110 * Ext JS Library 1.1.1
38111 * Copyright(c) 2006-2007, Ext JS, LLC.
38113 * Originally Released Under LGPL - original licence link has changed is not relivant.
38116 * <script type="text/javascript">
38119 * @class Roo.TabPanel
38120 * @extends Roo.util.Observable
38121 * A lightweight tab container.
38125 // basic tabs 1, built from existing content
38126 var tabs = new Roo.TabPanel("tabs1");
38127 tabs.addTab("script", "View Script");
38128 tabs.addTab("markup", "View Markup");
38129 tabs.activate("script");
38131 // more advanced tabs, built from javascript
38132 var jtabs = new Roo.TabPanel("jtabs");
38133 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38135 // set up the UpdateManager
38136 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38137 var updater = tab2.getUpdateManager();
38138 updater.setDefaultUrl("ajax1.htm");
38139 tab2.on('activate', updater.refresh, updater, true);
38141 // Use setUrl for Ajax loading
38142 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38143 tab3.setUrl("ajax2.htm", null, true);
38146 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38149 jtabs.activate("jtabs-1");
38152 * Create a new TabPanel.
38153 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38154 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38156 Roo.bootstrap.panel.Tabs = function(config){
38158 * The container element for this TabPanel.
38159 * @type Roo.Element
38161 this.el = Roo.get(config.el);
38164 if(typeof config == "boolean"){
38165 this.tabPosition = config ? "bottom" : "top";
38167 Roo.apply(this, config);
38171 if(this.tabPosition == "bottom"){
38172 // if tabs are at the bottom = create the body first.
38173 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38174 this.el.addClass("roo-tabs-bottom");
38176 // next create the tabs holders
38178 if (this.tabPosition == "west"){
38180 var reg = this.region; // fake it..
38182 if (!reg.mgr.parent) {
38185 reg = reg.mgr.parent.region;
38187 Roo.log("got nest?");
38189 if (reg.mgr.getRegion('west')) {
38190 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38191 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38192 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38193 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38194 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38202 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38203 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38204 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38205 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38210 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38213 // finally - if tabs are at the top, then create the body last..
38214 if(this.tabPosition != "bottom"){
38215 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38216 * @type Roo.Element
38218 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38219 this.el.addClass("roo-tabs-top");
38223 this.bodyEl.setStyle("position", "relative");
38225 this.active = null;
38226 this.activateDelegate = this.activate.createDelegate(this);
38231 * Fires when the active tab changes
38232 * @param {Roo.TabPanel} this
38233 * @param {Roo.TabPanelItem} activePanel The new active tab
38237 * @event beforetabchange
38238 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38239 * @param {Roo.TabPanel} this
38240 * @param {Object} e Set cancel to true on this object to cancel the tab change
38241 * @param {Roo.TabPanelItem} tab The tab being changed to
38243 "beforetabchange" : true
38246 Roo.EventManager.onWindowResize(this.onResize, this);
38247 this.cpad = this.el.getPadding("lr");
38248 this.hiddenCount = 0;
38251 // toolbar on the tabbar support...
38252 if (this.toolbar) {
38253 alert("no toolbar support yet");
38254 this.toolbar = false;
38256 var tcfg = this.toolbar;
38257 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38258 this.toolbar = new Roo.Toolbar(tcfg);
38259 if (Roo.isSafari) {
38260 var tbl = tcfg.container.child('table', true);
38261 tbl.setAttribute('width', '100%');
38269 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38272 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38274 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38276 tabPosition : "top",
38278 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38280 currentTabWidth : 0,
38282 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38286 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38290 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38292 preferredTabWidth : 175,
38294 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38296 resizeTabs : false,
38298 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38300 monitorResize : true,
38302 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38304 toolbar : false, // set by caller..
38306 region : false, /// set by caller
38308 disableTooltips : true, // not used yet...
38311 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38312 * @param {String} id The id of the div to use <b>or create</b>
38313 * @param {String} text The text for the tab
38314 * @param {String} content (optional) Content to put in the TabPanelItem body
38315 * @param {Boolean} closable (optional) True to create a close icon on the tab
38316 * @return {Roo.TabPanelItem} The created TabPanelItem
38318 addTab : function(id, text, content, closable, tpl)
38320 var item = new Roo.bootstrap.panel.TabItem({
38324 closable : closable,
38327 this.addTabItem(item);
38329 item.setContent(content);
38335 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38336 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38337 * @return {Roo.TabPanelItem}
38339 getTab : function(id){
38340 return this.items[id];
38344 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38345 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38347 hideTab : function(id){
38348 var t = this.items[id];
38351 this.hiddenCount++;
38352 this.autoSizeTabs();
38357 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38358 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38360 unhideTab : function(id){
38361 var t = this.items[id];
38363 t.setHidden(false);
38364 this.hiddenCount--;
38365 this.autoSizeTabs();
38370 * Adds an existing {@link Roo.TabPanelItem}.
38371 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38373 addTabItem : function(item)
38375 this.items[item.id] = item;
38376 this.items.push(item);
38377 this.autoSizeTabs();
38378 // if(this.resizeTabs){
38379 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38380 // this.autoSizeTabs();
38382 // item.autoSize();
38387 * Removes a {@link Roo.TabPanelItem}.
38388 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38390 removeTab : function(id){
38391 var items = this.items;
38392 var tab = items[id];
38393 if(!tab) { return; }
38394 var index = items.indexOf(tab);
38395 if(this.active == tab && items.length > 1){
38396 var newTab = this.getNextAvailable(index);
38401 this.stripEl.dom.removeChild(tab.pnode.dom);
38402 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38403 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38405 items.splice(index, 1);
38406 delete this.items[tab.id];
38407 tab.fireEvent("close", tab);
38408 tab.purgeListeners();
38409 this.autoSizeTabs();
38412 getNextAvailable : function(start){
38413 var items = this.items;
38415 // look for a next tab that will slide over to
38416 // replace the one being removed
38417 while(index < items.length){
38418 var item = items[++index];
38419 if(item && !item.isHidden()){
38423 // if one isn't found select the previous tab (on the left)
38426 var item = items[--index];
38427 if(item && !item.isHidden()){
38435 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38436 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38438 disableTab : function(id){
38439 var tab = this.items[id];
38440 if(tab && this.active != tab){
38446 * Enables a {@link Roo.TabPanelItem} that is disabled.
38447 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38449 enableTab : function(id){
38450 var tab = this.items[id];
38455 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38456 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38457 * @return {Roo.TabPanelItem} The TabPanelItem.
38459 activate : function(id)
38461 //Roo.log('activite:' + id);
38463 var tab = this.items[id];
38467 if(tab == this.active || tab.disabled){
38471 this.fireEvent("beforetabchange", this, e, tab);
38472 if(e.cancel !== true && !tab.disabled){
38474 this.active.hide();
38476 this.active = this.items[id];
38477 this.active.show();
38478 this.fireEvent("tabchange", this, this.active);
38484 * Gets the active {@link Roo.TabPanelItem}.
38485 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38487 getActiveTab : function(){
38488 return this.active;
38492 * Updates the tab body element to fit the height of the container element
38493 * for overflow scrolling
38494 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38496 syncHeight : function(targetHeight){
38497 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38498 var bm = this.bodyEl.getMargins();
38499 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38500 this.bodyEl.setHeight(newHeight);
38504 onResize : function(){
38505 if(this.monitorResize){
38506 this.autoSizeTabs();
38511 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38513 beginUpdate : function(){
38514 this.updating = true;
38518 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38520 endUpdate : function(){
38521 this.updating = false;
38522 this.autoSizeTabs();
38526 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38528 autoSizeTabs : function()
38530 var count = this.items.length;
38531 var vcount = count - this.hiddenCount;
38534 this.stripEl.hide();
38536 this.stripEl.show();
38539 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38544 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38545 var availWidth = Math.floor(w / vcount);
38546 var b = this.stripBody;
38547 if(b.getWidth() > w){
38548 var tabs = this.items;
38549 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38550 if(availWidth < this.minTabWidth){
38551 /*if(!this.sleft){ // incomplete scrolling code
38552 this.createScrollButtons();
38555 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38558 if(this.currentTabWidth < this.preferredTabWidth){
38559 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38565 * Returns the number of tabs in this TabPanel.
38568 getCount : function(){
38569 return this.items.length;
38573 * Resizes all the tabs to the passed width
38574 * @param {Number} The new width
38576 setTabWidth : function(width){
38577 this.currentTabWidth = width;
38578 for(var i = 0, len = this.items.length; i < len; i++) {
38579 if(!this.items[i].isHidden()) {
38580 this.items[i].setWidth(width);
38586 * Destroys this TabPanel
38587 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38589 destroy : function(removeEl){
38590 Roo.EventManager.removeResizeListener(this.onResize, this);
38591 for(var i = 0, len = this.items.length; i < len; i++){
38592 this.items[i].purgeListeners();
38594 if(removeEl === true){
38595 this.el.update("");
38600 createStrip : function(container)
38602 var strip = document.createElement("nav");
38603 strip.className = Roo.bootstrap.version == 4 ?
38604 "navbar-light bg-light" :
38605 "navbar navbar-default"; //"x-tabs-wrap";
38606 container.appendChild(strip);
38610 createStripList : function(strip)
38612 // div wrapper for retard IE
38613 // returns the "tr" element.
38614 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38615 //'<div class="x-tabs-strip-wrap">'+
38616 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38617 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38618 return strip.firstChild; //.firstChild.firstChild.firstChild;
38620 createBody : function(container)
38622 var body = document.createElement("div");
38623 Roo.id(body, "tab-body");
38624 //Roo.fly(body).addClass("x-tabs-body");
38625 Roo.fly(body).addClass("tab-content");
38626 container.appendChild(body);
38629 createItemBody :function(bodyEl, id){
38630 var body = Roo.getDom(id);
38632 body = document.createElement("div");
38635 //Roo.fly(body).addClass("x-tabs-item-body");
38636 Roo.fly(body).addClass("tab-pane");
38637 bodyEl.insertBefore(body, bodyEl.firstChild);
38641 createStripElements : function(stripEl, text, closable, tpl)
38643 var td = document.createElement("li"); // was td..
38644 td.className = 'nav-item';
38646 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38649 stripEl.appendChild(td);
38651 td.className = "x-tabs-closable";
38652 if(!this.closeTpl){
38653 this.closeTpl = new Roo.Template(
38654 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38655 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38656 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38659 var el = this.closeTpl.overwrite(td, {"text": text});
38660 var close = el.getElementsByTagName("div")[0];
38661 var inner = el.getElementsByTagName("em")[0];
38662 return {"el": el, "close": close, "inner": inner};
38665 // not sure what this is..
38666 // if(!this.tabTpl){
38667 //this.tabTpl = new Roo.Template(
38668 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38669 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38671 // this.tabTpl = new Roo.Template(
38672 // '<a href="#">' +
38673 // '<span unselectable="on"' +
38674 // (this.disableTooltips ? '' : ' title="{text}"') +
38675 // ' >{text}</span></a>'
38681 var template = tpl || this.tabTpl || false;
38684 template = new Roo.Template(
38685 Roo.bootstrap.version == 4 ?
38687 '<a class="nav-link" href="#" unselectable="on"' +
38688 (this.disableTooltips ? '' : ' title="{text}"') +
38691 '<a class="nav-link" href="#">' +
38692 '<span unselectable="on"' +
38693 (this.disableTooltips ? '' : ' title="{text}"') +
38694 ' >{text}</span></a>'
38699 switch (typeof(template)) {
38703 template = new Roo.Template(template);
38709 var el = template.overwrite(td, {"text": text});
38711 var inner = el.getElementsByTagName("span")[0];
38713 return {"el": el, "inner": inner};
38721 * @class Roo.TabPanelItem
38722 * @extends Roo.util.Observable
38723 * Represents an individual item (tab plus body) in a TabPanel.
38724 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38725 * @param {String} id The id of this TabPanelItem
38726 * @param {String} text The text for the tab of this TabPanelItem
38727 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38729 Roo.bootstrap.panel.TabItem = function(config){
38731 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38732 * @type Roo.TabPanel
38734 this.tabPanel = config.panel;
38736 * The id for this TabPanelItem
38739 this.id = config.id;
38741 this.disabled = false;
38743 this.text = config.text;
38745 this.loaded = false;
38746 this.closable = config.closable;
38749 * The body element for this TabPanelItem.
38750 * @type Roo.Element
38752 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38753 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38754 this.bodyEl.setStyle("display", "block");
38755 this.bodyEl.setStyle("zoom", "1");
38756 //this.hideAction();
38758 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38760 this.el = Roo.get(els.el);
38761 this.inner = Roo.get(els.inner, true);
38762 this.textEl = Roo.bootstrap.version == 4 ?
38763 this.el : Roo.get(this.el.dom.firstChild, true);
38765 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38766 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38769 // this.el.on("mousedown", this.onTabMouseDown, this);
38770 this.el.on("click", this.onTabClick, this);
38772 if(config.closable){
38773 var c = Roo.get(els.close, true);
38774 c.dom.title = this.closeText;
38775 c.addClassOnOver("close-over");
38776 c.on("click", this.closeClick, this);
38782 * Fires when this tab becomes the active tab.
38783 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38784 * @param {Roo.TabPanelItem} this
38788 * @event beforeclose
38789 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38790 * @param {Roo.TabPanelItem} this
38791 * @param {Object} e Set cancel to true on this object to cancel the close.
38793 "beforeclose": true,
38796 * Fires when this tab is closed.
38797 * @param {Roo.TabPanelItem} this
38801 * @event deactivate
38802 * Fires when this tab is no longer the active tab.
38803 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38804 * @param {Roo.TabPanelItem} this
38806 "deactivate" : true
38808 this.hidden = false;
38810 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38813 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38815 purgeListeners : function(){
38816 Roo.util.Observable.prototype.purgeListeners.call(this);
38817 this.el.removeAllListeners();
38820 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38823 this.status_node.addClass("active");
38826 this.tabPanel.stripWrap.repaint();
38828 this.fireEvent("activate", this.tabPanel, this);
38832 * Returns true if this tab is the active tab.
38833 * @return {Boolean}
38835 isActive : function(){
38836 return this.tabPanel.getActiveTab() == this;
38840 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38843 this.status_node.removeClass("active");
38845 this.fireEvent("deactivate", this.tabPanel, this);
38848 hideAction : function(){
38849 this.bodyEl.hide();
38850 this.bodyEl.setStyle("position", "absolute");
38851 this.bodyEl.setLeft("-20000px");
38852 this.bodyEl.setTop("-20000px");
38855 showAction : function(){
38856 this.bodyEl.setStyle("position", "relative");
38857 this.bodyEl.setTop("");
38858 this.bodyEl.setLeft("");
38859 this.bodyEl.show();
38863 * Set the tooltip for the tab.
38864 * @param {String} tooltip The tab's tooltip
38866 setTooltip : function(text){
38867 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38868 this.textEl.dom.qtip = text;
38869 this.textEl.dom.removeAttribute('title');
38871 this.textEl.dom.title = text;
38875 onTabClick : function(e){
38876 e.preventDefault();
38877 this.tabPanel.activate(this.id);
38880 onTabMouseDown : function(e){
38881 e.preventDefault();
38882 this.tabPanel.activate(this.id);
38885 getWidth : function(){
38886 return this.inner.getWidth();
38889 setWidth : function(width){
38890 var iwidth = width - this.linode.getPadding("lr");
38891 this.inner.setWidth(iwidth);
38892 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38893 this.linode.setWidth(width);
38897 * Show or hide the tab
38898 * @param {Boolean} hidden True to hide or false to show.
38900 setHidden : function(hidden){
38901 this.hidden = hidden;
38902 this.linode.setStyle("display", hidden ? "none" : "");
38906 * Returns true if this tab is "hidden"
38907 * @return {Boolean}
38909 isHidden : function(){
38910 return this.hidden;
38914 * Returns the text for this tab
38917 getText : function(){
38921 autoSize : function(){
38922 //this.el.beginMeasure();
38923 this.textEl.setWidth(1);
38925 * #2804 [new] Tabs in Roojs
38926 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38928 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38929 //this.el.endMeasure();
38933 * Sets the text for the tab (Note: this also sets the tooltip text)
38934 * @param {String} text The tab's text and tooltip
38936 setText : function(text){
38938 this.textEl.update(text);
38939 this.setTooltip(text);
38940 //if(!this.tabPanel.resizeTabs){
38941 // this.autoSize();
38945 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38947 activate : function(){
38948 this.tabPanel.activate(this.id);
38952 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38954 disable : function(){
38955 if(this.tabPanel.active != this){
38956 this.disabled = true;
38957 this.status_node.addClass("disabled");
38962 * Enables this TabPanelItem if it was previously disabled.
38964 enable : function(){
38965 this.disabled = false;
38966 this.status_node.removeClass("disabled");
38970 * Sets the content for this TabPanelItem.
38971 * @param {String} content The content
38972 * @param {Boolean} loadScripts true to look for and load scripts
38974 setContent : function(content, loadScripts){
38975 this.bodyEl.update(content, loadScripts);
38979 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38980 * @return {Roo.UpdateManager} The UpdateManager
38982 getUpdateManager : function(){
38983 return this.bodyEl.getUpdateManager();
38987 * Set a URL to be used to load the content for this TabPanelItem.
38988 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38989 * @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)
38990 * @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)
38991 * @return {Roo.UpdateManager} The UpdateManager
38993 setUrl : function(url, params, loadOnce){
38994 if(this.refreshDelegate){
38995 this.un('activate', this.refreshDelegate);
38997 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38998 this.on("activate", this.refreshDelegate);
38999 return this.bodyEl.getUpdateManager();
39003 _handleRefresh : function(url, params, loadOnce){
39004 if(!loadOnce || !this.loaded){
39005 var updater = this.bodyEl.getUpdateManager();
39006 updater.update(url, params, this._setLoaded.createDelegate(this));
39011 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39012 * Will fail silently if the setUrl method has not been called.
39013 * This does not activate the panel, just updates its content.
39015 refresh : function(){
39016 if(this.refreshDelegate){
39017 this.loaded = false;
39018 this.refreshDelegate();
39023 _setLoaded : function(){
39024 this.loaded = true;
39028 closeClick : function(e){
39031 this.fireEvent("beforeclose", this, o);
39032 if(o.cancel !== true){
39033 this.tabPanel.removeTab(this.id);
39037 * The text displayed in the tooltip for the close icon.
39040 closeText : "Close this tab"
39043 * This script refer to:
39044 * Title: International Telephone Input
39045 * Author: Jack O'Connor
39046 * Code version: v12.1.12
39047 * Availability: https://github.com/jackocnr/intl-tel-input.git
39050 Roo.bootstrap.PhoneInputData = function() {
39053 "Afghanistan (افغانستان)",
39058 "Albania (Shqipëri)",
39063 "Algeria (الجزائر)",
39088 "Antigua and Barbuda",
39098 "Armenia (Հայաստան)",
39114 "Austria (Österreich)",
39119 "Azerbaijan (Azərbaycan)",
39129 "Bahrain (البحرين)",
39134 "Bangladesh (বাংলাদেশ)",
39144 "Belarus (Беларусь)",
39149 "Belgium (België)",
39179 "Bosnia and Herzegovina (Босна и Херцеговина)",
39194 "British Indian Ocean Territory",
39199 "British Virgin Islands",
39209 "Bulgaria (България)",
39219 "Burundi (Uburundi)",
39224 "Cambodia (កម្ពុជា)",
39229 "Cameroon (Cameroun)",
39238 ["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"]
39241 "Cape Verde (Kabu Verdi)",
39246 "Caribbean Netherlands",
39257 "Central African Republic (République centrafricaine)",
39277 "Christmas Island",
39283 "Cocos (Keeling) Islands",
39294 "Comoros (جزر القمر)",
39299 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39304 "Congo (Republic) (Congo-Brazzaville)",
39324 "Croatia (Hrvatska)",
39345 "Czech Republic (Česká republika)",
39350 "Denmark (Danmark)",
39365 "Dominican Republic (República Dominicana)",
39369 ["809", "829", "849"]
39387 "Equatorial Guinea (Guinea Ecuatorial)",
39407 "Falkland Islands (Islas Malvinas)",
39412 "Faroe Islands (Føroyar)",
39433 "French Guiana (Guyane française)",
39438 "French Polynesia (Polynésie française)",
39453 "Georgia (საქართველო)",
39458 "Germany (Deutschland)",
39478 "Greenland (Kalaallit Nunaat)",
39515 "Guinea-Bissau (Guiné Bissau)",
39540 "Hungary (Magyarország)",
39545 "Iceland (Ísland)",
39565 "Iraq (العراق)",
39581 "Israel (ישראל)",
39608 "Jordan (الأردن)",
39613 "Kazakhstan (Казахстан)",
39634 "Kuwait (الكويت)",
39639 "Kyrgyzstan (Кыргызстан)",
39649 "Latvia (Latvija)",
39654 "Lebanon (لبنان)",
39669 "Libya (ليبيا)",
39679 "Lithuania (Lietuva)",
39694 "Macedonia (FYROM) (Македонија)",
39699 "Madagascar (Madagasikara)",
39729 "Marshall Islands",
39739 "Mauritania (موريتانيا)",
39744 "Mauritius (Moris)",
39765 "Moldova (Republica Moldova)",
39775 "Mongolia (Монгол)",
39780 "Montenegro (Crna Gora)",
39790 "Morocco (المغرب)",
39796 "Mozambique (Moçambique)",
39801 "Myanmar (Burma) (မြန်မာ)",
39806 "Namibia (Namibië)",
39821 "Netherlands (Nederland)",
39826 "New Caledonia (Nouvelle-Calédonie)",
39861 "North Korea (조선 민주주의 인민 공화국)",
39866 "Northern Mariana Islands",
39882 "Pakistan (پاکستان)",
39892 "Palestine (فلسطين)",
39902 "Papua New Guinea",
39944 "Réunion (La Réunion)",
39950 "Romania (România)",
39966 "Saint Barthélemy",
39977 "Saint Kitts and Nevis",
39987 "Saint Martin (Saint-Martin (partie française))",
39993 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39998 "Saint Vincent and the Grenadines",
40013 "São Tomé and Príncipe (São Tomé e Príncipe)",
40018 "Saudi Arabia (المملكة العربية السعودية)",
40023 "Senegal (Sénégal)",
40053 "Slovakia (Slovensko)",
40058 "Slovenia (Slovenija)",
40068 "Somalia (Soomaaliya)",
40078 "South Korea (대한민국)",
40083 "South Sudan (جنوب السودان)",
40093 "Sri Lanka (ශ්රී ලංකාව)",
40098 "Sudan (السودان)",
40108 "Svalbard and Jan Mayen",
40119 "Sweden (Sverige)",
40124 "Switzerland (Schweiz)",
40129 "Syria (سوريا)",
40174 "Trinidad and Tobago",
40179 "Tunisia (تونس)",
40184 "Turkey (Türkiye)",
40194 "Turks and Caicos Islands",
40204 "U.S. Virgin Islands",
40214 "Ukraine (Україна)",
40219 "United Arab Emirates (الإمارات العربية المتحدة)",
40241 "Uzbekistan (Oʻzbekiston)",
40251 "Vatican City (Città del Vaticano)",
40262 "Vietnam (Việt Nam)",
40267 "Wallis and Futuna (Wallis-et-Futuna)",
40272 "Western Sahara (الصحراء الغربية)",
40278 "Yemen (اليمن)",
40302 * This script refer to:
40303 * Title: International Telephone Input
40304 * Author: Jack O'Connor
40305 * Code version: v12.1.12
40306 * Availability: https://github.com/jackocnr/intl-tel-input.git
40310 * @class Roo.bootstrap.PhoneInput
40311 * @extends Roo.bootstrap.TriggerField
40312 * An input with International dial-code selection
40314 * @cfg {String} defaultDialCode default '+852'
40315 * @cfg {Array} preferedCountries default []
40318 * Create a new PhoneInput.
40319 * @param {Object} config Configuration options
40322 Roo.bootstrap.PhoneInput = function(config) {
40323 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40326 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40328 listWidth: undefined,
40330 selectedClass: 'active',
40332 invalidClass : "has-warning",
40334 validClass: 'has-success',
40336 allowed: '0123456789',
40341 * @cfg {String} defaultDialCode The default dial code when initializing the input
40343 defaultDialCode: '+852',
40346 * @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
40348 preferedCountries: false,
40350 getAutoCreate : function()
40352 var data = Roo.bootstrap.PhoneInputData();
40353 var align = this.labelAlign || this.parentLabelAlign();
40356 this.allCountries = [];
40357 this.dialCodeMapping = [];
40359 for (var i = 0; i < data.length; i++) {
40361 this.allCountries[i] = {
40365 priority: c[3] || 0,
40366 areaCodes: c[4] || null
40368 this.dialCodeMapping[c[2]] = {
40371 priority: c[3] || 0,
40372 areaCodes: c[4] || null
40384 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40385 maxlength: this.max_length,
40386 cls : 'form-control tel-input',
40387 autocomplete: 'new-password'
40390 var hiddenInput = {
40393 cls: 'hidden-tel-input'
40397 hiddenInput.name = this.name;
40400 if (this.disabled) {
40401 input.disabled = true;
40404 var flag_container = {
40421 cls: this.hasFeedback ? 'has-feedback' : '',
40427 cls: 'dial-code-holder',
40434 cls: 'roo-select2-container input-group',
40441 if (this.fieldLabel.length) {
40444 tooltip: 'This field is required'
40450 cls: 'control-label',
40456 html: this.fieldLabel
40459 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40465 if(this.indicatorpos == 'right') {
40466 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40473 if(align == 'left') {
40481 if(this.labelWidth > 12){
40482 label.style = "width: " + this.labelWidth + 'px';
40484 if(this.labelWidth < 13 && this.labelmd == 0){
40485 this.labelmd = this.labelWidth;
40487 if(this.labellg > 0){
40488 label.cls += ' col-lg-' + this.labellg;
40489 input.cls += ' col-lg-' + (12 - this.labellg);
40491 if(this.labelmd > 0){
40492 label.cls += ' col-md-' + this.labelmd;
40493 container.cls += ' col-md-' + (12 - this.labelmd);
40495 if(this.labelsm > 0){
40496 label.cls += ' col-sm-' + this.labelsm;
40497 container.cls += ' col-sm-' + (12 - this.labelsm);
40499 if(this.labelxs > 0){
40500 label.cls += ' col-xs-' + this.labelxs;
40501 container.cls += ' col-xs-' + (12 - this.labelxs);
40511 var settings = this;
40513 ['xs','sm','md','lg'].map(function(size){
40514 if (settings[size]) {
40515 cfg.cls += ' col-' + size + '-' + settings[size];
40519 this.store = new Roo.data.Store({
40520 proxy : new Roo.data.MemoryProxy({}),
40521 reader : new Roo.data.JsonReader({
40532 'name' : 'dialCode',
40536 'name' : 'priority',
40540 'name' : 'areaCodes',
40547 if(!this.preferedCountries) {
40548 this.preferedCountries = [
40555 var p = this.preferedCountries.reverse();
40558 for (var i = 0; i < p.length; i++) {
40559 for (var j = 0; j < this.allCountries.length; j++) {
40560 if(this.allCountries[j].iso2 == p[i]) {
40561 var t = this.allCountries[j];
40562 this.allCountries.splice(j,1);
40563 this.allCountries.unshift(t);
40569 this.store.proxy.data = {
40571 data: this.allCountries
40577 initEvents : function()
40580 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40582 this.indicator = this.indicatorEl();
40583 this.flag = this.flagEl();
40584 this.dialCodeHolder = this.dialCodeHolderEl();
40586 this.trigger = this.el.select('div.flag-box',true).first();
40587 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40592 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40593 _this.list.setWidth(lw);
40596 this.list.on('mouseover', this.onViewOver, this);
40597 this.list.on('mousemove', this.onViewMove, this);
40598 this.inputEl().on("keyup", this.onKeyUp, this);
40599 this.inputEl().on("keypress", this.onKeyPress, this);
40601 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40603 this.view = new Roo.View(this.list, this.tpl, {
40604 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40607 this.view.on('click', this.onViewClick, this);
40608 this.setValue(this.defaultDialCode);
40611 onTriggerClick : function(e)
40613 Roo.log('trigger click');
40618 if(this.isExpanded()){
40620 this.hasFocus = false;
40622 this.store.load({});
40623 this.hasFocus = true;
40628 isExpanded : function()
40630 return this.list.isVisible();
40633 collapse : function()
40635 if(!this.isExpanded()){
40639 Roo.get(document).un('mousedown', this.collapseIf, this);
40640 Roo.get(document).un('mousewheel', this.collapseIf, this);
40641 this.fireEvent('collapse', this);
40645 expand : function()
40649 if(this.isExpanded() || !this.hasFocus){
40653 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40654 this.list.setWidth(lw);
40657 this.restrictHeight();
40659 Roo.get(document).on('mousedown', this.collapseIf, this);
40660 Roo.get(document).on('mousewheel', this.collapseIf, this);
40662 this.fireEvent('expand', this);
40665 restrictHeight : function()
40667 this.list.alignTo(this.inputEl(), this.listAlign);
40668 this.list.alignTo(this.inputEl(), this.listAlign);
40671 onViewOver : function(e, t)
40673 if(this.inKeyMode){
40676 var item = this.view.findItemFromChild(t);
40679 var index = this.view.indexOf(item);
40680 this.select(index, false);
40685 onViewClick : function(view, doFocus, el, e)
40687 var index = this.view.getSelectedIndexes()[0];
40689 var r = this.store.getAt(index);
40692 this.onSelect(r, index);
40694 if(doFocus !== false && !this.blockFocus){
40695 this.inputEl().focus();
40699 onViewMove : function(e, t)
40701 this.inKeyMode = false;
40704 select : function(index, scrollIntoView)
40706 this.selectedIndex = index;
40707 this.view.select(index);
40708 if(scrollIntoView !== false){
40709 var el = this.view.getNode(index);
40711 this.list.scrollChildIntoView(el, false);
40716 createList : function()
40718 this.list = Roo.get(document.body).createChild({
40720 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40721 style: 'display:none'
40724 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40727 collapseIf : function(e)
40729 var in_combo = e.within(this.el);
40730 var in_list = e.within(this.list);
40731 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40733 if (in_combo || in_list || is_list) {
40739 onSelect : function(record, index)
40741 if(this.fireEvent('beforeselect', this, record, index) !== false){
40743 this.setFlagClass(record.data.iso2);
40744 this.setDialCode(record.data.dialCode);
40745 this.hasFocus = false;
40747 this.fireEvent('select', this, record, index);
40751 flagEl : function()
40753 var flag = this.el.select('div.flag',true).first();
40760 dialCodeHolderEl : function()
40762 var d = this.el.select('input.dial-code-holder',true).first();
40769 setDialCode : function(v)
40771 this.dialCodeHolder.dom.value = '+'+v;
40774 setFlagClass : function(n)
40776 this.flag.dom.className = 'flag '+n;
40779 getValue : function()
40781 var v = this.inputEl().getValue();
40782 if(this.dialCodeHolder) {
40783 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40788 setValue : function(v)
40790 var d = this.getDialCode(v);
40792 //invalid dial code
40793 if(v.length == 0 || !d || d.length == 0) {
40795 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40796 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40802 this.setFlagClass(this.dialCodeMapping[d].iso2);
40803 this.setDialCode(d);
40804 this.inputEl().dom.value = v.replace('+'+d,'');
40805 this.hiddenEl().dom.value = this.getValue();
40810 getDialCode : function(v)
40814 if (v.length == 0) {
40815 return this.dialCodeHolder.dom.value;
40819 if (v.charAt(0) != "+") {
40822 var numericChars = "";
40823 for (var i = 1; i < v.length; i++) {
40824 var c = v.charAt(i);
40827 if (this.dialCodeMapping[numericChars]) {
40828 dialCode = v.substr(1, i);
40830 if (numericChars.length == 4) {
40840 this.setValue(this.defaultDialCode);
40844 hiddenEl : function()
40846 return this.el.select('input.hidden-tel-input',true).first();
40849 // after setting val
40850 onKeyUp : function(e){
40851 this.setValue(this.getValue());
40854 onKeyPress : function(e){
40855 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40862 * @class Roo.bootstrap.MoneyField
40863 * @extends Roo.bootstrap.ComboBox
40864 * Bootstrap MoneyField class
40867 * Create a new MoneyField.
40868 * @param {Object} config Configuration options
40871 Roo.bootstrap.MoneyField = function(config) {
40873 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40877 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40880 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40882 allowDecimals : true,
40884 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40886 decimalSeparator : ".",
40888 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40890 decimalPrecision : 0,
40892 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40894 allowNegative : true,
40896 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40900 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40902 minValue : Number.NEGATIVE_INFINITY,
40904 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40906 maxValue : Number.MAX_VALUE,
40908 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40910 minText : "The minimum value for this field is {0}",
40912 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40914 maxText : "The maximum value for this field is {0}",
40916 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40917 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40919 nanText : "{0} is not a valid number",
40921 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40925 * @cfg {String} defaults currency of the MoneyField
40926 * value should be in lkey
40928 defaultCurrency : false,
40930 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40932 thousandsDelimiter : false,
40934 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40945 getAutoCreate : function()
40947 var align = this.labelAlign || this.parentLabelAlign();
40959 cls : 'form-control roo-money-amount-input',
40960 autocomplete: 'new-password'
40963 var hiddenInput = {
40967 cls: 'hidden-number-input'
40970 if(this.max_length) {
40971 input.maxlength = this.max_length;
40975 hiddenInput.name = this.name;
40978 if (this.disabled) {
40979 input.disabled = true;
40982 var clg = 12 - this.inputlg;
40983 var cmd = 12 - this.inputmd;
40984 var csm = 12 - this.inputsm;
40985 var cxs = 12 - this.inputxs;
40989 cls : 'row roo-money-field',
40993 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40997 cls: 'roo-select2-container input-group',
41001 cls : 'form-control roo-money-currency-input',
41002 autocomplete: 'new-password',
41004 name : this.currencyName
41008 cls : 'input-group-addon',
41022 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41026 cls: this.hasFeedback ? 'has-feedback' : '',
41037 if (this.fieldLabel.length) {
41040 tooltip: 'This field is required'
41046 cls: 'control-label',
41052 html: this.fieldLabel
41055 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41061 if(this.indicatorpos == 'right') {
41062 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41069 if(align == 'left') {
41077 if(this.labelWidth > 12){
41078 label.style = "width: " + this.labelWidth + 'px';
41080 if(this.labelWidth < 13 && this.labelmd == 0){
41081 this.labelmd = this.labelWidth;
41083 if(this.labellg > 0){
41084 label.cls += ' col-lg-' + this.labellg;
41085 input.cls += ' col-lg-' + (12 - this.labellg);
41087 if(this.labelmd > 0){
41088 label.cls += ' col-md-' + this.labelmd;
41089 container.cls += ' col-md-' + (12 - this.labelmd);
41091 if(this.labelsm > 0){
41092 label.cls += ' col-sm-' + this.labelsm;
41093 container.cls += ' col-sm-' + (12 - this.labelsm);
41095 if(this.labelxs > 0){
41096 label.cls += ' col-xs-' + this.labelxs;
41097 container.cls += ' col-xs-' + (12 - this.labelxs);
41108 var settings = this;
41110 ['xs','sm','md','lg'].map(function(size){
41111 if (settings[size]) {
41112 cfg.cls += ' col-' + size + '-' + settings[size];
41119 initEvents : function()
41121 this.indicator = this.indicatorEl();
41123 this.initCurrencyEvent();
41125 this.initNumberEvent();
41128 initCurrencyEvent : function()
41131 throw "can not find store for combo";
41134 this.store = Roo.factory(this.store, Roo.data);
41135 this.store.parent = this;
41139 this.triggerEl = this.el.select('.input-group-addon', true).first();
41141 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41146 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41147 _this.list.setWidth(lw);
41150 this.list.on('mouseover', this.onViewOver, this);
41151 this.list.on('mousemove', this.onViewMove, this);
41152 this.list.on('scroll', this.onViewScroll, this);
41155 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41158 this.view = new Roo.View(this.list, this.tpl, {
41159 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41162 this.view.on('click', this.onViewClick, this);
41164 this.store.on('beforeload', this.onBeforeLoad, this);
41165 this.store.on('load', this.onLoad, this);
41166 this.store.on('loadexception', this.onLoadException, this);
41168 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41169 "up" : function(e){
41170 this.inKeyMode = true;
41174 "down" : function(e){
41175 if(!this.isExpanded()){
41176 this.onTriggerClick();
41178 this.inKeyMode = true;
41183 "enter" : function(e){
41186 if(this.fireEvent("specialkey", this, e)){
41187 this.onViewClick(false);
41193 "esc" : function(e){
41197 "tab" : function(e){
41200 if(this.fireEvent("specialkey", this, e)){
41201 this.onViewClick(false);
41209 doRelay : function(foo, bar, hname){
41210 if(hname == 'down' || this.scope.isExpanded()){
41211 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41219 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41223 initNumberEvent : function(e)
41225 this.inputEl().on("keydown" , this.fireKey, this);
41226 this.inputEl().on("focus", this.onFocus, this);
41227 this.inputEl().on("blur", this.onBlur, this);
41229 this.inputEl().relayEvent('keyup', this);
41231 if(this.indicator){
41232 this.indicator.addClass('invisible');
41235 this.originalValue = this.getValue();
41237 if(this.validationEvent == 'keyup'){
41238 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41239 this.inputEl().on('keyup', this.filterValidation, this);
41241 else if(this.validationEvent !== false){
41242 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41245 if(this.selectOnFocus){
41246 this.on("focus", this.preFocus, this);
41249 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41250 this.inputEl().on("keypress", this.filterKeys, this);
41252 this.inputEl().relayEvent('keypress', this);
41255 var allowed = "0123456789";
41257 if(this.allowDecimals){
41258 allowed += this.decimalSeparator;
41261 if(this.allowNegative){
41265 if(this.thousandsDelimiter) {
41269 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41271 var keyPress = function(e){
41273 var k = e.getKey();
41275 var c = e.getCharCode();
41278 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41279 allowed.indexOf(String.fromCharCode(c)) === -1
41285 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41289 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41294 this.inputEl().on("keypress", keyPress, this);
41298 onTriggerClick : function(e)
41305 this.loadNext = false;
41307 if(this.isExpanded()){
41312 this.hasFocus = true;
41314 if(this.triggerAction == 'all') {
41315 this.doQuery(this.allQuery, true);
41319 this.doQuery(this.getRawValue());
41322 getCurrency : function()
41324 var v = this.currencyEl().getValue();
41329 restrictHeight : function()
41331 this.list.alignTo(this.currencyEl(), this.listAlign);
41332 this.list.alignTo(this.currencyEl(), this.listAlign);
41335 onViewClick : function(view, doFocus, el, e)
41337 var index = this.view.getSelectedIndexes()[0];
41339 var r = this.store.getAt(index);
41342 this.onSelect(r, index);
41346 onSelect : function(record, index){
41348 if(this.fireEvent('beforeselect', this, record, index) !== false){
41350 this.setFromCurrencyData(index > -1 ? record.data : false);
41354 this.fireEvent('select', this, record, index);
41358 setFromCurrencyData : function(o)
41362 this.lastCurrency = o;
41364 if (this.currencyField) {
41365 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41367 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41370 this.lastSelectionText = currency;
41372 //setting default currency
41373 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41374 this.setCurrency(this.defaultCurrency);
41378 this.setCurrency(currency);
41381 setFromData : function(o)
41385 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41387 this.setFromCurrencyData(c);
41392 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41394 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41397 this.setValue(value);
41401 setCurrency : function(v)
41403 this.currencyValue = v;
41406 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41411 setValue : function(v)
41413 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41419 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41421 this.inputEl().dom.value = (v == '') ? '' :
41422 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41424 if(!this.allowZero && v === '0') {
41425 this.hiddenEl().dom.value = '';
41426 this.inputEl().dom.value = '';
41433 getRawValue : function()
41435 var v = this.inputEl().getValue();
41440 getValue : function()
41442 return this.fixPrecision(this.parseValue(this.getRawValue()));
41445 parseValue : function(value)
41447 if(this.thousandsDelimiter) {
41449 r = new RegExp(",", "g");
41450 value = value.replace(r, "");
41453 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41454 return isNaN(value) ? '' : value;
41458 fixPrecision : function(value)
41460 if(this.thousandsDelimiter) {
41462 r = new RegExp(",", "g");
41463 value = value.replace(r, "");
41466 var nan = isNaN(value);
41468 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41469 return nan ? '' : value;
41471 return parseFloat(value).toFixed(this.decimalPrecision);
41474 decimalPrecisionFcn : function(v)
41476 return Math.floor(v);
41479 validateValue : function(value)
41481 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41485 var num = this.parseValue(value);
41488 this.markInvalid(String.format(this.nanText, value));
41492 if(num < this.minValue){
41493 this.markInvalid(String.format(this.minText, this.minValue));
41497 if(num > this.maxValue){
41498 this.markInvalid(String.format(this.maxText, this.maxValue));
41505 validate : function()
41507 if(this.disabled || this.allowBlank){
41512 var currency = this.getCurrency();
41514 if(this.validateValue(this.getRawValue()) && currency.length){
41519 this.markInvalid();
41523 getName: function()
41528 beforeBlur : function()
41534 var v = this.parseValue(this.getRawValue());
41541 onBlur : function()
41545 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41546 //this.el.removeClass(this.focusClass);
41549 this.hasFocus = false;
41551 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41555 var v = this.getValue();
41557 if(String(v) !== String(this.startValue)){
41558 this.fireEvent('change', this, v, this.startValue);
41561 this.fireEvent("blur", this);
41564 inputEl : function()
41566 return this.el.select('.roo-money-amount-input', true).first();
41569 currencyEl : function()
41571 return this.el.select('.roo-money-currency-input', true).first();
41574 hiddenEl : function()
41576 return this.el.select('input.hidden-number-input',true).first();
41580 * @class Roo.bootstrap.BezierSignature
41581 * @extends Roo.bootstrap.Component
41582 * Bootstrap BezierSignature class
41583 * This script refer to:
41584 * Title: Signature Pad
41586 * Availability: https://github.com/szimek/signature_pad
41589 * Create a new BezierSignature
41590 * @param {Object} config The config object
41593 Roo.bootstrap.BezierSignature = function(config){
41594 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41600 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41607 mouse_btn_down: true,
41610 * @cfg {int} canvas height
41612 canvas_height: '200px',
41615 * @cfg {float|function} Radius of a single dot.
41620 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41625 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41630 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41635 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41640 * @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.
41642 bg_color: 'rgba(0, 0, 0, 0)',
41645 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41647 dot_color: 'black',
41650 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41652 velocity_filter_weight: 0.7,
41655 * @cfg {function} Callback when stroke begin.
41660 * @cfg {function} Callback when stroke end.
41664 getAutoCreate : function()
41666 var cls = 'roo-signature column';
41669 cls += ' ' + this.cls;
41679 for(var i = 0; i < col_sizes.length; i++) {
41680 if(this[col_sizes[i]]) {
41681 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41691 cls: 'roo-signature-body',
41695 cls: 'roo-signature-body-canvas',
41696 height: this.canvas_height,
41697 width: this.canvas_width
41704 style: 'display: none'
41712 initEvents: function()
41714 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41716 var canvas = this.canvasEl();
41718 // mouse && touch event swapping...
41719 canvas.dom.style.touchAction = 'none';
41720 canvas.dom.style.msTouchAction = 'none';
41722 this.mouse_btn_down = false;
41723 canvas.on('mousedown', this._handleMouseDown, this);
41724 canvas.on('mousemove', this._handleMouseMove, this);
41725 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41727 if (window.PointerEvent) {
41728 canvas.on('pointerdown', this._handleMouseDown, this);
41729 canvas.on('pointermove', this._handleMouseMove, this);
41730 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41733 if ('ontouchstart' in window) {
41734 canvas.on('touchstart', this._handleTouchStart, this);
41735 canvas.on('touchmove', this._handleTouchMove, this);
41736 canvas.on('touchend', this._handleTouchEnd, this);
41739 Roo.EventManager.onWindowResize(this.resize, this, true);
41741 // file input event
41742 this.fileEl().on('change', this.uploadImage, this);
41749 resize: function(){
41751 var canvas = this.canvasEl().dom;
41752 var ctx = this.canvasElCtx();
41753 var img_data = false;
41755 if(canvas.width > 0) {
41756 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41758 // setting canvas width will clean img data
41761 var style = window.getComputedStyle ?
41762 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41764 var padding_left = parseInt(style.paddingLeft) || 0;
41765 var padding_right = parseInt(style.paddingRight) || 0;
41767 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41770 ctx.putImageData(img_data, 0, 0);
41774 _handleMouseDown: function(e)
41776 if (e.browserEvent.which === 1) {
41777 this.mouse_btn_down = true;
41778 this.strokeBegin(e);
41782 _handleMouseMove: function (e)
41784 if (this.mouse_btn_down) {
41785 this.strokeMoveUpdate(e);
41789 _handleMouseUp: function (e)
41791 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41792 this.mouse_btn_down = false;
41797 _handleTouchStart: function (e) {
41799 e.preventDefault();
41800 if (e.browserEvent.targetTouches.length === 1) {
41801 // var touch = e.browserEvent.changedTouches[0];
41802 // this.strokeBegin(touch);
41804 this.strokeBegin(e); // assume e catching the correct xy...
41808 _handleTouchMove: function (e) {
41809 e.preventDefault();
41810 // var touch = event.targetTouches[0];
41811 // _this._strokeMoveUpdate(touch);
41812 this.strokeMoveUpdate(e);
41815 _handleTouchEnd: function (e) {
41816 var wasCanvasTouched = e.target === this.canvasEl().dom;
41817 if (wasCanvasTouched) {
41818 e.preventDefault();
41819 // var touch = event.changedTouches[0];
41820 // _this._strokeEnd(touch);
41825 reset: function () {
41826 this._lastPoints = [];
41827 this._lastVelocity = 0;
41828 this._lastWidth = (this.min_width + this.max_width) / 2;
41829 this.canvasElCtx().fillStyle = this.dot_color;
41832 strokeMoveUpdate: function(e)
41834 this.strokeUpdate(e);
41836 if (this.throttle) {
41837 this.throttleStroke(this.strokeUpdate, this.throttle);
41840 this.strokeUpdate(e);
41844 strokeBegin: function(e)
41846 var newPointGroup = {
41847 color: this.dot_color,
41851 if (typeof this.onBegin === 'function') {
41855 this.curve_data.push(newPointGroup);
41857 this.strokeUpdate(e);
41860 strokeUpdate: function(e)
41862 var rect = this.canvasEl().dom.getBoundingClientRect();
41863 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41864 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41865 var lastPoints = lastPointGroup.points;
41866 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41867 var isLastPointTooClose = lastPoint
41868 ? point.distanceTo(lastPoint) <= this.min_distance
41870 var color = lastPointGroup.color;
41871 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41872 var curve = this.addPoint(point);
41874 this.drawDot({color: color, point: point});
41877 this.drawCurve({color: color, curve: curve});
41887 strokeEnd: function(e)
41889 this.strokeUpdate(e);
41890 if (typeof this.onEnd === 'function') {
41895 addPoint: function (point) {
41896 var _lastPoints = this._lastPoints;
41897 _lastPoints.push(point);
41898 if (_lastPoints.length > 2) {
41899 if (_lastPoints.length === 3) {
41900 _lastPoints.unshift(_lastPoints[0]);
41902 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41903 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41904 _lastPoints.shift();
41910 calculateCurveWidths: function (startPoint, endPoint) {
41911 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41912 (1 - this.velocity_filter_weight) * this._lastVelocity;
41914 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41917 start: this._lastWidth
41920 this._lastVelocity = velocity;
41921 this._lastWidth = newWidth;
41925 drawDot: function (_a) {
41926 var color = _a.color, point = _a.point;
41927 var ctx = this.canvasElCtx();
41928 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41930 this.drawCurveSegment(point.x, point.y, width);
41932 ctx.fillStyle = color;
41936 drawCurve: function (_a) {
41937 var color = _a.color, curve = _a.curve;
41938 var ctx = this.canvasElCtx();
41939 var widthDelta = curve.endWidth - curve.startWidth;
41940 var drawSteps = Math.floor(curve.length()) * 2;
41942 ctx.fillStyle = color;
41943 for (var i = 0; i < drawSteps; i += 1) {
41944 var t = i / drawSteps;
41950 var x = uuu * curve.startPoint.x;
41951 x += 3 * uu * t * curve.control1.x;
41952 x += 3 * u * tt * curve.control2.x;
41953 x += ttt * curve.endPoint.x;
41954 var y = uuu * curve.startPoint.y;
41955 y += 3 * uu * t * curve.control1.y;
41956 y += 3 * u * tt * curve.control2.y;
41957 y += ttt * curve.endPoint.y;
41958 var width = curve.startWidth + ttt * widthDelta;
41959 this.drawCurveSegment(x, y, width);
41965 drawCurveSegment: function (x, y, width) {
41966 var ctx = this.canvasElCtx();
41968 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41969 this.is_empty = false;
41974 var ctx = this.canvasElCtx();
41975 var canvas = this.canvasEl().dom;
41976 ctx.fillStyle = this.bg_color;
41977 ctx.clearRect(0, 0, canvas.width, canvas.height);
41978 ctx.fillRect(0, 0, canvas.width, canvas.height);
41979 this.curve_data = [];
41981 this.is_empty = true;
41986 return this.el.select('input',true).first();
41989 canvasEl: function()
41991 return this.el.select('canvas',true).first();
41994 canvasElCtx: function()
41996 return this.el.select('canvas',true).first().dom.getContext('2d');
41999 getImage: function(type)
42001 if(this.is_empty) {
42006 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42009 drawFromImage: function(img_src)
42011 var img = new Image();
42013 img.onload = function(){
42014 this.canvasElCtx().drawImage(img, 0, 0);
42019 this.is_empty = false;
42022 selectImage: function()
42024 this.fileEl().dom.click();
42027 uploadImage: function(e)
42029 var reader = new FileReader();
42031 reader.onload = function(e){
42032 var img = new Image();
42033 img.onload = function(){
42035 this.canvasElCtx().drawImage(img, 0, 0);
42037 img.src = e.target.result;
42040 reader.readAsDataURL(e.target.files[0]);
42043 // Bezier Point Constructor
42044 Point: (function () {
42045 function Point(x, y, time) {
42048 this.time = time || Date.now();
42050 Point.prototype.distanceTo = function (start) {
42051 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42053 Point.prototype.equals = function (other) {
42054 return this.x === other.x && this.y === other.y && this.time === other.time;
42056 Point.prototype.velocityFrom = function (start) {
42057 return this.time !== start.time
42058 ? this.distanceTo(start) / (this.time - start.time)
42065 // Bezier Constructor
42066 Bezier: (function () {
42067 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42068 this.startPoint = startPoint;
42069 this.control2 = control2;
42070 this.control1 = control1;
42071 this.endPoint = endPoint;
42072 this.startWidth = startWidth;
42073 this.endWidth = endWidth;
42075 Bezier.fromPoints = function (points, widths, scope) {
42076 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42077 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42078 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42080 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42081 var dx1 = s1.x - s2.x;
42082 var dy1 = s1.y - s2.y;
42083 var dx2 = s2.x - s3.x;
42084 var dy2 = s2.y - s3.y;
42085 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42086 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42087 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42088 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42089 var dxm = m1.x - m2.x;
42090 var dym = m1.y - m2.y;
42091 var k = l2 / (l1 + l2);
42092 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42093 var tx = s2.x - cm.x;
42094 var ty = s2.y - cm.y;
42096 c1: new scope.Point(m1.x + tx, m1.y + ty),
42097 c2: new scope.Point(m2.x + tx, m2.y + ty)
42100 Bezier.prototype.length = function () {
42105 for (var i = 0; i <= steps; i += 1) {
42107 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42108 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42110 var xdiff = cx - px;
42111 var ydiff = cy - py;
42112 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42119 Bezier.prototype.point = function (t, start, c1, c2, end) {
42120 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42121 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42122 + (3.0 * c2 * (1.0 - t) * t * t)
42123 + (end * t * t * t);
42128 throttleStroke: function(fn, wait) {
42129 if (wait === void 0) { wait = 250; }
42131 var timeout = null;
42135 var later = function () {
42136 previous = Date.now();
42138 result = fn.apply(storedContext, storedArgs);
42140 storedContext = null;
42144 return function wrapper() {
42146 for (var _i = 0; _i < arguments.length; _i++) {
42147 args[_i] = arguments[_i];
42149 var now = Date.now();
42150 var remaining = wait - (now - previous);
42151 storedContext = this;
42153 if (remaining <= 0 || remaining > wait) {
42155 clearTimeout(timeout);
42159 result = fn.apply(storedContext, storedArgs);
42161 storedContext = null;
42165 else if (!timeout) {
42166 timeout = window.setTimeout(later, remaining);