2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets, function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
61 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
64 allowDomMove : false, // to stop relocations in parent onRender...
74 * Initialize Events for the element
76 initEvents : function() { },
82 can_build_overlaid : true,
84 container_method : false,
91 // returns the parent component..
92 return Roo.ComponentMgr.get(this.parentId)
98 onRender : function(ct, position)
100 // Roo.log("Call onRender: " + this.xtype);
102 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
105 if (this.el.attr('xtype')) {
106 this.el.attr('xtypex', this.el.attr('xtype'));
107 this.el.dom.removeAttribute('xtype');
117 var cfg = Roo.apply({}, this.getAutoCreate());
119 cfg.id = this.id || Roo.id();
121 // fill in the extra attributes
122 if (this.xattr && typeof(this.xattr) =='object') {
123 for (var i in this.xattr) {
124 cfg[i] = this.xattr[i];
129 cfg.dataId = this.dataId;
133 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
136 if (this.style) { // fixme needs to support more complex style data.
137 cfg.style = this.style;
141 cfg.name = this.name;
144 this.el = ct.createChild(cfg, position);
147 this.tooltipEl().attr('tooltip', this.tooltip);
150 if(this.tabIndex !== undefined){
151 this.el.dom.setAttribute('tabIndex', this.tabIndex);
158 * Fetch the element to add children to
159 * @return {Roo.Element} defaults to this.el
161 getChildContainer : function()
166 * Fetch the element to display the tooltip on.
167 * @return {Roo.Element} defaults to this.el
169 tooltipEl : function()
174 * This is really a wrapper for addxtypeChild
175 * it handles stuff relating to flexy:foreach / flexy:if
176 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
177 * -- this is a bit of a nightmare... and is even more confusing to debug..
182 addxtype : function(tree,cntr)
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 var cn = Roo.factory(tree); // this is posibly the first of two times that the ctor get's called...
187 cn.parentType = this.xtype; //??
188 cn.parentId = this.id;
189 if (typeof(cn.container_method) == 'string') {
190 cntr = cn.container_method;
194 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
196 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
198 var build_from_html = Roo.XComponent.build_from_html;
200 var is_body = (tree.xtype == 'Body') ;
202 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
204 var self_cntr_el = Roo.get(this[cntr](false));
206 // do not try and build conditional elements
207 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
211 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
212 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
213 //return this.addxtypeChild(tree,cntr, is_body);
214 return this.addxtypeChild(tree, cntr, is_body);
217 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
220 return this.addxtypeChild(Roo.apply({}, tree),cntr);
223 Roo.log('skipping render');
229 if (!build_from_html) {
233 // this i think handles overlaying multiple children of the same type
234 // with the sam eelement.. - which might be buggy..
236 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
242 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
246 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
252 * add a child to this element
253 * - turn the child.cfg into a child_instance
254 * - call child_instance.render( this { getContainerMethod()} )
255 * - loop through the children, and call addxtype.. (reall this) on newly created child.
259 addxtypeChild : function (tree, cntr, is_body)
261 Roo.debug && Roo.log('addxtypeChild:' + cntr);
263 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
266 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
267 (typeof(tree['flexy:foreach']) != 'undefined');
271 skip_children = false;
272 // render the element if it's not BODY.
275 // if parent was disabled, then do not try and create the children..
276 if(!this[cntr](true)){
281 cn = Roo.factory(tree);
283 cn.parentType = this.xtype; //??
284 cn.parentId = this.id;
286 var build_from_html = Roo.XComponent.build_from_html;
289 // does the container contain child eleemnts with 'xtype' attributes.
290 // that match this xtype..
291 // note - when we render we create these as well..
292 // so we should check to see if body has xtype set.
293 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
295 var self_cntr_el = Roo.get(this[cntr](false));
296 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
298 //Roo.log(Roo.XComponent.build_from_html);
299 //Roo.log("got echild:");
302 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
303 // and are not displayed -this causes this to use up the wrong element when matching.
304 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
307 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
308 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
314 //echild.dom.removeAttribute('xtype');
316 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
317 Roo.debug && Roo.log(self_cntr_el);
318 Roo.debug && Roo.log(echild);
319 Roo.debug && Roo.log(cn);
325 // if object has flexy:if - then it may or may not be rendered.
326 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
327 // skip a flexy if element.
328 Roo.debug && Roo.log('skipping render');
329 Roo.debug && Roo.log(tree);
331 Roo.debug && Roo.log('skipping all children');
332 skip_children = true;
337 // actually if flexy:foreach is found, we really want to create
338 // multiple copies here...
340 //Roo.log(this[cntr]());
341 // some elements do not have render methods.. like the layouts...
343 if(this[cntr](true) === false){
348 cn.render && cn.render(this[cntr](true));
351 // then add the element..
358 cn.addxtypeChildren(tree.items, skip_children);
364 * add a number of children to this object,
365 * which in turn calls render...
369 addxtypeChildren: function(child_array, skip_children)
372 if (!child_array || !child_array.length ) {
377 for(var i =0;i < child_array.length;i++) {
381 // Roo.log(['add child', items[i]]);
382 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
386 this.fireEvent('childrenrendered', this);
396 * xAddChildren - the 'sub-compentized' version of the above idea..
398 xAddChildren: function(child_array, skip_children)
401 if (!child_array || !child_array.length ) {
406 for(var i =0;i < child_array.length;i++) {
410 // Roo.log(['add child', items[i]]);
411 nitems.push(this.xAdd(Roo.apply({}, child_array[i])));
415 this.fireEvent('childrenrendered', this);
421 * add a child to this element
422 * - turn the child.cfg into a child_instance
423 * - call child_instance.render( this { getContainerMethod()} )
424 * - loop through the children, and call addxtype.. (reall this) on newly created child.
428 xAdd : function (tree, cntr, is_body)
430 Roo.debug && Roo.log('xadd:' + cntr);
432 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
434 var parent_ctnr = this[cntr](true);
435 if(parent_ctnr === false){
436 return false; // getChildContainer an return false explicitly to block children being added?
439 throw new Exception("could not find parent Container for item");
442 var cn = Roo.factory(tree);
443 // at this point items[] array may be set..
444 // constructors should not really be building their children?
445 cn.parentType = this.xtype; //??
446 cn.parentId = this.id;
449 cn.render && cn.render(parent_ctnr);
451 cn.xAddChildren(tree.items || cn.items);
452 delete tree.items; // not really needed?
458 * Set the element that will be used to show or hide
460 setVisibilityEl : function(el)
462 this.visibilityEl = el;
466 * Get the element that will be used to show or hide
468 getVisibilityEl : function()
470 if (typeof(this.visibilityEl) == 'object') {
471 return this.visibilityEl;
474 if (typeof(this.visibilityEl) == 'string') {
475 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
482 * Show a component - removes 'hidden' class
486 if(!this.getVisibilityEl()){
490 this.getVisibilityEl().removeClass(['hidden','d-none']);
492 this.fireEvent('show', this);
497 * Hide a component - adds 'hidden' class
501 if(!this.getVisibilityEl()){
505 this.getVisibilityEl().addClass(['hidden','d-none']);
507 this.fireEvent('hide', this);
520 * @class Roo.bootstrap.Body
521 * @extends Roo.bootstrap.Component
522 * Bootstrap Body class
526 * @param {Object} config The config object
527 * @cfg {DomElement} do_render - if this is set, then the constructor will try and initialize render, using this as the start point
531 Roo.bootstrap.Body = function(config){
533 config = config || {};
535 Roo.bootstrap.Body.superclass.constructor.call(this, config);
536 this.el = Roo.get(config.el ? config.el : document.body );
537 if (this.cls && this.cls.length) {
538 Roo.get(document.body).addClass(this.cls);
540 if (config.do_render) {
541 this.onRender(config.do_render, '');
542 this.xAddChildren(config.items);
547 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
550 is_body : true,// just to make sure it's constructed?
555 onRender : function(ct, position)
557 if (!this.do_render) {
560 this.el = Roo.get(this.do_render);
577 * @class Roo.bootstrap.ButtonGroup
578 * @extends Roo.bootstrap.Component
579 * Bootstrap ButtonGroup class
580 * @cfg {String} size lg | sm | xs (default empty normal)
581 * @cfg {String} align vertical | justified (default none)
582 * @cfg {String} direction up | down (default down)
583 * @cfg {Boolean} toolbar false | true
584 * @cfg {Boolean} btn true | false
589 * @param {Object} config The config object
592 Roo.bootstrap.ButtonGroup = function(config){
593 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
596 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
604 getAutoCreate : function(){
610 cfg.html = this.html || cfg.html;
621 if (['vertical','justified'].indexOf(this.align)!==-1) {
622 cfg.cls = 'btn-group-' + this.align;
624 if (this.align == 'justified') {
625 console.log(this.items);
629 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
630 cfg.cls += ' btn-group-' + this.size;
633 if (this.direction == 'up') {
634 cfg.cls += ' dropup' ;
640 * Add a button to the group (similar to NavItem API.)
642 addItem : function(cfg)
644 var cn = new Roo.bootstrap.Button(cfg);
646 cn.parentId = this.id;
647 cn.onRender(this.el, null);
661 * @class Roo.bootstrap.Button
662 * @extends Roo.bootstrap.Component
663 * Bootstrap Button class
664 * @cfg {String} html The button content
665 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
666 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
667 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
668 * @cfg {String} size ( lg | sm | xs)
669 * @cfg {String} tag ( a | input | submit)
670 * @cfg {String} href empty or href
671 * @cfg {Boolean} disabled default false;
672 * @cfg {Boolean} isClose default false;
673 * @cfg {String} glyphicon depricated - use fa
674 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
675 * @cfg {String} badge text for badge
676 * @cfg {String} theme (default|glow)
677 * @cfg {Boolean} inverse dark themed version
678 * @cfg {Boolean} toggle is it a slidy toggle button
679 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
680 * @cfg {String} ontext text for on slidy toggle state
681 * @cfg {String} offtext text for off slidy toggle state
682 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
683 * @cfg {Boolean} removeClass remove the standard class..
684 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
687 * Create a new button
688 * @param {Object} config The config object
692 Roo.bootstrap.Button = function(config){
693 Roo.bootstrap.Button.superclass.constructor.call(this, config);
694 this.weightClass = ["btn-default btn-outline-secondary",
706 * When a butotn is pressed
707 * @param {Roo.bootstrap.Button} btn
708 * @param {Roo.EventObject} e
713 * After the button has been toggles
714 * @param {Roo.bootstrap.Button} btn
715 * @param {Roo.EventObject} e
716 * @param {boolean} pressed (also available as button.pressed)
722 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
743 preventDefault: true,
751 getAutoCreate : function(){
759 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
760 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
765 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
767 if (this.toggle == true) {
770 cls: 'slider-frame roo-button',
775 'data-off-text':'OFF',
776 cls: 'slider-button',
782 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
783 cfg.cls += ' '+this.weight;
792 cfg["aria-hidden"] = true;
794 cfg.html = "×";
800 if (this.theme==='default') {
801 cfg.cls = 'btn roo-button';
803 //if (this.parentType != 'Navbar') {
804 this.weight = this.weight.length ? this.weight : 'default';
806 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
808 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
809 var weight = this.weight == 'default' ? 'secondary' : this.weight;
810 cfg.cls += ' btn-' + outline + weight;
811 if (this.weight == 'default') {
813 cfg.cls += ' btn-' + this.weight;
816 } else if (this.theme==='glow') {
819 cfg.cls = 'btn-glow roo-button';
821 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
823 cfg.cls += ' ' + this.weight;
829 this.cls += ' inverse';
833 if (this.active || this.pressed === true) {
834 cfg.cls += ' active';
838 cfg.disabled = 'disabled';
842 Roo.log('changing to ul' );
844 this.glyphicon = 'caret';
845 if (Roo.bootstrap.version == 4) {
846 this.fa = 'caret-down';
851 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
853 //gsRoo.log(this.parentType);
854 if (this.parentType === 'Navbar' && !this.parent().bar) {
855 Roo.log('changing to li?');
864 href : this.href || '#'
867 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
868 cfg.cls += ' dropdown';
875 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
877 if (this.glyphicon) {
878 cfg.html = ' ' + cfg.html;
883 cls: 'glyphicon glyphicon-' + this.glyphicon
888 cfg.html = ' ' + cfg.html;
893 cls: 'fa fas fa-' + this.fa
903 // cfg.cls='btn roo-button';
907 var value = cfg.html;
912 cls: 'glyphicon glyphicon-' + this.glyphicon,
919 cls: 'fa fas fa-' + this.fa,
924 var bw = this.badge_weight.length ? this.badge_weight :
925 (this.weight.length ? this.weight : 'secondary');
926 bw = bw == 'default' ? 'secondary' : bw;
932 cls: 'badge badge-' + bw,
941 cfg.cls += ' dropdown';
942 cfg.html = typeof(cfg.html) != 'undefined' ?
943 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
946 if (cfg.tag !== 'a' && this.href !== '') {
947 throw "Tag must be a to set href.";
948 } else if (this.href.length > 0) {
949 cfg.href = this.href;
952 if(this.removeClass){
957 cfg.target = this.target;
962 initEvents: function() {
963 // Roo.log('init events?');
964 // Roo.log(this.el.dom);
967 if (typeof (this.menu) != 'undefined') {
968 this.menu.parentType = this.xtype;
969 this.menu.triggerEl = this.el;
970 this.addxtype(Roo.apply({}, this.menu));
974 if (this.el.hasClass('roo-button')) {
975 this.el.on('click', this.onClick, this);
977 this.el.select('.roo-button').on('click', this.onClick, this);
980 if(this.removeClass){
981 this.el.on('click', this.onClick, this);
984 this.el.enableDisplayMode();
987 onClick : function(e)
993 Roo.log('button on click ');
994 if(this.preventDefault){
998 if (this.pressed === true || this.pressed === false) {
999 this.toggleActive(e);
1003 this.fireEvent('click', this, e);
1007 * Enables this button
1011 this.disabled = false;
1012 this.el.removeClass('disabled');
1016 * Disable this button
1018 disable : function()
1020 this.disabled = true;
1021 this.el.addClass('disabled');
1024 * sets the active state on/off,
1025 * @param {Boolean} state (optional) Force a particular state
1027 setActive : function(v) {
1029 this.el[v ? 'addClass' : 'removeClass']('active');
1033 * toggles the current active state
1035 toggleActive : function(e)
1037 this.setActive(!this.pressed);
1038 this.fireEvent('toggle', this, e, !this.pressed);
1041 * get the current active state
1042 * @return {boolean} true if it's active
1044 isActive : function()
1046 return this.el.hasClass('active');
1049 * set the text of the first selected button
1051 setText : function(str)
1053 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1056 * get the text of the first selected button
1058 getText : function()
1060 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1063 setWeight : function(str)
1065 this.el.removeClass(this.weightClass);
1067 var outline = this.outline ? 'outline-' : '';
1068 if (str == 'default') {
1069 this.el.addClass('btn-default btn-outline-secondary');
1072 this.el.addClass('btn-' + outline + str);
1086 * @class Roo.bootstrap.Column
1087 * @extends Roo.bootstrap.Component
1088 * Bootstrap Column class
1089 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1090 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1091 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1092 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1093 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1094 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1095 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1096 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1099 * @cfg {Boolean} hidden (true|false) hide the element
1100 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1101 * @cfg {String} fa (ban|check|...) font awesome icon
1102 * @cfg {Number} fasize (1|2|....) font awsome size
1104 * @cfg {String} icon (info-sign|check|...) glyphicon name
1106 * @cfg {String} html content of column.
1109 * Create a new Column
1110 * @param {Object} config The config object
1113 Roo.bootstrap.Column = function(config){
1114 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1117 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1135 getAutoCreate : function(){
1136 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1144 ['xs','sm','md','lg'].map(function(size){
1145 //Roo.log( size + ':' + settings[size]);
1147 if (settings[size+'off'] !== false) {
1148 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1151 if (settings[size] === false) {
1155 if (!settings[size]) { // 0 = hidden
1156 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1159 cfg.cls += ' col-' + size + '-' + settings[size] + (
1160 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1166 cfg.cls += ' hidden';
1169 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1170 cfg.cls +=' alert alert-' + this.alert;
1174 if (this.html.length) {
1175 cfg.html = this.html;
1179 if (this.fasize > 1) {
1180 fasize = ' fa-' + this.fasize + 'x';
1182 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1187 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1206 * @class Roo.bootstrap.Container
1207 * @extends Roo.bootstrap.Component
1208 * Bootstrap Container class
1209 * @cfg {Boolean} jumbotron is it a jumbotron element
1210 * @cfg {String} html content of element
1211 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1212 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1213 * @cfg {String} header content of header (for panel)
1214 * @cfg {String} footer content of footer (for panel)
1215 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1216 * @cfg {String} tag (header|aside|section) type of HTML tag.
1217 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1218 * @cfg {String} fa font awesome icon
1219 * @cfg {String} icon (info-sign|check|...) glyphicon name
1220 * @cfg {Boolean} hidden (true|false) hide the element
1221 * @cfg {Boolean} expandable (true|false) default false
1222 * @cfg {Boolean} expanded (true|false) default true
1223 * @cfg {String} rheader contet on the right of header
1224 * @cfg {Boolean} clickable (true|false) default false
1228 * Create a new Container
1229 * @param {Object} config The config object
1232 Roo.bootstrap.Container = function(config){
1233 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1239 * After the panel has been expand
1241 * @param {Roo.bootstrap.Container} this
1246 * After the panel has been collapsed
1248 * @param {Roo.bootstrap.Container} this
1253 * When a element is chick
1254 * @param {Roo.bootstrap.Container} this
1255 * @param {Roo.EventObject} e
1261 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1279 getChildContainer : function() {
1285 if (this.panel.length) {
1286 return this.el.select('.panel-body',true).first();
1293 getAutoCreate : function(){
1296 tag : this.tag || 'div',
1300 if (this.jumbotron) {
1301 cfg.cls = 'jumbotron';
1306 // - this is applied by the parent..
1308 // cfg.cls = this.cls + '';
1311 if (this.sticky.length) {
1313 var bd = Roo.get(document.body);
1314 if (!bd.hasClass('bootstrap-sticky')) {
1315 bd.addClass('bootstrap-sticky');
1316 Roo.select('html',true).setStyle('height', '100%');
1319 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1323 if (this.well.length) {
1324 switch (this.well) {
1327 cfg.cls +=' well well-' +this.well;
1336 cfg.cls += ' hidden';
1340 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1341 cfg.cls +=' alert alert-' + this.alert;
1346 if (this.panel.length) {
1347 cfg.cls += ' panel panel-' + this.panel;
1349 if (this.header.length) {
1353 if(this.expandable){
1355 cfg.cls = cfg.cls + ' expandable';
1359 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1367 cls : 'panel-title',
1368 html : (this.expandable ? ' ' : '') + this.header
1372 cls: 'panel-header-right',
1378 cls : 'panel-heading',
1379 style : this.expandable ? 'cursor: pointer' : '',
1387 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1392 if (this.footer.length) {
1394 cls : 'panel-footer',
1403 body.html = this.html || cfg.html;
1404 // prefix with the icons..
1406 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1409 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1414 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1415 cfg.cls = 'container';
1421 initEvents: function()
1423 if(this.expandable){
1424 var headerEl = this.headerEl();
1427 headerEl.on('click', this.onToggleClick, this);
1432 this.el.on('click', this.onClick, this);
1437 onToggleClick : function()
1439 var headerEl = this.headerEl();
1455 if(this.fireEvent('expand', this)) {
1457 this.expanded = true;
1459 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1461 this.el.select('.panel-body',true).first().removeClass('hide');
1463 var toggleEl = this.toggleEl();
1469 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1474 collapse : function()
1476 if(this.fireEvent('collapse', this)) {
1478 this.expanded = false;
1480 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1481 this.el.select('.panel-body',true).first().addClass('hide');
1483 var toggleEl = this.toggleEl();
1489 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1493 toggleEl : function()
1495 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1499 return this.el.select('.panel-heading .fa',true).first();
1502 headerEl : function()
1504 if(!this.el || !this.panel.length || !this.header.length){
1508 return this.el.select('.panel-heading',true).first()
1513 if(!this.el || !this.panel.length){
1517 return this.el.select('.panel-body',true).first()
1520 titleEl : function()
1522 if(!this.el || !this.panel.length || !this.header.length){
1526 return this.el.select('.panel-title',true).first();
1529 setTitle : function(v)
1531 var titleEl = this.titleEl();
1537 titleEl.dom.innerHTML = v;
1540 getTitle : function()
1543 var titleEl = this.titleEl();
1549 return titleEl.dom.innerHTML;
1552 setRightTitle : function(v)
1554 var t = this.el.select('.panel-header-right',true).first();
1560 t.dom.innerHTML = v;
1563 onClick : function(e)
1567 this.fireEvent('click', this, e);
1580 * @class Roo.bootstrap.Img
1581 * @extends Roo.bootstrap.Component
1582 * Bootstrap Img class
1583 * @cfg {Boolean} imgResponsive false | true
1584 * @cfg {String} border rounded | circle | thumbnail
1585 * @cfg {String} src image source
1586 * @cfg {String} alt image alternative text
1587 * @cfg {String} href a tag href
1588 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1589 * @cfg {String} xsUrl xs image source
1590 * @cfg {String} smUrl sm image source
1591 * @cfg {String} mdUrl md image source
1592 * @cfg {String} lgUrl lg image source
1595 * Create a new Input
1596 * @param {Object} config The config object
1599 Roo.bootstrap.Img = function(config){
1600 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1606 * The img click event for the img.
1607 * @param {Roo.EventObject} e
1613 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1615 imgResponsive: true,
1625 getAutoCreate : function()
1627 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1628 return this.createSingleImg();
1633 cls: 'roo-image-responsive-group',
1638 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1640 if(!_this[size + 'Url']){
1646 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1647 html: _this.html || cfg.html,
1648 src: _this[size + 'Url']
1651 img.cls += ' roo-image-responsive-' + size;
1653 var s = ['xs', 'sm', 'md', 'lg'];
1655 s.splice(s.indexOf(size), 1);
1657 Roo.each(s, function(ss){
1658 img.cls += ' hidden-' + ss;
1661 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1662 cfg.cls += ' img-' + _this.border;
1666 cfg.alt = _this.alt;
1679 a.target = _this.target;
1683 cfg.cn.push((_this.href) ? a : img);
1690 createSingleImg : function()
1694 cls: (this.imgResponsive) ? 'img-responsive' : '',
1696 src : 'about:blank' // just incase src get's set to undefined?!?
1699 cfg.html = this.html || cfg.html;
1701 cfg.src = this.src || cfg.src;
1703 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1704 cfg.cls += ' img-' + this.border;
1721 a.target = this.target;
1726 return (this.href) ? a : cfg;
1729 initEvents: function()
1732 this.el.on('click', this.onClick, this);
1737 onClick : function(e)
1739 Roo.log('img onclick');
1740 this.fireEvent('click', this, e);
1743 * Sets the url of the image - used to update it
1744 * @param {String} url the url of the image
1747 setSrc : function(url)
1751 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1752 this.el.dom.src = url;
1756 this.el.select('img', true).first().dom.src = url;
1772 * @class Roo.bootstrap.Link
1773 * @extends Roo.bootstrap.Component
1774 * Bootstrap Link Class
1775 * @cfg {String} alt image alternative text
1776 * @cfg {String} href a tag href
1777 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1778 * @cfg {String} html the content of the link.
1779 * @cfg {String} anchor name for the anchor link
1780 * @cfg {String} fa - favicon
1782 * @cfg {Boolean} preventDefault (true | false) default false
1786 * Create a new Input
1787 * @param {Object} config The config object
1790 Roo.bootstrap.Link = function(config){
1791 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1797 * The img click event for the img.
1798 * @param {Roo.EventObject} e
1804 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1808 preventDefault: false,
1814 getAutoCreate : function()
1816 var html = this.html || '';
1818 if (this.fa !== false) {
1819 html = '<i class="fa fa-' + this.fa + '"></i>';
1824 // anchor's do not require html/href...
1825 if (this.anchor === false) {
1827 cfg.href = this.href || '#';
1829 cfg.name = this.anchor;
1830 if (this.html !== false || this.fa !== false) {
1833 if (this.href !== false) {
1834 cfg.href = this.href;
1838 if(this.alt !== false){
1843 if(this.target !== false) {
1844 cfg.target = this.target;
1850 initEvents: function() {
1852 if(!this.href || this.preventDefault){
1853 this.el.on('click', this.onClick, this);
1857 onClick : function(e)
1859 if(this.preventDefault){
1862 //Roo.log('img onclick');
1863 this.fireEvent('click', this, e);
1876 * @class Roo.bootstrap.Header
1877 * @extends Roo.bootstrap.Component
1878 * Bootstrap Header class
1879 * @cfg {String} html content of header
1880 * @cfg {Number} level (1|2|3|4|5|6) default 1
1883 * Create a new Header
1884 * @param {Object} config The config object
1888 Roo.bootstrap.Header = function(config){
1889 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1892 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1900 getAutoCreate : function(){
1905 tag: 'h' + (1 *this.level),
1906 html: this.html || ''
1918 * Ext JS Library 1.1.1
1919 * Copyright(c) 2006-2007, Ext JS, LLC.
1921 * Originally Released Under LGPL - original licence link has changed is not relivant.
1924 * <script type="text/javascript">
1928 * @class Roo.bootstrap.MenuMgr
1929 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1932 Roo.bootstrap.MenuMgr = function(){
1933 var menus, active, groups = {}, attached = false, lastShow = new Date();
1935 // private - called when first menu is created
1938 active = new Roo.util.MixedCollection();
1939 Roo.get(document).addKeyListener(27, function(){
1940 if(active.length > 0){
1948 if(active && active.length > 0){
1949 var c = active.clone();
1959 if(active.length < 1){
1960 Roo.get(document).un("mouseup", onMouseDown);
1968 var last = active.last();
1969 lastShow = new Date();
1972 Roo.get(document).on("mouseup", onMouseDown);
1977 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1978 m.parentMenu.activeChild = m;
1979 }else if(last && last.isVisible()){
1980 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1985 function onBeforeHide(m){
1987 m.activeChild.hide();
1989 if(m.autoHideTimer){
1990 clearTimeout(m.autoHideTimer);
1991 delete m.autoHideTimer;
1996 function onBeforeShow(m){
1997 var pm = m.parentMenu;
1998 if(!pm && !m.allowOtherMenus){
2000 }else if(pm && pm.activeChild && active != m){
2001 pm.activeChild.hide();
2005 // private this should really trigger on mouseup..
2006 function onMouseDown(e){
2007 Roo.log("on Mouse Up");
2009 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
2010 Roo.log("MenuManager hideAll");
2019 function onBeforeCheck(mi, state){
2021 var g = groups[mi.group];
2022 for(var i = 0, l = g.length; i < l; i++){
2024 g[i].setChecked(false);
2033 * Hides all menus that are currently visible
2035 hideAll : function(){
2040 register : function(menu){
2044 menus[menu.id] = menu;
2045 menu.on("beforehide", onBeforeHide);
2046 menu.on("hide", onHide);
2047 menu.on("beforeshow", onBeforeShow);
2048 menu.on("show", onShow);
2050 if(g && menu.events["checkchange"]){
2054 groups[g].push(menu);
2055 menu.on("checkchange", onCheck);
2060 * Returns a {@link Roo.menu.Menu} object
2061 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
2062 * be used to generate and return a new Menu instance.
2064 get : function(menu){
2065 if(typeof menu == "string"){ // menu id
2067 }else if(menu.events){ // menu instance
2070 /*else if(typeof menu.length == 'number'){ // array of menu items?
2071 return new Roo.bootstrap.Menu({items:menu});
2072 }else{ // otherwise, must be a config
2073 return new Roo.bootstrap.Menu(menu);
2080 unregister : function(menu){
2081 delete menus[menu.id];
2082 menu.un("beforehide", onBeforeHide);
2083 menu.un("hide", onHide);
2084 menu.un("beforeshow", onBeforeShow);
2085 menu.un("show", onShow);
2087 if(g && menu.events["checkchange"]){
2088 groups[g].remove(menu);
2089 menu.un("checkchange", onCheck);
2094 registerCheckable : function(menuItem){
2095 var g = menuItem.group;
2100 groups[g].push(menuItem);
2101 menuItem.on("beforecheckchange", onBeforeCheck);
2106 unregisterCheckable : function(menuItem){
2107 var g = menuItem.group;
2109 groups[g].remove(menuItem);
2110 menuItem.un("beforecheckchange", onBeforeCheck);
2122 * @class Roo.bootstrap.Menu
2123 * @extends Roo.bootstrap.Component
2124 * Bootstrap Menu class - container for MenuItems
2125 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2126 * @cfg {bool} hidden if the menu should be hidden when rendered.
2127 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2128 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2132 * @param {Object} config The config object
2136 Roo.bootstrap.Menu = function(config){
2137 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2138 if (this.registerMenu && this.type != 'treeview') {
2139 Roo.bootstrap.MenuMgr.register(this);
2146 * Fires before this menu is displayed (return false to block)
2147 * @param {Roo.menu.Menu} this
2152 * Fires before this menu is hidden (return false to block)
2153 * @param {Roo.menu.Menu} this
2158 * Fires after this menu is displayed
2159 * @param {Roo.menu.Menu} this
2164 * Fires after this menu is hidden
2165 * @param {Roo.menu.Menu} this
2170 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2171 * @param {Roo.menu.Menu} this
2172 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2173 * @param {Roo.EventObject} e
2178 * Fires when the mouse is hovering over this menu
2179 * @param {Roo.menu.Menu} this
2180 * @param {Roo.EventObject} e
2181 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2186 * Fires when the mouse exits this menu
2187 * @param {Roo.menu.Menu} this
2188 * @param {Roo.EventObject} e
2189 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2194 * Fires when a menu item contained in this menu is clicked
2195 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2196 * @param {Roo.EventObject} e
2200 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2203 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2207 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2210 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2212 registerMenu : true,
2214 menuItems :false, // stores the menu items..
2224 getChildContainer : function() {
2228 getAutoCreate : function(){
2230 //if (['right'].indexOf(this.align)!==-1) {
2231 // cfg.cn[1].cls += ' pull-right'
2237 cls : 'dropdown-menu' ,
2238 style : 'z-index:1000'
2242 if (this.type === 'submenu') {
2243 cfg.cls = 'submenu active';
2245 if (this.type === 'treeview') {
2246 cfg.cls = 'treeview-menu';
2251 initEvents : function() {
2253 // Roo.log("ADD event");
2254 // Roo.log(this.triggerEl.dom);
2256 this.triggerEl.on('click', this.onTriggerClick, this);
2258 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2261 if (this.triggerEl.hasClass('nav-item')) {
2262 // dropdown toggle on the 'a' in BS4?
2263 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2265 this.triggerEl.addClass('dropdown-toggle');
2268 this.el.on('touchstart' , this.onTouch, this);
2270 this.el.on('click' , this.onClick, this);
2272 this.el.on("mouseover", this.onMouseOver, this);
2273 this.el.on("mouseout", this.onMouseOut, this);
2277 findTargetItem : function(e)
2279 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2283 //Roo.log(t); Roo.log(t.id);
2285 //Roo.log(this.menuitems);
2286 return this.menuitems.get(t.id);
2288 //return this.items.get(t.menuItemId);
2294 onTouch : function(e)
2296 Roo.log("menu.onTouch");
2297 //e.stopEvent(); this make the user popdown broken
2301 onClick : function(e)
2303 Roo.log("menu.onClick");
2305 var t = this.findTargetItem(e);
2306 if(!t || t.isContainer){
2311 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2312 if(t == this.activeItem && t.shouldDeactivate(e)){
2313 this.activeItem.deactivate();
2314 delete this.activeItem;
2318 this.setActiveItem(t, true);
2326 Roo.log('pass click event');
2330 this.fireEvent("click", this, t, e);
2334 if(!t.href.length || t.href == '#'){
2335 (function() { _this.hide(); }).defer(100);
2340 onMouseOver : function(e){
2341 var t = this.findTargetItem(e);
2344 // if(t.canActivate && !t.disabled){
2345 // this.setActiveItem(t, true);
2349 this.fireEvent("mouseover", this, e, t);
2351 isVisible : function(){
2352 return !this.hidden;
2354 onMouseOut : function(e){
2355 var t = this.findTargetItem(e);
2358 // if(t == this.activeItem && t.shouldDeactivate(e)){
2359 // this.activeItem.deactivate();
2360 // delete this.activeItem;
2363 this.fireEvent("mouseout", this, e, t);
2368 * Displays this menu relative to another element
2369 * @param {String/HTMLElement/Roo.Element} element The element to align to
2370 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2371 * the element (defaults to this.defaultAlign)
2372 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2374 show : function(el, pos, parentMenu)
2376 if (false === this.fireEvent("beforeshow", this)) {
2377 Roo.log("show canceled");
2380 this.parentMenu = parentMenu;
2385 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2388 * Displays this menu at a specific xy position
2389 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2390 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2392 showAt : function(xy, parentMenu, /* private: */_e){
2393 this.parentMenu = parentMenu;
2398 this.fireEvent("beforeshow", this);
2399 //xy = this.el.adjustForConstraints(xy);
2403 this.hideMenuItems();
2404 this.hidden = false;
2405 this.triggerEl.addClass('open');
2406 this.el.addClass('show');
2408 // reassign x when hitting right
2409 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2410 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2413 // reassign y when hitting bottom
2414 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2415 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2418 // but the list may align on trigger left or trigger top... should it be a properity?
2420 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2425 this.fireEvent("show", this);
2431 this.doFocus.defer(50, this);
2435 doFocus : function(){
2437 this.focusEl.focus();
2442 * Hides this menu and optionally all parent menus
2443 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2445 hide : function(deep)
2447 if (false === this.fireEvent("beforehide", this)) {
2448 Roo.log("hide canceled");
2451 this.hideMenuItems();
2452 if(this.el && this.isVisible()){
2454 if(this.activeItem){
2455 this.activeItem.deactivate();
2456 this.activeItem = null;
2458 this.triggerEl.removeClass('open');;
2459 this.el.removeClass('show');
2461 this.fireEvent("hide", this);
2463 if(deep === true && this.parentMenu){
2464 this.parentMenu.hide(true);
2468 onTriggerClick : function(e)
2470 Roo.log('trigger click');
2472 var target = e.getTarget();
2474 Roo.log(target.nodeName.toLowerCase());
2476 if(target.nodeName.toLowerCase() === 'i'){
2482 onTriggerPress : function(e)
2484 Roo.log('trigger press');
2485 //Roo.log(e.getTarget());
2486 // Roo.log(this.triggerEl.dom);
2488 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2489 var pel = Roo.get(e.getTarget());
2490 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2491 Roo.log('is treeview or dropdown?');
2495 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2499 if (this.isVisible()) {
2504 this.show(this.triggerEl, '?', false);
2507 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2514 hideMenuItems : function()
2516 Roo.log("hide Menu Items");
2521 this.el.select('.open',true).each(function(aa) {
2523 aa.removeClass('open');
2527 addxtypeChild : function (tree, cntr) {
2528 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2530 this.menuitems.add(comp);
2542 this.getEl().dom.innerHTML = '';
2543 this.menuitems.clear();
2557 * @class Roo.bootstrap.MenuItem
2558 * @extends Roo.bootstrap.Component
2559 * Bootstrap MenuItem class
2560 * @cfg {String} html the menu label
2561 * @cfg {String} href the link
2562 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2563 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2564 * @cfg {Boolean} active used on sidebars to highlight active itesm
2565 * @cfg {String} fa favicon to show on left of menu item.
2566 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2570 * Create a new MenuItem
2571 * @param {Object} config The config object
2575 Roo.bootstrap.MenuItem = function(config){
2576 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2581 * The raw click event for the entire grid.
2582 * @param {Roo.bootstrap.MenuItem} this
2583 * @param {Roo.EventObject} e
2589 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2593 preventDefault: false,
2594 isContainer : false,
2598 getAutoCreate : function(){
2600 if(this.isContainer){
2603 cls: 'dropdown-menu-item '
2613 cls : 'dropdown-item',
2618 if (this.fa !== false) {
2621 cls : 'fa fa-' + this.fa
2630 cls: 'dropdown-menu-item',
2633 if (this.parent().type == 'treeview') {
2634 cfg.cls = 'treeview-menu';
2637 cfg.cls += ' active';
2642 anc.href = this.href || cfg.cn[0].href ;
2643 ctag.html = this.html || cfg.cn[0].html ;
2647 initEvents: function()
2649 if (this.parent().type == 'treeview') {
2650 this.el.select('a').on('click', this.onClick, this);
2654 this.menu.parentType = this.xtype;
2655 this.menu.triggerEl = this.el;
2656 this.menu = this.addxtype(Roo.apply({}, this.menu));
2660 onClick : function(e)
2662 Roo.log('item on click ');
2664 if(this.preventDefault){
2667 //this.parent().hideMenuItems();
2669 this.fireEvent('click', this, e);
2688 * @class Roo.bootstrap.MenuSeparator
2689 * @extends Roo.bootstrap.Component
2690 * Bootstrap MenuSeparator class
2693 * Create a new MenuItem
2694 * @param {Object} config The config object
2698 Roo.bootstrap.MenuSeparator = function(config){
2699 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2702 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2704 getAutoCreate : function(){
2723 * @class Roo.bootstrap.Modal
2724 * @extends Roo.bootstrap.Component
2725 * Bootstrap Modal class
2726 * @cfg {String} title Title of dialog
2727 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2728 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2729 * @cfg {Boolean} specificTitle default false
2730 * @cfg {Array} buttons Array of buttons or standard button set..
2731 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2732 * @cfg {Boolean} animate default true
2733 * @cfg {Boolean} allow_close default true
2734 * @cfg {Boolean} fitwindow default false
2735 * @cfg {String} size (sm|lg) default empty
2736 * @cfg {Number} max_width set the max width of modal
2740 * Create a new Modal Dialog
2741 * @param {Object} config The config object
2744 Roo.bootstrap.Modal = function(config){
2745 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2750 * The raw btnclick event for the button
2751 * @param {Roo.EventObject} e
2756 * Fire when dialog resize
2757 * @param {Roo.bootstrap.Modal} this
2758 * @param {Roo.EventObject} e
2762 this.buttons = this.buttons || [];
2765 this.tmpl = Roo.factory(this.tmpl);
2770 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2772 title : 'test dialog',
2782 specificTitle: false,
2784 buttonPosition: 'right',
2807 onRender : function(ct, position)
2809 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2812 var cfg = Roo.apply({}, this.getAutoCreate());
2815 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2817 //if (!cfg.name.length) {
2821 cfg.cls += ' ' + this.cls;
2824 cfg.style = this.style;
2826 this.el = Roo.get(document.body).createChild(cfg, position);
2828 //var type = this.el.dom.type;
2831 if(this.tabIndex !== undefined){
2832 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2835 this.dialogEl = this.el.select('.modal-dialog',true).first();
2836 this.bodyEl = this.el.select('.modal-body',true).first();
2837 this.closeEl = this.el.select('.modal-header .close', true).first();
2838 this.headerEl = this.el.select('.modal-header',true).first();
2839 this.titleEl = this.el.select('.modal-title',true).first();
2840 this.footerEl = this.el.select('.modal-footer',true).first();
2842 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2844 //this.el.addClass("x-dlg-modal");
2846 if (this.buttons.length) {
2847 Roo.each(this.buttons, function(bb) {
2848 var b = Roo.apply({}, bb);
2849 b.xns = b.xns || Roo.bootstrap;
2850 b.xtype = b.xtype || 'Button';
2851 if (typeof(b.listeners) == 'undefined') {
2852 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2855 var btn = Roo.factory(b);
2857 btn.render(this.getButtonContainer());
2861 // render the children.
2864 if(typeof(this.items) != 'undefined'){
2865 var items = this.items;
2868 for(var i =0;i < items.length;i++) {
2869 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2873 this.items = nitems;
2875 // where are these used - they used to be body/close/footer
2879 //this.el.addClass([this.fieldClass, this.cls]);
2883 getAutoCreate : function()
2887 html : this.html || ''
2892 cls : 'modal-title',
2896 if(this.specificTitle){
2902 if (this.allow_close && Roo.bootstrap.version == 3) {
2912 if (this.allow_close && Roo.bootstrap.version == 4) {
2922 if(this.size.length){
2923 size = 'modal-' + this.size;
2926 var footer = Roo.bootstrap.version == 3 ?
2928 cls : 'modal-footer',
2932 cls: 'btn-' + this.buttonPosition
2937 { // BS4 uses mr-auto on left buttons....
2938 cls : 'modal-footer'
2949 cls: "modal-dialog " + size,
2952 cls : "modal-content",
2955 cls : 'modal-header',
2970 modal.cls += ' fade';
2976 getChildContainer : function() {
2981 getButtonContainer : function() {
2983 return Roo.bootstrap.version == 4 ?
2984 this.el.select('.modal-footer',true).first()
2985 : this.el.select('.modal-footer div',true).first();
2988 initEvents : function()
2990 if (this.allow_close) {
2991 this.closeEl.on('click', this.hide, this);
2993 Roo.EventManager.onWindowResize(this.resize, this, true);
3001 this.maskEl.setSize(
3002 Roo.lib.Dom.getViewWidth(true),
3003 Roo.lib.Dom.getViewHeight(true)
3006 if (this.fitwindow) {
3010 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
3011 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
3016 if(this.max_width !== 0) {
3018 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
3021 this.setSize(w, this.height);
3025 if(this.max_height) {
3026 this.setSize(w,Math.min(
3028 Roo.lib.Dom.getViewportHeight(true) - 60
3034 if(!this.fit_content) {
3035 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
3039 this.setSize(w, Math.min(
3041 this.headerEl.getHeight() +
3042 this.footerEl.getHeight() +
3043 this.getChildHeight(this.bodyEl.dom.childNodes),
3044 Roo.lib.Dom.getViewportHeight(true) - 60)
3050 setSize : function(w,h)
3061 if (!this.rendered) {
3065 //this.el.setStyle('display', 'block');
3066 this.el.removeClass('hideing');
3067 this.el.dom.style.display='block';
3069 Roo.get(document.body).addClass('modal-open');
3071 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3074 this.el.addClass('show');
3075 this.el.addClass('in');
3078 this.el.addClass('show');
3079 this.el.addClass('in');
3082 // not sure how we can show data in here..
3084 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3087 Roo.get(document.body).addClass("x-body-masked");
3089 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3090 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3091 this.maskEl.dom.style.display = 'block';
3092 this.maskEl.addClass('show');
3097 this.fireEvent('show', this);
3099 // set zindex here - otherwise it appears to be ignored...
3100 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3103 this.items.forEach( function(e) {
3104 e.layout ? e.layout() : false;
3112 if(this.fireEvent("beforehide", this) !== false){
3114 this.maskEl.removeClass('show');
3116 this.maskEl.dom.style.display = '';
3117 Roo.get(document.body).removeClass("x-body-masked");
3118 this.el.removeClass('in');
3119 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3121 if(this.animate){ // why
3122 this.el.addClass('hideing');
3123 this.el.removeClass('show');
3125 if (!this.el.hasClass('hideing')) {
3126 return; // it's been shown again...
3129 this.el.dom.style.display='';
3131 Roo.get(document.body).removeClass('modal-open');
3132 this.el.removeClass('hideing');
3136 this.el.removeClass('show');
3137 this.el.dom.style.display='';
3138 Roo.get(document.body).removeClass('modal-open');
3141 this.fireEvent('hide', this);
3144 isVisible : function()
3147 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3151 addButton : function(str, cb)
3155 var b = Roo.apply({}, { html : str } );
3156 b.xns = b.xns || Roo.bootstrap;
3157 b.xtype = b.xtype || 'Button';
3158 if (typeof(b.listeners) == 'undefined') {
3159 b.listeners = { click : cb.createDelegate(this) };
3162 var btn = Roo.factory(b);
3164 btn.render(this.getButtonContainer());
3170 setDefaultButton : function(btn)
3172 //this.el.select('.modal-footer').()
3175 resizeTo: function(w,h)
3177 this.dialogEl.setWidth(w);
3179 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3181 this.bodyEl.setHeight(h - diff);
3183 this.fireEvent('resize', this);
3186 setContentSize : function(w, h)
3190 onButtonClick: function(btn,e)
3193 this.fireEvent('btnclick', btn.name, e);
3196 * Set the title of the Dialog
3197 * @param {String} str new Title
3199 setTitle: function(str) {
3200 this.titleEl.dom.innerHTML = str;
3203 * Set the body of the Dialog
3204 * @param {String} str new Title
3206 setBody: function(str) {
3207 this.bodyEl.dom.innerHTML = str;
3210 * Set the body of the Dialog using the template
3211 * @param {Obj} data - apply this data to the template and replace the body contents.
3213 applyBody: function(obj)
3216 Roo.log("Error - using apply Body without a template");
3219 this.tmpl.overwrite(this.bodyEl, obj);
3222 getChildHeight : function(child_nodes)
3226 child_nodes.length == 0
3231 var child_height = 0;
3233 for(var i = 0; i < child_nodes.length; i++) {
3236 * for modal with tabs...
3237 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3239 var layout_childs = child_nodes[i].childNodes;
3241 for(var j = 0; j < layout_childs.length; j++) {
3243 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3245 var layout_body_childs = layout_childs[j].childNodes;
3247 for(var k = 0; k < layout_body_childs.length; k++) {
3249 if(layout_body_childs[k].classList.contains('navbar')) {
3250 child_height += layout_body_childs[k].offsetHeight;
3254 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3256 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3258 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3260 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3261 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3276 child_height += child_nodes[i].offsetHeight;
3277 // Roo.log(child_nodes[i].offsetHeight);
3280 return child_height;
3286 Roo.apply(Roo.bootstrap.Modal, {
3288 * Button config that displays a single OK button
3297 * Button config that displays Yes and No buttons
3313 * Button config that displays OK and Cancel buttons
3328 * Button config that displays Yes, No and Cancel buttons
3352 * messagebox - can be used as a replace
3356 * @class Roo.MessageBox
3357 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3361 Roo.Msg.alert('Status', 'Changes saved successfully.');
3363 // Prompt for user data:
3364 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3366 // process text value...
3370 // Show a dialog using config options:
3372 title:'Save Changes?',
3373 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3374 buttons: Roo.Msg.YESNOCANCEL,
3381 Roo.bootstrap.MessageBox = function(){
3382 var dlg, opt, mask, waitTimer;
3383 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3384 var buttons, activeTextEl, bwidth;
3388 var handleButton = function(button){
3390 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3394 var handleHide = function(){
3396 dlg.el.removeClass(opt.cls);
3399 // Roo.TaskMgr.stop(waitTimer);
3400 // waitTimer = null;
3405 var updateButtons = function(b){
3408 buttons["ok"].hide();
3409 buttons["cancel"].hide();
3410 buttons["yes"].hide();
3411 buttons["no"].hide();
3412 dlg.footerEl.hide();
3416 dlg.footerEl.show();
3417 for(var k in buttons){
3418 if(typeof buttons[k] != "function"){
3421 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3422 width += buttons[k].el.getWidth()+15;
3432 var handleEsc = function(d, k, e){
3433 if(opt && opt.closable !== false){
3443 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3444 * @return {Roo.BasicDialog} The BasicDialog element
3446 getDialog : function(){
3448 dlg = new Roo.bootstrap.Modal( {
3451 //constraintoviewport:false,
3453 //collapsible : false,
3458 //buttonAlign:"center",
3459 closeClick : function(){
3460 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3463 handleButton("cancel");
3468 dlg.on("hide", handleHide);
3470 //dlg.addKeyListener(27, handleEsc);
3472 this.buttons = buttons;
3473 var bt = this.buttonText;
3474 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3475 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3476 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3477 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3479 bodyEl = dlg.bodyEl.createChild({
3481 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3482 '<textarea class="roo-mb-textarea"></textarea>' +
3483 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3485 msgEl = bodyEl.dom.firstChild;
3486 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3487 textboxEl.enableDisplayMode();
3488 textboxEl.addKeyListener([10,13], function(){
3489 if(dlg.isVisible() && opt && opt.buttons){
3492 }else if(opt.buttons.yes){
3493 handleButton("yes");
3497 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3498 textareaEl.enableDisplayMode();
3499 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3500 progressEl.enableDisplayMode();
3502 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3503 var pf = progressEl.dom.firstChild;
3505 pp = Roo.get(pf.firstChild);
3506 pp.setHeight(pf.offsetHeight);
3514 * Updates the message box body text
3515 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3516 * the XHTML-compliant non-breaking space character '&#160;')
3517 * @return {Roo.MessageBox} This message box
3519 updateText : function(text)
3521 if(!dlg.isVisible() && !opt.width){
3522 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3523 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3525 msgEl.innerHTML = text || ' ';
3527 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3528 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3530 Math.min(opt.width || cw , this.maxWidth),
3531 Math.max(opt.minWidth || this.minWidth, bwidth)
3534 activeTextEl.setWidth(w);
3536 if(dlg.isVisible()){
3537 dlg.fixedcenter = false;
3539 // to big, make it scroll. = But as usual stupid IE does not support
3542 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3543 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3544 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3546 bodyEl.dom.style.height = '';
3547 bodyEl.dom.style.overflowY = '';
3550 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3552 bodyEl.dom.style.overflowX = '';
3555 dlg.setContentSize(w, bodyEl.getHeight());
3556 if(dlg.isVisible()){
3557 dlg.fixedcenter = true;
3563 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3564 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3565 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3566 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3567 * @return {Roo.MessageBox} This message box
3569 updateProgress : function(value, text){
3571 this.updateText(text);
3574 if (pp) { // weird bug on my firefox - for some reason this is not defined
3575 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3576 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3582 * Returns true if the message box is currently displayed
3583 * @return {Boolean} True if the message box is visible, else false
3585 isVisible : function(){
3586 return dlg && dlg.isVisible();
3590 * Hides the message box if it is displayed
3593 if(this.isVisible()){
3599 * Displays a new message box, or reinitializes an existing message box, based on the config options
3600 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3601 * The following config object properties are supported:
3603 Property Type Description
3604 ---------- --------------- ------------------------------------------------------------------------------------
3605 animEl String/Element An id or Element from which the message box should animate as it opens and
3606 closes (defaults to undefined)
3607 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3608 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3609 closable Boolean False to hide the top-right close button (defaults to true). Note that
3610 progress and wait dialogs will ignore this property and always hide the
3611 close button as they can only be closed programmatically.
3612 cls String A custom CSS class to apply to the message box element
3613 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3614 displayed (defaults to 75)
3615 fn Function A callback function to execute after closing the dialog. The arguments to the
3616 function will be btn (the name of the button that was clicked, if applicable,
3617 e.g. "ok"), and text (the value of the active text field, if applicable).
3618 Progress and wait dialogs will ignore this option since they do not respond to
3619 user actions and can only be closed programmatically, so any required function
3620 should be called by the same code after it closes the dialog.
3621 icon String A CSS class that provides a background image to be used as an icon for
3622 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3623 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3624 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3625 modal Boolean False to allow user interaction with the page while the message box is
3626 displayed (defaults to true)
3627 msg String A string that will replace the existing message box body text (defaults
3628 to the XHTML-compliant non-breaking space character ' ')
3629 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3630 progress Boolean True to display a progress bar (defaults to false)
3631 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3632 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3633 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3634 title String The title text
3635 value String The string value to set into the active textbox element if displayed
3636 wait Boolean True to display a progress bar (defaults to false)
3637 width Number The width of the dialog in pixels
3644 msg: 'Please enter your address:',
3646 buttons: Roo.MessageBox.OKCANCEL,
3649 animEl: 'addAddressBtn'
3652 * @param {Object} config Configuration options
3653 * @return {Roo.MessageBox} This message box
3655 show : function(options)
3658 // this causes nightmares if you show one dialog after another
3659 // especially on callbacks..
3661 if(this.isVisible()){
3664 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3665 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3666 Roo.log("New Dialog Message:" + options.msg )
3667 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3668 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3671 var d = this.getDialog();
3673 d.setTitle(opt.title || " ");
3674 d.closeEl.setDisplayed(opt.closable !== false);
3675 activeTextEl = textboxEl;
3676 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3681 textareaEl.setHeight(typeof opt.multiline == "number" ?
3682 opt.multiline : this.defaultTextHeight);
3683 activeTextEl = textareaEl;
3692 progressEl.setDisplayed(opt.progress === true);
3694 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3696 this.updateProgress(0);
3697 activeTextEl.dom.value = opt.value || "";
3699 dlg.setDefaultButton(activeTextEl);
3701 var bs = opt.buttons;
3705 }else if(bs && bs.yes){
3706 db = buttons["yes"];
3708 dlg.setDefaultButton(db);
3710 bwidth = updateButtons(opt.buttons);
3711 this.updateText(opt.msg);
3713 d.el.addClass(opt.cls);
3715 d.proxyDrag = opt.proxyDrag === true;
3716 d.modal = opt.modal !== false;
3717 d.mask = opt.modal !== false ? mask : false;
3719 // force it to the end of the z-index stack so it gets a cursor in FF
3720 document.body.appendChild(dlg.el.dom);
3721 d.animateTarget = null;
3722 d.show(options.animEl);
3728 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3729 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3730 * and closing the message box when the process is complete.
3731 * @param {String} title The title bar text
3732 * @param {String} msg The message box body text
3733 * @return {Roo.MessageBox} This message box
3735 progress : function(title, msg){
3742 minWidth: this.minProgressWidth,
3749 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3750 * If a callback function is passed it will be called after the user clicks the button, and the
3751 * id of the button that was clicked will be passed as the only parameter to the callback
3752 * (could also be the top-right close button).
3753 * @param {String} title The title bar text
3754 * @param {String} msg The message box body text
3755 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3756 * @param {Object} scope (optional) The scope of the callback function
3757 * @return {Roo.MessageBox} This message box
3759 alert : function(title, msg, fn, scope)
3774 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3775 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3776 * You are responsible for closing the message box when the process is complete.
3777 * @param {String} msg The message box body text
3778 * @param {String} title (optional) The title bar text
3779 * @return {Roo.MessageBox} This message box
3781 wait : function(msg, title){
3792 waitTimer = Roo.TaskMgr.start({
3794 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3802 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3803 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3804 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3805 * @param {String} title The title bar text
3806 * @param {String} msg The message box body text
3807 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3808 * @param {Object} scope (optional) The scope of the callback function
3809 * @return {Roo.MessageBox} This message box
3811 confirm : function(title, msg, fn, scope){
3815 buttons: this.YESNO,
3824 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3825 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3826 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3827 * (could also be the top-right close button) and the text that was entered will be passed as the two
3828 * parameters to the callback.
3829 * @param {String} title The title bar text
3830 * @param {String} msg The message box body text
3831 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3832 * @param {Object} scope (optional) The scope of the callback function
3833 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3834 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3835 * @return {Roo.MessageBox} This message box
3837 prompt : function(title, msg, fn, scope, multiline){
3841 buttons: this.OKCANCEL,
3846 multiline: multiline,
3853 * Button config that displays a single OK button
3858 * Button config that displays Yes and No buttons
3861 YESNO : {yes:true, no:true},
3863 * Button config that displays OK and Cancel buttons
3866 OKCANCEL : {ok:true, cancel:true},
3868 * Button config that displays Yes, No and Cancel buttons
3871 YESNOCANCEL : {yes:true, no:true, cancel:true},
3874 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3877 defaultTextHeight : 75,
3879 * The maximum width in pixels of the message box (defaults to 600)
3884 * The minimum width in pixels of the message box (defaults to 100)
3889 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3890 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3893 minProgressWidth : 250,
3895 * An object containing the default button text strings that can be overriden for localized language support.
3896 * Supported properties are: ok, cancel, yes and no.
3897 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3910 * Shorthand for {@link Roo.MessageBox}
3912 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3913 Roo.Msg = Roo.Msg || Roo.MessageBox;
3922 * @class Roo.bootstrap.Navbar
3923 * @extends Roo.bootstrap.Component
3924 * Bootstrap Navbar class
3927 * Create a new Navbar
3928 * @param {Object} config The config object
3932 Roo.bootstrap.Navbar = function(config){
3933 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3937 * @event beforetoggle
3938 * Fire before toggle the menu
3939 * @param {Roo.EventObject} e
3941 "beforetoggle" : true
3945 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3954 getAutoCreate : function(){
3957 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3961 initEvents :function ()
3963 //Roo.log(this.el.select('.navbar-toggle',true));
3964 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3971 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3973 var size = this.el.getSize();
3974 this.maskEl.setSize(size.width, size.height);
3975 this.maskEl.enableDisplayMode("block");
3984 getChildContainer : function()
3986 if (this.el && this.el.select('.collapse').getCount()) {
3987 return this.el.select('.collapse',true).first();
4002 onToggle : function()
4005 if(this.fireEvent('beforetoggle', this) === false){
4008 var ce = this.el.select('.navbar-collapse',true).first();
4010 if (!ce.hasClass('show')) {
4020 * Expand the navbar pulldown
4022 expand : function ()
4025 var ce = this.el.select('.navbar-collapse',true).first();
4026 if (ce.hasClass('collapsing')) {
4029 ce.dom.style.height = '';
4031 ce.addClass('in'); // old...
4032 ce.removeClass('collapse');
4033 ce.addClass('show');
4034 var h = ce.getHeight();
4036 ce.removeClass('show');
4037 // at this point we should be able to see it..
4038 ce.addClass('collapsing');
4040 ce.setHeight(0); // resize it ...
4041 ce.on('transitionend', function() {
4042 //Roo.log('done transition');
4043 ce.removeClass('collapsing');
4044 ce.addClass('show');
4045 ce.removeClass('collapse');
4047 ce.dom.style.height = '';
4048 }, this, { single: true} );
4050 ce.dom.scrollTop = 0;
4053 * Collapse the navbar pulldown
4055 collapse : function()
4057 var ce = this.el.select('.navbar-collapse',true).first();
4059 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
4060 // it's collapsed or collapsing..
4063 ce.removeClass('in'); // old...
4064 ce.setHeight(ce.getHeight());
4065 ce.removeClass('show');
4066 ce.addClass('collapsing');
4068 ce.on('transitionend', function() {
4069 ce.dom.style.height = '';
4070 ce.removeClass('collapsing');
4071 ce.addClass('collapse');
4072 }, this, { single: true} );
4092 * @class Roo.bootstrap.NavSimplebar
4093 * @extends Roo.bootstrap.Navbar
4094 * Bootstrap Sidebar class
4096 * @cfg {Boolean} inverse is inverted color
4098 * @cfg {String} type (nav | pills | tabs)
4099 * @cfg {Boolean} arrangement stacked | justified
4100 * @cfg {String} align (left | right) alignment
4102 * @cfg {Boolean} main (true|false) main nav bar? default false
4103 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4105 * @cfg {String} tag (header|footer|nav|div) default is nav
4107 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4111 * Create a new Sidebar
4112 * @param {Object} config The config object
4116 Roo.bootstrap.NavSimplebar = function(config){
4117 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4120 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4136 getAutoCreate : function(){
4140 tag : this.tag || 'div',
4141 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4143 if (['light','white'].indexOf(this.weight) > -1) {
4144 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4146 cfg.cls += ' bg-' + this.weight;
4149 cfg.cls += ' navbar-inverse';
4153 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4155 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4164 cls: 'nav nav-' + this.xtype,
4170 this.type = this.type || 'nav';
4171 if (['tabs','pills'].indexOf(this.type) != -1) {
4172 cfg.cn[0].cls += ' nav-' + this.type
4176 if (this.type!=='nav') {
4177 Roo.log('nav type must be nav/tabs/pills')
4179 cfg.cn[0].cls += ' navbar-nav'
4185 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4186 cfg.cn[0].cls += ' nav-' + this.arrangement;
4190 if (this.align === 'right') {
4191 cfg.cn[0].cls += ' navbar-right';
4216 * navbar-expand-md fixed-top
4220 * @class Roo.bootstrap.NavHeaderbar
4221 * @extends Roo.bootstrap.NavSimplebar
4222 * Bootstrap Sidebar class
4224 * @cfg {String} brand what is brand
4225 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4226 * @cfg {String} brand_href href of the brand
4227 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4228 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4229 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4230 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4233 * Create a new Sidebar
4234 * @param {Object} config The config object
4238 Roo.bootstrap.NavHeaderbar = function(config){
4239 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4243 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4250 desktopCenter : false,
4253 getAutoCreate : function(){
4256 tag: this.nav || 'nav',
4257 cls: 'navbar navbar-expand-md',
4263 if (this.desktopCenter) {
4264 cn.push({cls : 'container', cn : []});
4272 cls: 'navbar-toggle navbar-toggler',
4273 'data-toggle': 'collapse',
4278 html: 'Toggle navigation'
4282 cls: 'icon-bar navbar-toggler-icon'
4295 cn.push( Roo.bootstrap.version == 4 ? btn : {
4297 cls: 'navbar-header',
4306 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4310 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4312 if (['light','white'].indexOf(this.weight) > -1) {
4313 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4315 cfg.cls += ' bg-' + this.weight;
4318 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4319 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4321 // tag can override this..
4323 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4326 if (this.brand !== '') {
4327 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4328 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4330 href: this.brand_href ? this.brand_href : '#',
4331 cls: 'navbar-brand',
4339 cfg.cls += ' main-nav';
4347 getHeaderChildContainer : function()
4349 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4350 return this.el.select('.navbar-header',true).first();
4353 return this.getChildContainer();
4357 initEvents : function()
4359 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4361 if (this.autohide) {
4366 Roo.get(document).on('scroll',function(e) {
4367 var ns = Roo.get(document).getScroll().top;
4368 var os = prevScroll;
4372 ft.removeClass('slideDown');
4373 ft.addClass('slideUp');
4376 ft.removeClass('slideUp');
4377 ft.addClass('slideDown');
4398 * @class Roo.bootstrap.NavSidebar
4399 * @extends Roo.bootstrap.Navbar
4400 * Bootstrap Sidebar class
4403 * Create a new Sidebar
4404 * @param {Object} config The config object
4408 Roo.bootstrap.NavSidebar = function(config){
4409 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4412 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4414 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4416 getAutoCreate : function(){
4421 cls: 'sidebar sidebar-nav'
4443 * @class Roo.bootstrap.NavGroup
4444 * @extends Roo.bootstrap.Component
4445 * Bootstrap NavGroup class
4446 * @cfg {String} align (left|right)
4447 * @cfg {Boolean} inverse
4448 * @cfg {String} type (nav|pills|tab) default nav
4449 * @cfg {String} navId - reference Id for navbar.
4453 * Create a new nav group
4454 * @param {Object} config The config object
4457 Roo.bootstrap.NavGroup = function(config){
4458 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4461 Roo.bootstrap.NavGroup.register(this);
4465 * Fires when the active item changes
4466 * @param {Roo.bootstrap.NavGroup} this
4467 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4468 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4475 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4486 getAutoCreate : function()
4488 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4494 if (Roo.bootstrap.version == 4) {
4495 if (['tabs','pills'].indexOf(this.type) != -1) {
4496 cfg.cls += ' nav-' + this.type;
4498 // trying to remove so header bar can right align top?
4499 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4500 // do not use on header bar...
4501 cfg.cls += ' navbar-nav';
4506 if (['tabs','pills'].indexOf(this.type) != -1) {
4507 cfg.cls += ' nav-' + this.type
4509 if (this.type !== 'nav') {
4510 Roo.log('nav type must be nav/tabs/pills')
4512 cfg.cls += ' navbar-nav'
4516 if (this.parent() && this.parent().sidebar) {
4519 cls: 'dashboard-menu sidebar-menu'
4525 if (this.form === true) {
4528 cls: 'navbar-form form-inline'
4530 //nav navbar-right ml-md-auto
4531 if (this.align === 'right') {
4532 cfg.cls += ' navbar-right ml-md-auto';
4534 cfg.cls += ' navbar-left';
4538 if (this.align === 'right') {
4539 cfg.cls += ' navbar-right ml-md-auto';
4541 cfg.cls += ' mr-auto';
4545 cfg.cls += ' navbar-inverse';
4553 * sets the active Navigation item
4554 * @param {Roo.bootstrap.NavItem} the new current navitem
4556 setActiveItem : function(item)
4559 Roo.each(this.navItems, function(v){
4564 v.setActive(false, true);
4571 item.setActive(true, true);
4572 this.fireEvent('changed', this, item, prev);
4577 * gets the active Navigation item
4578 * @return {Roo.bootstrap.NavItem} the current navitem
4580 getActive : function()
4584 Roo.each(this.navItems, function(v){
4595 indexOfNav : function()
4599 Roo.each(this.navItems, function(v,i){
4610 * adds a Navigation item
4611 * @param {Roo.bootstrap.NavItem} the navitem to add
4613 addItem : function(cfg)
4615 if (this.form && Roo.bootstrap.version == 4) {
4618 var cn = new Roo.bootstrap.NavItem(cfg);
4620 cn.parentId = this.id;
4621 cn.onRender(this.el, null);
4625 * register a Navigation item
4626 * @param {Roo.bootstrap.NavItem} the navitem to add
4628 register : function(item)
4630 this.navItems.push( item);
4631 item.navId = this.navId;
4636 * clear all the Navigation item
4639 clearAll : function()
4642 this.el.dom.innerHTML = '';
4645 getNavItem: function(tabId)
4648 Roo.each(this.navItems, function(e) {
4649 if (e.tabId == tabId) {
4659 setActiveNext : function()
4661 var i = this.indexOfNav(this.getActive());
4662 if (i > this.navItems.length) {
4665 this.setActiveItem(this.navItems[i+1]);
4667 setActivePrev : function()
4669 var i = this.indexOfNav(this.getActive());
4673 this.setActiveItem(this.navItems[i-1]);
4675 clearWasActive : function(except) {
4676 Roo.each(this.navItems, function(e) {
4677 if (e.tabId != except.tabId && e.was_active) {
4678 e.was_active = false;
4685 getWasActive : function ()
4688 Roo.each(this.navItems, function(e) {
4703 Roo.apply(Roo.bootstrap.NavGroup, {
4707 * register a Navigation Group
4708 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4710 register : function(navgrp)
4712 this.groups[navgrp.navId] = navgrp;
4716 * fetch a Navigation Group based on the navigation ID
4717 * @param {string} the navgroup to add
4718 * @returns {Roo.bootstrap.NavGroup} the navgroup
4720 get: function(navId) {
4721 if (typeof(this.groups[navId]) == 'undefined') {
4723 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4725 return this.groups[navId] ;
4740 * @class Roo.bootstrap.NavItem
4741 * @extends Roo.bootstrap.Component
4742 * Bootstrap Navbar.NavItem class
4743 * @cfg {String} href link to
4744 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4746 * @cfg {String} html content of button
4747 * @cfg {String} badge text inside badge
4748 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4749 * @cfg {String} glyphicon DEPRICATED - use fa
4750 * @cfg {String} icon DEPRICATED - use fa
4751 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4752 * @cfg {Boolean} active Is item active
4753 * @cfg {Boolean} disabled Is item disabled
4755 * @cfg {Boolean} preventDefault (true | false) default false
4756 * @cfg {String} tabId the tab that this item activates.
4757 * @cfg {String} tagtype (a|span) render as a href or span?
4758 * @cfg {Boolean} animateRef (true|false) link to element default false
4761 * Create a new Navbar Item
4762 * @param {Object} config The config object
4764 Roo.bootstrap.NavItem = function(config){
4765 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4770 * The raw click event for the entire grid.
4771 * @param {Roo.EventObject} e
4776 * Fires when the active item active state changes
4777 * @param {Roo.bootstrap.NavItem} this
4778 * @param {boolean} state the new state
4784 * Fires when scroll to element
4785 * @param {Roo.bootstrap.NavItem} this
4786 * @param {Object} options
4787 * @param {Roo.EventObject} e
4795 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4804 preventDefault : false,
4812 button_outline : false,
4816 getAutoCreate : function(){
4824 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4826 if (this.disabled) {
4827 cfg.cls += ' disabled';
4831 if (this.button_weight.length) {
4832 cfg.tag = this.href ? 'a' : 'button';
4833 cfg.html = this.html || '';
4834 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4836 cfg.href = this.href;
4839 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4842 // menu .. should add dropdown-menu class - so no need for carat..
4844 if (this.badge !== '') {
4846 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4851 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4855 href : this.href || "#",
4856 html: this.html || ''
4859 if (this.tagtype == 'a') {
4860 cfg.cn[0].cls = 'nav-link';
4863 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4866 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4868 if(this.glyphicon) {
4869 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4874 cfg.cn[0].html += " <span class='caret'></span>";
4878 if (this.badge !== '') {
4880 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4888 onRender : function(ct, position)
4890 // Roo.log("Call onRender: " + this.xtype);
4891 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4895 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4896 this.navLink = this.el.select('.nav-link',true).first();
4901 initEvents: function()
4903 if (typeof (this.menu) != 'undefined') {
4904 this.menu.parentType = this.xtype;
4905 this.menu.triggerEl = this.el;
4906 this.menu = this.addxtype(Roo.apply({}, this.menu));
4909 this.el.select('a',true).on('click', this.onClick, this);
4911 if(this.tagtype == 'span'){
4912 this.el.select('span',true).on('click', this.onClick, this);
4915 // at this point parent should be available..
4916 this.parent().register(this);
4919 onClick : function(e)
4921 if (e.getTarget('.dropdown-menu-item')) {
4922 // did you click on a menu itemm.... - then don't trigger onclick..
4927 this.preventDefault ||
4930 Roo.log("NavItem - prevent Default?");
4934 if (this.disabled) {
4938 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4939 if (tg && tg.transition) {
4940 Roo.log("waiting for the transitionend");
4946 //Roo.log("fire event clicked");
4947 if(this.fireEvent('click', this, e) === false){
4951 if(this.tagtype == 'span'){
4955 //Roo.log(this.href);
4956 var ael = this.el.select('a',true).first();
4959 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4960 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4961 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4962 return; // ignore... - it's a 'hash' to another page.
4964 Roo.log("NavItem - prevent Default?");
4966 this.scrollToElement(e);
4970 var p = this.parent();
4972 if (['tabs','pills'].indexOf(p.type)!==-1) {
4973 if (typeof(p.setActiveItem) !== 'undefined') {
4974 p.setActiveItem(this);
4978 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4979 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4980 // remove the collapsed menu expand...
4981 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4985 isActive: function () {
4988 setActive : function(state, fire, is_was_active)
4990 if (this.active && !state && this.navId) {
4991 this.was_active = true;
4992 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4994 nv.clearWasActive(this);
4998 this.active = state;
5001 this.el.removeClass('active');
5002 this.navLink ? this.navLink.removeClass('active') : false;
5003 } else if (!this.el.hasClass('active')) {
5005 this.el.addClass('active');
5006 if (Roo.bootstrap.version == 4 && this.navLink ) {
5007 this.navLink.addClass('active');
5012 this.fireEvent('changed', this, state);
5015 // show a panel if it's registered and related..
5017 if (!this.navId || !this.tabId || !state || is_was_active) {
5021 var tg = Roo.bootstrap.TabGroup.get(this.navId);
5025 var pan = tg.getPanelByName(this.tabId);
5029 // if we can not flip to new panel - go back to old nav highlight..
5030 if (false == tg.showPanel(pan)) {
5031 var nv = Roo.bootstrap.NavGroup.get(this.navId);
5033 var onav = nv.getWasActive();
5035 onav.setActive(true, false, true);
5044 // this should not be here...
5045 setDisabled : function(state)
5047 this.disabled = state;
5049 this.el.removeClass('disabled');
5050 } else if (!this.el.hasClass('disabled')) {
5051 this.el.addClass('disabled');
5057 * Fetch the element to display the tooltip on.
5058 * @return {Roo.Element} defaults to this.el
5060 tooltipEl : function()
5062 return this.el.select('' + this.tagtype + '', true).first();
5065 scrollToElement : function(e)
5067 var c = document.body;
5070 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5072 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5073 c = document.documentElement;
5076 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5082 var o = target.calcOffsetsTo(c);
5089 this.fireEvent('scrollto', this, options, e);
5091 Roo.get(c).scrollTo('top', options.value, true);
5104 * <span> icon </span>
5105 * <span> text </span>
5106 * <span>badge </span>
5110 * @class Roo.bootstrap.NavSidebarItem
5111 * @extends Roo.bootstrap.NavItem
5112 * Bootstrap Navbar.NavSidebarItem class
5113 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5114 * {Boolean} open is the menu open
5115 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5116 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5117 * {String} buttonSize (sm|md|lg)the extra classes for the button
5118 * {Boolean} showArrow show arrow next to the text (default true)
5120 * Create a new Navbar Button
5121 * @param {Object} config The config object
5123 Roo.bootstrap.NavSidebarItem = function(config){
5124 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5129 * The raw click event for the entire grid.
5130 * @param {Roo.EventObject} e
5135 * Fires when the active item active state changes
5136 * @param {Roo.bootstrap.NavSidebarItem} this
5137 * @param {boolean} state the new state
5145 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5147 badgeWeight : 'default',
5153 buttonWeight : 'default',
5159 getAutoCreate : function(){
5164 href : this.href || '#',
5170 if(this.buttonView){
5173 href : this.href || '#',
5174 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5187 cfg.cls += ' active';
5190 if (this.disabled) {
5191 cfg.cls += ' disabled';
5194 cfg.cls += ' open x-open';
5197 if (this.glyphicon || this.icon) {
5198 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5199 a.cn.push({ tag : 'i', cls : c }) ;
5202 if(!this.buttonView){
5205 html : this.html || ''
5212 if (this.badge !== '') {
5213 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5219 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5222 a.cls += ' dropdown-toggle treeview' ;
5228 initEvents : function()
5230 if (typeof (this.menu) != 'undefined') {
5231 this.menu.parentType = this.xtype;
5232 this.menu.triggerEl = this.el;
5233 this.menu = this.addxtype(Roo.apply({}, this.menu));
5236 this.el.on('click', this.onClick, this);
5238 if(this.badge !== ''){
5239 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5244 onClick : function(e)
5251 if(this.preventDefault){
5255 this.fireEvent('click', this, e);
5258 disable : function()
5260 this.setDisabled(true);
5265 this.setDisabled(false);
5268 setDisabled : function(state)
5270 if(this.disabled == state){
5274 this.disabled = state;
5277 this.el.addClass('disabled');
5281 this.el.removeClass('disabled');
5286 setActive : function(state)
5288 if(this.active == state){
5292 this.active = state;
5295 this.el.addClass('active');
5299 this.el.removeClass('active');
5304 isActive: function ()
5309 setBadge : function(str)
5315 this.badgeEl.dom.innerHTML = str;
5332 * @class Roo.bootstrap.Row
5333 * @extends Roo.bootstrap.Component
5334 * Bootstrap Row class (contains columns...)
5338 * @param {Object} config The config object
5341 Roo.bootstrap.Row = function(config){
5342 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5345 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5347 getAutoCreate : function(){
5366 * @class Roo.bootstrap.Element
5367 * @extends Roo.bootstrap.Component
5368 * Bootstrap Element class
5369 * @cfg {String} html contents of the element
5370 * @cfg {String} tag tag of the element
5371 * @cfg {String} cls class of the element
5372 * @cfg {Boolean} preventDefault (true|false) default false
5373 * @cfg {Boolean} clickable (true|false) default false
5376 * Create a new Element
5377 * @param {Object} config The config object
5380 Roo.bootstrap.Element = function(config){
5381 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5387 * When a element is chick
5388 * @param {Roo.bootstrap.Element} this
5389 * @param {Roo.EventObject} e
5395 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5400 preventDefault: false,
5403 getAutoCreate : function(){
5407 // cls: this.cls, double assign in parent class Component.js :: onRender
5414 initEvents: function()
5416 Roo.bootstrap.Element.superclass.initEvents.call(this);
5419 this.el.on('click', this.onClick, this);
5424 onClick : function(e)
5426 if(this.preventDefault){
5430 this.fireEvent('click', this, e);
5433 getValue : function()
5435 return this.el.dom.innerHTML;
5438 setValue : function(value)
5440 this.el.dom.innerHTML = value;
5455 * @class Roo.bootstrap.Pagination
5456 * @extends Roo.bootstrap.Component
5457 * Bootstrap Pagination class
5458 * @cfg {String} size xs | sm | md | lg
5459 * @cfg {Boolean} inverse false | true
5462 * Create a new Pagination
5463 * @param {Object} config The config object
5466 Roo.bootstrap.Pagination = function(config){
5467 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5470 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5476 getAutoCreate : function(){
5482 cfg.cls += ' inverse';
5488 cfg.cls += " " + this.cls;
5506 * @class Roo.bootstrap.PaginationItem
5507 * @extends Roo.bootstrap.Component
5508 * Bootstrap PaginationItem class
5509 * @cfg {String} html text
5510 * @cfg {String} href the link
5511 * @cfg {Boolean} preventDefault (true | false) default true
5512 * @cfg {Boolean} active (true | false) default false
5513 * @cfg {Boolean} disabled default false
5517 * Create a new PaginationItem
5518 * @param {Object} config The config object
5522 Roo.bootstrap.PaginationItem = function(config){
5523 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5528 * The raw click event for the entire grid.
5529 * @param {Roo.EventObject} e
5535 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5539 preventDefault: true,
5544 getAutoCreate : function(){
5550 href : this.href ? this.href : '#',
5551 html : this.html ? this.html : ''
5561 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5565 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5571 initEvents: function() {
5573 this.el.on('click', this.onClick, this);
5576 onClick : function(e)
5578 Roo.log('PaginationItem on click ');
5579 if(this.preventDefault){
5587 this.fireEvent('click', this, e);
5603 * @class Roo.bootstrap.Slider
5604 * @extends Roo.bootstrap.Component
5605 * Bootstrap Slider class
5608 * Create a new Slider
5609 * @param {Object} config The config object
5612 Roo.bootstrap.Slider = function(config){
5613 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5616 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5618 getAutoCreate : function(){
5622 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5626 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5638 * Ext JS Library 1.1.1
5639 * Copyright(c) 2006-2007, Ext JS, LLC.
5641 * Originally Released Under LGPL - original licence link has changed is not relivant.
5644 * <script type="text/javascript">
5649 * @class Roo.grid.ColumnModel
5650 * @extends Roo.util.Observable
5651 * This is the default implementation of a ColumnModel used by the Grid. It defines
5652 * the columns in the grid.
5655 var colModel = new Roo.grid.ColumnModel([
5656 {header: "Ticker", width: 60, sortable: true, locked: true},
5657 {header: "Company Name", width: 150, sortable: true},
5658 {header: "Market Cap.", width: 100, sortable: true},
5659 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5660 {header: "Employees", width: 100, sortable: true, resizable: false}
5665 * The config options listed for this class are options which may appear in each
5666 * individual column definition.
5667 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5669 * @param {Object} config An Array of column config objects. See this class's
5670 * config objects for details.
5672 Roo.grid.ColumnModel = function(config){
5674 * The config passed into the constructor
5676 this.config = config;
5679 // if no id, create one
5680 // if the column does not have a dataIndex mapping,
5681 // map it to the order it is in the config
5682 for(var i = 0, len = config.length; i < len; i++){
5684 if(typeof c.dataIndex == "undefined"){
5687 if(typeof c.renderer == "string"){
5688 c.renderer = Roo.util.Format[c.renderer];
5690 if(typeof c.id == "undefined"){
5693 if(c.editor && c.editor.xtype){
5694 c.editor = Roo.factory(c.editor, Roo.grid);
5696 if(c.editor && c.editor.isFormField){
5697 c.editor = new Roo.grid.GridEditor(c.editor);
5699 this.lookup[c.id] = c;
5703 * The width of columns which have no width specified (defaults to 100)
5706 this.defaultWidth = 100;
5709 * Default sortable of columns which have no sortable specified (defaults to false)
5712 this.defaultSortable = false;
5716 * @event widthchange
5717 * Fires when the width of a column changes.
5718 * @param {ColumnModel} this
5719 * @param {Number} columnIndex The column index
5720 * @param {Number} newWidth The new width
5722 "widthchange": true,
5724 * @event headerchange
5725 * Fires when the text of a header changes.
5726 * @param {ColumnModel} this
5727 * @param {Number} columnIndex The column index
5728 * @param {Number} newText The new header text
5730 "headerchange": true,
5732 * @event hiddenchange
5733 * Fires when a column is hidden or "unhidden".
5734 * @param {ColumnModel} this
5735 * @param {Number} columnIndex The column index
5736 * @param {Boolean} hidden true if hidden, false otherwise
5738 "hiddenchange": true,
5740 * @event columnmoved
5741 * Fires when a column is moved.
5742 * @param {ColumnModel} this
5743 * @param {Number} oldIndex
5744 * @param {Number} newIndex
5746 "columnmoved" : true,
5748 * @event columlockchange
5749 * Fires when a column's locked state is changed
5750 * @param {ColumnModel} this
5751 * @param {Number} colIndex
5752 * @param {Boolean} locked true if locked
5754 "columnlockchange" : true
5756 Roo.grid.ColumnModel.superclass.constructor.call(this);
5758 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5760 * @cfg {String} header The header text to display in the Grid view.
5763 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5764 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5765 * specified, the column's index is used as an index into the Record's data Array.
5768 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5769 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5772 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5773 * Defaults to the value of the {@link #defaultSortable} property.
5774 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5777 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5780 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5783 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5786 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5789 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5790 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5791 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5792 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5795 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5798 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5801 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5804 * @cfg {String} cursor (Optional)
5807 * @cfg {String} tooltip (Optional)
5810 * @cfg {Number} xs (Optional)
5813 * @cfg {Number} sm (Optional)
5816 * @cfg {Number} md (Optional)
5819 * @cfg {Number} lg (Optional)
5822 * Returns the id of the column at the specified index.
5823 * @param {Number} index The column index
5824 * @return {String} the id
5826 getColumnId : function(index){
5827 return this.config[index].id;
5831 * Returns the column for a specified id.
5832 * @param {String} id The column id
5833 * @return {Object} the column
5835 getColumnById : function(id){
5836 return this.lookup[id];
5841 * Returns the column for a specified dataIndex.
5842 * @param {String} dataIndex The column dataIndex
5843 * @return {Object|Boolean} the column or false if not found
5845 getColumnByDataIndex: function(dataIndex){
5846 var index = this.findColumnIndex(dataIndex);
5847 return index > -1 ? this.config[index] : false;
5851 * Returns the index for a specified column id.
5852 * @param {String} id The column id
5853 * @return {Number} the index, or -1 if not found
5855 getIndexById : function(id){
5856 for(var i = 0, len = this.config.length; i < len; i++){
5857 if(this.config[i].id == id){
5865 * Returns the index for a specified column dataIndex.
5866 * @param {String} dataIndex The column dataIndex
5867 * @return {Number} the index, or -1 if not found
5870 findColumnIndex : function(dataIndex){
5871 for(var i = 0, len = this.config.length; i < len; i++){
5872 if(this.config[i].dataIndex == dataIndex){
5880 moveColumn : function(oldIndex, newIndex){
5881 var c = this.config[oldIndex];
5882 this.config.splice(oldIndex, 1);
5883 this.config.splice(newIndex, 0, c);
5884 this.dataMap = null;
5885 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5888 isLocked : function(colIndex){
5889 return this.config[colIndex].locked === true;
5892 setLocked : function(colIndex, value, suppressEvent){
5893 if(this.isLocked(colIndex) == value){
5896 this.config[colIndex].locked = value;
5898 this.fireEvent("columnlockchange", this, colIndex, value);
5902 getTotalLockedWidth : function(){
5904 for(var i = 0; i < this.config.length; i++){
5905 if(this.isLocked(i) && !this.isHidden(i)){
5906 this.totalWidth += this.getColumnWidth(i);
5912 getLockedCount : function(){
5913 for(var i = 0, len = this.config.length; i < len; i++){
5914 if(!this.isLocked(i)){
5919 return this.config.length;
5923 * Returns the number of columns.
5926 getColumnCount : function(visibleOnly){
5927 if(visibleOnly === true){
5929 for(var i = 0, len = this.config.length; i < len; i++){
5930 if(!this.isHidden(i)){
5936 return this.config.length;
5940 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5941 * @param {Function} fn
5942 * @param {Object} scope (optional)
5943 * @return {Array} result
5945 getColumnsBy : function(fn, scope){
5947 for(var i = 0, len = this.config.length; i < len; i++){
5948 var c = this.config[i];
5949 if(fn.call(scope||this, c, i) === true){
5957 * Returns true if the specified column is sortable.
5958 * @param {Number} col The column index
5961 isSortable : function(col){
5962 if(typeof this.config[col].sortable == "undefined"){
5963 return this.defaultSortable;
5965 return this.config[col].sortable;
5969 * Returns the rendering (formatting) function defined for the column.
5970 * @param {Number} col The column index.
5971 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5973 getRenderer : function(col){
5974 if(!this.config[col].renderer){
5975 return Roo.grid.ColumnModel.defaultRenderer;
5977 return this.config[col].renderer;
5981 * Sets the rendering (formatting) function for a column.
5982 * @param {Number} col The column index
5983 * @param {Function} fn The function to use to process the cell's raw data
5984 * to return HTML markup for the grid view. The render function is called with
5985 * the following parameters:<ul>
5986 * <li>Data value.</li>
5987 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5988 * <li>css A CSS style string to apply to the table cell.</li>
5989 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5990 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5991 * <li>Row index</li>
5992 * <li>Column index</li>
5993 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5995 setRenderer : function(col, fn){
5996 this.config[col].renderer = fn;
6000 * Returns the width for the specified column.
6001 * @param {Number} col The column index
6004 getColumnWidth : function(col){
6005 return this.config[col].width * 1 || this.defaultWidth;
6009 * Sets the width for a column.
6010 * @param {Number} col The column index
6011 * @param {Number} width The new width
6013 setColumnWidth : function(col, width, suppressEvent){
6014 this.config[col].width = width;
6015 this.totalWidth = null;
6017 this.fireEvent("widthchange", this, col, width);
6022 * Returns the total width of all columns.
6023 * @param {Boolean} includeHidden True to include hidden column widths
6026 getTotalWidth : function(includeHidden){
6027 if(!this.totalWidth){
6028 this.totalWidth = 0;
6029 for(var i = 0, len = this.config.length; i < len; i++){
6030 if(includeHidden || !this.isHidden(i)){
6031 this.totalWidth += this.getColumnWidth(i);
6035 return this.totalWidth;
6039 * Returns the header for the specified column.
6040 * @param {Number} col The column index
6043 getColumnHeader : function(col){
6044 return this.config[col].header;
6048 * Sets the header for a column.
6049 * @param {Number} col The column index
6050 * @param {String} header The new header
6052 setColumnHeader : function(col, header){
6053 this.config[col].header = header;
6054 this.fireEvent("headerchange", this, col, header);
6058 * Returns the tooltip for the specified column.
6059 * @param {Number} col The column index
6062 getColumnTooltip : function(col){
6063 return this.config[col].tooltip;
6066 * Sets the tooltip for a column.
6067 * @param {Number} col The column index
6068 * @param {String} tooltip The new tooltip
6070 setColumnTooltip : function(col, tooltip){
6071 this.config[col].tooltip = tooltip;
6075 * Returns the dataIndex for the specified column.
6076 * @param {Number} col The column index
6079 getDataIndex : function(col){
6080 return this.config[col].dataIndex;
6084 * Sets the dataIndex for a column.
6085 * @param {Number} col The column index
6086 * @param {Number} dataIndex The new dataIndex
6088 setDataIndex : function(col, dataIndex){
6089 this.config[col].dataIndex = dataIndex;
6095 * Returns true if the cell is editable.
6096 * @param {Number} colIndex The column index
6097 * @param {Number} rowIndex The row index - this is nto actually used..?
6100 isCellEditable : function(colIndex, rowIndex){
6101 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6105 * Returns the editor defined for the cell/column.
6106 * return false or null to disable editing.
6107 * @param {Number} colIndex The column index
6108 * @param {Number} rowIndex The row index
6111 getCellEditor : function(colIndex, rowIndex){
6112 return this.config[colIndex].editor;
6116 * Sets if a column is editable.
6117 * @param {Number} col The column index
6118 * @param {Boolean} editable True if the column is editable
6120 setEditable : function(col, editable){
6121 this.config[col].editable = editable;
6126 * Returns true if the column is hidden.
6127 * @param {Number} colIndex The column index
6130 isHidden : function(colIndex){
6131 return this.config[colIndex].hidden;
6136 * Returns true if the column width cannot be changed
6138 isFixed : function(colIndex){
6139 return this.config[colIndex].fixed;
6143 * Returns true if the column can be resized
6146 isResizable : function(colIndex){
6147 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6150 * Sets if a column is hidden.
6151 * @param {Number} colIndex The column index
6152 * @param {Boolean} hidden True if the column is hidden
6154 setHidden : function(colIndex, hidden){
6155 this.config[colIndex].hidden = hidden;
6156 this.totalWidth = null;
6157 this.fireEvent("hiddenchange", this, colIndex, hidden);
6161 * Sets the editor for a column.
6162 * @param {Number} col The column index
6163 * @param {Object} editor The editor object
6165 setEditor : function(col, editor){
6166 this.config[col].editor = editor;
6170 Roo.grid.ColumnModel.defaultRenderer = function(value)
6172 if(typeof value == "object") {
6175 if(typeof value == "string" && value.length < 1){
6179 return String.format("{0}", value);
6182 // Alias for backwards compatibility
6183 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6186 * Ext JS Library 1.1.1
6187 * Copyright(c) 2006-2007, Ext JS, LLC.
6189 * Originally Released Under LGPL - original licence link has changed is not relivant.
6192 * <script type="text/javascript">
6196 * @class Roo.LoadMask
6197 * A simple utility class for generically masking elements while loading data. If the element being masked has
6198 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6199 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6200 * element's UpdateManager load indicator and will be destroyed after the initial load.
6202 * Create a new LoadMask
6203 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6204 * @param {Object} config The config object
6206 Roo.LoadMask = function(el, config){
6207 this.el = Roo.get(el);
6208 Roo.apply(this, config);
6210 this.store.on('beforeload', this.onBeforeLoad, this);
6211 this.store.on('load', this.onLoad, this);
6212 this.store.on('loadexception', this.onLoadException, this);
6213 this.removeMask = false;
6215 var um = this.el.getUpdateManager();
6216 um.showLoadIndicator = false; // disable the default indicator
6217 um.on('beforeupdate', this.onBeforeLoad, this);
6218 um.on('update', this.onLoad, this);
6219 um.on('failure', this.onLoad, this);
6220 this.removeMask = true;
6224 Roo.LoadMask.prototype = {
6226 * @cfg {Boolean} removeMask
6227 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6228 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6232 * The text to display in a centered loading message box (defaults to 'Loading...')
6236 * @cfg {String} msgCls
6237 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6239 msgCls : 'x-mask-loading',
6242 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6248 * Disables the mask to prevent it from being displayed
6250 disable : function(){
6251 this.disabled = true;
6255 * Enables the mask so that it can be displayed
6257 enable : function(){
6258 this.disabled = false;
6261 onLoadException : function()
6265 if (typeof(arguments[3]) != 'undefined') {
6266 Roo.MessageBox.alert("Error loading",arguments[3]);
6270 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6271 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6278 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6283 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6287 onBeforeLoad : function(){
6289 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6294 destroy : function(){
6296 this.store.un('beforeload', this.onBeforeLoad, this);
6297 this.store.un('load', this.onLoad, this);
6298 this.store.un('loadexception', this.onLoadException, this);
6300 var um = this.el.getUpdateManager();
6301 um.un('beforeupdate', this.onBeforeLoad, this);
6302 um.un('update', this.onLoad, this);
6303 um.un('failure', this.onLoad, this);
6314 * @class Roo.bootstrap.Table
6315 * @extends Roo.bootstrap.Component
6316 * Bootstrap Table class
6317 * @cfg {String} cls table class
6318 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6319 * @cfg {String} bgcolor Specifies the background color for a table
6320 * @cfg {Number} border Specifies whether the table cells should have borders or not
6321 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6322 * @cfg {Number} cellspacing Specifies the space between cells
6323 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6324 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6325 * @cfg {String} sortable Specifies that the table should be sortable
6326 * @cfg {String} summary Specifies a summary of the content of a table
6327 * @cfg {Number} width Specifies the width of a table
6328 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6330 * @cfg {boolean} striped Should the rows be alternative striped
6331 * @cfg {boolean} bordered Add borders to the table
6332 * @cfg {boolean} hover Add hover highlighting
6333 * @cfg {boolean} condensed Format condensed
6334 * @cfg {boolean} responsive Format condensed
6335 * @cfg {Boolean} loadMask (true|false) default false
6336 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6337 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6338 * @cfg {Boolean} rowSelection (true|false) default false
6339 * @cfg {Boolean} cellSelection (true|false) default false
6340 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6341 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6342 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6343 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6347 * Create a new Table
6348 * @param {Object} config The config object
6351 Roo.bootstrap.Table = function(config){
6352 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6357 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6358 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6359 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6360 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6362 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6364 this.sm.grid = this;
6365 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6366 this.sm = this.selModel;
6367 this.sm.xmodule = this.xmodule || false;
6370 if (this.cm && typeof(this.cm.config) == 'undefined') {
6371 this.colModel = new Roo.grid.ColumnModel(this.cm);
6372 this.cm = this.colModel;
6373 this.cm.xmodule = this.xmodule || false;
6376 this.store= Roo.factory(this.store, Roo.data);
6377 this.ds = this.store;
6378 this.ds.xmodule = this.xmodule || false;
6381 if (this.footer && this.store) {
6382 this.footer.dataSource = this.ds;
6383 this.footer = Roo.factory(this.footer);
6390 * Fires when a cell is clicked
6391 * @param {Roo.bootstrap.Table} this
6392 * @param {Roo.Element} el
6393 * @param {Number} rowIndex
6394 * @param {Number} columnIndex
6395 * @param {Roo.EventObject} e
6399 * @event celldblclick
6400 * Fires when a cell is double clicked
6401 * @param {Roo.bootstrap.Table} this
6402 * @param {Roo.Element} el
6403 * @param {Number} rowIndex
6404 * @param {Number} columnIndex
6405 * @param {Roo.EventObject} e
6407 "celldblclick" : true,
6410 * Fires when a row is clicked
6411 * @param {Roo.bootstrap.Table} this
6412 * @param {Roo.Element} el
6413 * @param {Number} rowIndex
6414 * @param {Roo.EventObject} e
6418 * @event rowdblclick
6419 * Fires when a row is double clicked
6420 * @param {Roo.bootstrap.Table} this
6421 * @param {Roo.Element} el
6422 * @param {Number} rowIndex
6423 * @param {Roo.EventObject} e
6425 "rowdblclick" : true,
6428 * Fires when a mouseover occur
6429 * @param {Roo.bootstrap.Table} this
6430 * @param {Roo.Element} el
6431 * @param {Number} rowIndex
6432 * @param {Number} columnIndex
6433 * @param {Roo.EventObject} e
6438 * Fires when a mouseout occur
6439 * @param {Roo.bootstrap.Table} this
6440 * @param {Roo.Element} el
6441 * @param {Number} rowIndex
6442 * @param {Number} columnIndex
6443 * @param {Roo.EventObject} e
6448 * Fires when a row is rendered, so you can change add a style to it.
6449 * @param {Roo.bootstrap.Table} this
6450 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6454 * @event rowsrendered
6455 * Fires when all the rows have been rendered
6456 * @param {Roo.bootstrap.Table} this
6458 'rowsrendered' : true,
6460 * @event contextmenu
6461 * The raw contextmenu event for the entire grid.
6462 * @param {Roo.EventObject} e
6464 "contextmenu" : true,
6466 * @event rowcontextmenu
6467 * Fires when a row is right clicked
6468 * @param {Roo.bootstrap.Table} this
6469 * @param {Number} rowIndex
6470 * @param {Roo.EventObject} e
6472 "rowcontextmenu" : true,
6474 * @event cellcontextmenu
6475 * Fires when a cell is right clicked
6476 * @param {Roo.bootstrap.Table} this
6477 * @param {Number} rowIndex
6478 * @param {Number} cellIndex
6479 * @param {Roo.EventObject} e
6481 "cellcontextmenu" : true,
6483 * @event headercontextmenu
6484 * Fires when a header is right clicked
6485 * @param {Roo.bootstrap.Table} this
6486 * @param {Number} columnIndex
6487 * @param {Roo.EventObject} e
6489 "headercontextmenu" : true
6493 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6519 rowSelection : false,
6520 cellSelection : false,
6523 // Roo.Element - the tbody
6525 // Roo.Element - thead element
6528 container: false, // used by gridpanel...
6534 auto_hide_footer : false,
6536 getAutoCreate : function()
6538 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6545 if (this.scrollBody) {
6546 cfg.cls += ' table-body-fixed';
6549 cfg.cls += ' table-striped';
6553 cfg.cls += ' table-hover';
6555 if (this.bordered) {
6556 cfg.cls += ' table-bordered';
6558 if (this.condensed) {
6559 cfg.cls += ' table-condensed';
6561 if (this.responsive) {
6562 cfg.cls += ' table-responsive';
6566 cfg.cls+= ' ' +this.cls;
6569 // this lot should be simplifed...
6582 ].forEach(function(k) {
6590 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6593 if(this.store || this.cm){
6594 if(this.headerShow){
6595 cfg.cn.push(this.renderHeader());
6598 cfg.cn.push(this.renderBody());
6600 if(this.footerShow){
6601 cfg.cn.push(this.renderFooter());
6603 // where does this come from?
6604 //cfg.cls+= ' TableGrid';
6607 return { cn : [ cfg ] };
6610 initEvents : function()
6612 if(!this.store || !this.cm){
6615 if (this.selModel) {
6616 this.selModel.initEvents();
6620 //Roo.log('initEvents with ds!!!!');
6622 this.mainBody = this.el.select('tbody', true).first();
6623 this.mainHead = this.el.select('thead', true).first();
6624 this.mainFoot = this.el.select('tfoot', true).first();
6630 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6631 e.on('click', _this.sort, _this);
6634 this.mainBody.on("click", this.onClick, this);
6635 this.mainBody.on("dblclick", this.onDblClick, this);
6637 // why is this done????? = it breaks dialogs??
6638 //this.parent().el.setStyle('position', 'relative');
6642 this.footer.parentId = this.id;
6643 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6646 this.el.select('tfoot tr td').first().addClass('hide');
6651 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6654 this.store.on('load', this.onLoad, this);
6655 this.store.on('beforeload', this.onBeforeLoad, this);
6656 this.store.on('update', this.onUpdate, this);
6657 this.store.on('add', this.onAdd, this);
6658 this.store.on("clear", this.clear, this);
6660 this.el.on("contextmenu", this.onContextMenu, this);
6662 this.mainBody.on('scroll', this.onBodyScroll, this);
6664 this.cm.on("headerchange", this.onHeaderChange, this);
6666 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6670 onContextMenu : function(e, t)
6672 this.processEvent("contextmenu", e);
6675 processEvent : function(name, e)
6677 if (name != 'touchstart' ) {
6678 this.fireEvent(name, e);
6681 var t = e.getTarget();
6683 var cell = Roo.get(t);
6689 if(cell.findParent('tfoot', false, true)){
6693 if(cell.findParent('thead', false, true)){
6695 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6696 cell = Roo.get(t).findParent('th', false, true);
6698 Roo.log("failed to find th in thead?");
6699 Roo.log(e.getTarget());
6704 var cellIndex = cell.dom.cellIndex;
6706 var ename = name == 'touchstart' ? 'click' : name;
6707 this.fireEvent("header" + ename, this, cellIndex, e);
6712 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6713 cell = Roo.get(t).findParent('td', false, true);
6715 Roo.log("failed to find th in tbody?");
6716 Roo.log(e.getTarget());
6721 var row = cell.findParent('tr', false, true);
6722 var cellIndex = cell.dom.cellIndex;
6723 var rowIndex = row.dom.rowIndex - 1;
6727 this.fireEvent("row" + name, this, rowIndex, e);
6731 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6737 onMouseover : function(e, el)
6739 var cell = Roo.get(el);
6745 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6746 cell = cell.findParent('td', false, true);
6749 var row = cell.findParent('tr', false, true);
6750 var cellIndex = cell.dom.cellIndex;
6751 var rowIndex = row.dom.rowIndex - 1; // start from 0
6753 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6757 onMouseout : function(e, el)
6759 var cell = Roo.get(el);
6765 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6766 cell = cell.findParent('td', false, true);
6769 var row = cell.findParent('tr', false, true);
6770 var cellIndex = cell.dom.cellIndex;
6771 var rowIndex = row.dom.rowIndex - 1; // start from 0
6773 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6777 onClick : function(e, el)
6779 var cell = Roo.get(el);
6781 if(!cell || (!this.cellSelection && !this.rowSelection)){
6785 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6786 cell = cell.findParent('td', false, true);
6789 if(!cell || typeof(cell) == 'undefined'){
6793 var row = cell.findParent('tr', false, true);
6795 if(!row || typeof(row) == 'undefined'){
6799 var cellIndex = cell.dom.cellIndex;
6800 var rowIndex = this.getRowIndex(row);
6802 // why??? - should these not be based on SelectionModel?
6803 if(this.cellSelection){
6804 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6807 if(this.rowSelection){
6808 this.fireEvent('rowclick', this, row, rowIndex, e);
6814 onDblClick : function(e,el)
6816 var cell = Roo.get(el);
6818 if(!cell || (!this.cellSelection && !this.rowSelection)){
6822 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6823 cell = cell.findParent('td', false, true);
6826 if(!cell || typeof(cell) == 'undefined'){
6830 var row = cell.findParent('tr', false, true);
6832 if(!row || typeof(row) == 'undefined'){
6836 var cellIndex = cell.dom.cellIndex;
6837 var rowIndex = this.getRowIndex(row);
6839 if(this.cellSelection){
6840 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6843 if(this.rowSelection){
6844 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6848 sort : function(e,el)
6850 var col = Roo.get(el);
6852 if(!col.hasClass('sortable')){
6856 var sort = col.attr('sort');
6859 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6863 this.store.sortInfo = {field : sort, direction : dir};
6866 Roo.log("calling footer first");
6867 this.footer.onClick('first');
6870 this.store.load({ params : { start : 0 } });
6874 renderHeader : function()
6882 this.totalWidth = 0;
6884 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6886 var config = cm.config[i];
6890 cls : 'x-hcol-' + i,
6892 html: cm.getColumnHeader(i)
6897 if(typeof(config.sortable) != 'undefined' && config.sortable){
6899 c.html = '<i class="glyphicon"></i>' + c.html;
6902 // could use BS4 hidden-..-down
6904 if(typeof(config.lgHeader) != 'undefined'){
6905 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6908 if(typeof(config.mdHeader) != 'undefined'){
6909 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6912 if(typeof(config.smHeader) != 'undefined'){
6913 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6916 if(typeof(config.xsHeader) != 'undefined'){
6917 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6924 if(typeof(config.tooltip) != 'undefined'){
6925 c.tooltip = config.tooltip;
6928 if(typeof(config.colspan) != 'undefined'){
6929 c.colspan = config.colspan;
6932 if(typeof(config.hidden) != 'undefined' && config.hidden){
6933 c.style += ' display:none;';
6936 if(typeof(config.dataIndex) != 'undefined'){
6937 c.sort = config.dataIndex;
6942 if(typeof(config.align) != 'undefined' && config.align.length){
6943 c.style += ' text-align:' + config.align + ';';
6946 if(typeof(config.width) != 'undefined'){
6947 c.style += ' width:' + config.width + 'px;';
6948 this.totalWidth += config.width;
6950 this.totalWidth += 100; // assume minimum of 100 per column?
6953 if(typeof(config.cls) != 'undefined'){
6954 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6957 ['xs','sm','md','lg'].map(function(size){
6959 if(typeof(config[size]) == 'undefined'){
6963 if (!config[size]) { // 0 = hidden
6964 // BS 4 '0' is treated as hide that column and below.
6965 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6969 c.cls += ' col-' + size + '-' + config[size] + (
6970 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6982 renderBody : function()
6992 colspan : this.cm.getColumnCount()
7002 renderFooter : function()
7012 colspan : this.cm.getColumnCount()
7026 // Roo.log('ds onload');
7031 var ds = this.store;
7033 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7034 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
7035 if (_this.store.sortInfo) {
7037 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
7038 e.select('i', true).addClass(['glyphicon-arrow-up']);
7041 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
7042 e.select('i', true).addClass(['glyphicon-arrow-down']);
7047 var tbody = this.mainBody;
7049 if(ds.getCount() > 0){
7050 ds.data.each(function(d,rowIndex){
7051 var row = this.renderRow(cm, ds, rowIndex);
7053 tbody.createChild(row);
7057 if(row.cellObjects.length){
7058 Roo.each(row.cellObjects, function(r){
7059 _this.renderCellObject(r);
7066 var tfoot = this.el.select('tfoot', true).first();
7068 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7070 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7072 var total = this.ds.getTotalCount();
7074 if(this.footer.pageSize < total){
7075 this.mainFoot.show();
7079 Roo.each(this.el.select('tbody td', true).elements, function(e){
7080 e.on('mouseover', _this.onMouseover, _this);
7083 Roo.each(this.el.select('tbody td', true).elements, function(e){
7084 e.on('mouseout', _this.onMouseout, _this);
7086 this.fireEvent('rowsrendered', this);
7092 onUpdate : function(ds,record)
7094 this.refreshRow(record);
7098 onRemove : function(ds, record, index, isUpdate){
7099 if(isUpdate !== true){
7100 this.fireEvent("beforerowremoved", this, index, record);
7102 var bt = this.mainBody.dom;
7104 var rows = this.el.select('tbody > tr', true).elements;
7106 if(typeof(rows[index]) != 'undefined'){
7107 bt.removeChild(rows[index].dom);
7110 // if(bt.rows[index]){
7111 // bt.removeChild(bt.rows[index]);
7114 if(isUpdate !== true){
7115 //this.stripeRows(index);
7116 //this.syncRowHeights(index, index);
7118 this.fireEvent("rowremoved", this, index, record);
7122 onAdd : function(ds, records, rowIndex)
7124 //Roo.log('on Add called');
7125 // - note this does not handle multiple adding very well..
7126 var bt = this.mainBody.dom;
7127 for (var i =0 ; i < records.length;i++) {
7128 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7129 //Roo.log(records[i]);
7130 //Roo.log(this.store.getAt(rowIndex+i));
7131 this.insertRow(this.store, rowIndex + i, false);
7138 refreshRow : function(record){
7139 var ds = this.store, index;
7140 if(typeof record == 'number'){
7142 record = ds.getAt(index);
7144 index = ds.indexOf(record);
7146 this.insertRow(ds, index, true);
7148 this.onRemove(ds, record, index+1, true);
7150 //this.syncRowHeights(index, index);
7152 this.fireEvent("rowupdated", this, index, record);
7155 insertRow : function(dm, rowIndex, isUpdate){
7158 this.fireEvent("beforerowsinserted", this, rowIndex);
7160 //var s = this.getScrollState();
7161 var row = this.renderRow(this.cm, this.store, rowIndex);
7162 // insert before rowIndex..
7163 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7167 if(row.cellObjects.length){
7168 Roo.each(row.cellObjects, function(r){
7169 _this.renderCellObject(r);
7174 this.fireEvent("rowsinserted", this, rowIndex);
7175 //this.syncRowHeights(firstRow, lastRow);
7176 //this.stripeRows(firstRow);
7183 getRowDom : function(rowIndex)
7185 var rows = this.el.select('tbody > tr', true).elements;
7187 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7190 // returns the object tree for a tr..
7193 renderRow : function(cm, ds, rowIndex)
7195 var d = ds.getAt(rowIndex);
7199 cls : 'x-row-' + rowIndex,
7203 var cellObjects = [];
7205 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7206 var config = cm.config[i];
7208 var renderer = cm.getRenderer(i);
7212 if(typeof(renderer) !== 'undefined'){
7213 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7215 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7216 // and are rendered into the cells after the row is rendered - using the id for the element.
7218 if(typeof(value) === 'object'){
7228 rowIndex : rowIndex,
7233 this.fireEvent('rowclass', this, rowcfg);
7237 cls : rowcfg.rowClass + ' x-col-' + i,
7239 html: (typeof(value) === 'object') ? '' : value
7246 if(typeof(config.colspan) != 'undefined'){
7247 td.colspan = config.colspan;
7250 if(typeof(config.hidden) != 'undefined' && config.hidden){
7251 td.style += ' display:none;';
7254 if(typeof(config.align) != 'undefined' && config.align.length){
7255 td.style += ' text-align:' + config.align + ';';
7257 if(typeof(config.valign) != 'undefined' && config.valign.length){
7258 td.style += ' vertical-align:' + config.valign + ';';
7261 if(typeof(config.width) != 'undefined'){
7262 td.style += ' width:' + config.width + 'px;';
7265 if(typeof(config.cursor) != 'undefined'){
7266 td.style += ' cursor:' + config.cursor + ';';
7269 if(typeof(config.cls) != 'undefined'){
7270 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7273 ['xs','sm','md','lg'].map(function(size){
7275 if(typeof(config[size]) == 'undefined'){
7281 if (!config[size]) { // 0 = hidden
7282 // BS 4 '0' is treated as hide that column and below.
7283 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7287 td.cls += ' col-' + size + '-' + config[size] + (
7288 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7298 row.cellObjects = cellObjects;
7306 onBeforeLoad : function()
7315 this.el.select('tbody', true).first().dom.innerHTML = '';
7318 * Show or hide a row.
7319 * @param {Number} rowIndex to show or hide
7320 * @param {Boolean} state hide
7322 setRowVisibility : function(rowIndex, state)
7324 var bt = this.mainBody.dom;
7326 var rows = this.el.select('tbody > tr', true).elements;
7328 if(typeof(rows[rowIndex]) == 'undefined'){
7331 rows[rowIndex].dom.style.display = state ? '' : 'none';
7335 getSelectionModel : function(){
7337 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7339 return this.selModel;
7342 * Render the Roo.bootstrap object from renderder
7344 renderCellObject : function(r)
7348 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7350 var t = r.cfg.render(r.container);
7353 Roo.each(r.cfg.cn, function(c){
7355 container: t.getChildContainer(),
7358 _this.renderCellObject(child);
7363 getRowIndex : function(row)
7367 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7378 * Returns the grid's underlying element = used by panel.Grid
7379 * @return {Element} The element
7381 getGridEl : function(){
7385 * Forces a resize - used by panel.Grid
7386 * @return {Element} The element
7388 autoSize : function()
7390 //var ctr = Roo.get(this.container.dom.parentElement);
7391 var ctr = Roo.get(this.el.dom);
7393 var thd = this.getGridEl().select('thead',true).first();
7394 var tbd = this.getGridEl().select('tbody', true).first();
7395 var tfd = this.getGridEl().select('tfoot', true).first();
7397 var cw = ctr.getWidth();
7401 tbd.setSize(ctr.getWidth(),
7402 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7404 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7407 cw = Math.max(cw, this.totalWidth);
7408 this.getGridEl().select('tr',true).setWidth(cw);
7409 // resize 'expandable coloumn?
7411 return; // we doe not have a view in this design..
7414 onBodyScroll: function()
7416 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7418 this.mainHead.setStyle({
7419 'position' : 'relative',
7420 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7426 var scrollHeight = this.mainBody.dom.scrollHeight;
7428 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7430 var height = this.mainBody.getHeight();
7432 if(scrollHeight - height == scrollTop) {
7434 var total = this.ds.getTotalCount();
7436 if(this.footer.cursor + this.footer.pageSize < total){
7438 this.footer.ds.load({
7440 start : this.footer.cursor + this.footer.pageSize,
7441 limit : this.footer.pageSize
7451 onHeaderChange : function()
7453 var header = this.renderHeader();
7454 var table = this.el.select('table', true).first();
7456 this.mainHead.remove();
7457 this.mainHead = table.createChild(header, this.mainBody, false);
7460 onHiddenChange : function(colModel, colIndex, hidden)
7462 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7463 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7465 this.CSS.updateRule(thSelector, "display", "");
7466 this.CSS.updateRule(tdSelector, "display", "");
7469 this.CSS.updateRule(thSelector, "display", "none");
7470 this.CSS.updateRule(tdSelector, "display", "none");
7473 this.onHeaderChange();
7477 setColumnWidth: function(col_index, width)
7479 // width = "md-2 xs-2..."
7480 if(!this.colModel.config[col_index]) {
7484 var w = width.split(" ");
7486 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7488 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7491 for(var j = 0; j < w.length; j++) {
7497 var size_cls = w[j].split("-");
7499 if(!Number.isInteger(size_cls[1] * 1)) {
7503 if(!this.colModel.config[col_index][size_cls[0]]) {
7507 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7511 h_row[0].classList.replace(
7512 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7513 "col-"+size_cls[0]+"-"+size_cls[1]
7516 for(var i = 0; i < rows.length; i++) {
7518 var size_cls = w[j].split("-");
7520 if(!Number.isInteger(size_cls[1] * 1)) {
7524 if(!this.colModel.config[col_index][size_cls[0]]) {
7528 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7532 rows[i].classList.replace(
7533 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7534 "col-"+size_cls[0]+"-"+size_cls[1]
7538 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7553 * @class Roo.bootstrap.TableCell
7554 * @extends Roo.bootstrap.Component
7555 * Bootstrap TableCell class
7556 * @cfg {String} html cell contain text
7557 * @cfg {String} cls cell class
7558 * @cfg {String} tag cell tag (td|th) default td
7559 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7560 * @cfg {String} align Aligns the content in a cell
7561 * @cfg {String} axis Categorizes cells
7562 * @cfg {String} bgcolor Specifies the background color of a cell
7563 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7564 * @cfg {Number} colspan Specifies the number of columns a cell should span
7565 * @cfg {String} headers Specifies one or more header cells a cell is related to
7566 * @cfg {Number} height Sets the height of a cell
7567 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7568 * @cfg {Number} rowspan Sets the number of rows a cell should span
7569 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7570 * @cfg {String} valign Vertical aligns the content in a cell
7571 * @cfg {Number} width Specifies the width of a cell
7574 * Create a new TableCell
7575 * @param {Object} config The config object
7578 Roo.bootstrap.TableCell = function(config){
7579 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7582 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7602 getAutoCreate : function(){
7603 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7623 cfg.align=this.align
7629 cfg.bgcolor=this.bgcolor
7632 cfg.charoff=this.charoff
7635 cfg.colspan=this.colspan
7638 cfg.headers=this.headers
7641 cfg.height=this.height
7644 cfg.nowrap=this.nowrap
7647 cfg.rowspan=this.rowspan
7650 cfg.scope=this.scope
7653 cfg.valign=this.valign
7656 cfg.width=this.width
7675 * @class Roo.bootstrap.TableRow
7676 * @extends Roo.bootstrap.Component
7677 * Bootstrap TableRow class
7678 * @cfg {String} cls row class
7679 * @cfg {String} align Aligns the content in a table row
7680 * @cfg {String} bgcolor Specifies a background color for a table row
7681 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7682 * @cfg {String} valign Vertical aligns the content in a table row
7685 * Create a new TableRow
7686 * @param {Object} config The config object
7689 Roo.bootstrap.TableRow = function(config){
7690 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7693 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7701 getAutoCreate : function(){
7702 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7712 cfg.align = this.align;
7715 cfg.bgcolor = this.bgcolor;
7718 cfg.charoff = this.charoff;
7721 cfg.valign = this.valign;
7739 * @class Roo.bootstrap.TableBody
7740 * @extends Roo.bootstrap.Component
7741 * Bootstrap TableBody class
7742 * @cfg {String} cls element class
7743 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7744 * @cfg {String} align Aligns the content inside the element
7745 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7746 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7749 * Create a new TableBody
7750 * @param {Object} config The config object
7753 Roo.bootstrap.TableBody = function(config){
7754 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7757 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7765 getAutoCreate : function(){
7766 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7780 cfg.align = this.align;
7783 cfg.charoff = this.charoff;
7786 cfg.valign = this.valign;
7793 // initEvents : function()
7800 // this.store = Roo.factory(this.store, Roo.data);
7801 // this.store.on('load', this.onLoad, this);
7803 // this.store.load();
7807 // onLoad: function ()
7809 // this.fireEvent('load', this);
7819 * Ext JS Library 1.1.1
7820 * Copyright(c) 2006-2007, Ext JS, LLC.
7822 * Originally Released Under LGPL - original licence link has changed is not relivant.
7825 * <script type="text/javascript">
7828 // as we use this in bootstrap.
7829 Roo.namespace('Roo.form');
7831 * @class Roo.form.Action
7832 * Internal Class used to handle form actions
7834 * @param {Roo.form.BasicForm} el The form element or its id
7835 * @param {Object} config Configuration options
7840 // define the action interface
7841 Roo.form.Action = function(form, options){
7843 this.options = options || {};
7846 * Client Validation Failed
7849 Roo.form.Action.CLIENT_INVALID = 'client';
7851 * Server Validation Failed
7854 Roo.form.Action.SERVER_INVALID = 'server';
7856 * Connect to Server Failed
7859 Roo.form.Action.CONNECT_FAILURE = 'connect';
7861 * Reading Data from Server Failed
7864 Roo.form.Action.LOAD_FAILURE = 'load';
7866 Roo.form.Action.prototype = {
7868 failureType : undefined,
7869 response : undefined,
7873 run : function(options){
7878 success : function(response){
7883 handleResponse : function(response){
7887 // default connection failure
7888 failure : function(response){
7890 this.response = response;
7891 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7892 this.form.afterAction(this, false);
7895 processResponse : function(response){
7896 this.response = response;
7897 if(!response.responseText){
7900 this.result = this.handleResponse(response);
7904 // utility functions used internally
7905 getUrl : function(appendParams){
7906 var url = this.options.url || this.form.url || this.form.el.dom.action;
7908 var p = this.getParams();
7910 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7916 getMethod : function(){
7917 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7920 getParams : function(){
7921 var bp = this.form.baseParams;
7922 var p = this.options.params;
7924 if(typeof p == "object"){
7925 p = Roo.urlEncode(Roo.applyIf(p, bp));
7926 }else if(typeof p == 'string' && bp){
7927 p += '&' + Roo.urlEncode(bp);
7930 p = Roo.urlEncode(bp);
7935 createCallback : function(){
7937 success: this.success,
7938 failure: this.failure,
7940 timeout: (this.form.timeout*1000),
7941 upload: this.form.fileUpload ? this.success : undefined
7946 Roo.form.Action.Submit = function(form, options){
7947 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7950 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7953 haveProgress : false,
7954 uploadComplete : false,
7956 // uploadProgress indicator.
7957 uploadProgress : function()
7959 if (!this.form.progressUrl) {
7963 if (!this.haveProgress) {
7964 Roo.MessageBox.progress("Uploading", "Uploading");
7966 if (this.uploadComplete) {
7967 Roo.MessageBox.hide();
7971 this.haveProgress = true;
7973 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7975 var c = new Roo.data.Connection();
7977 url : this.form.progressUrl,
7982 success : function(req){
7983 //console.log(data);
7987 rdata = Roo.decode(req.responseText)
7989 Roo.log("Invalid data from server..");
7993 if (!rdata || !rdata.success) {
7995 Roo.MessageBox.alert(Roo.encode(rdata));
7998 var data = rdata.data;
8000 if (this.uploadComplete) {
8001 Roo.MessageBox.hide();
8006 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
8007 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
8010 this.uploadProgress.defer(2000,this);
8013 failure: function(data) {
8014 Roo.log('progress url failed ');
8025 // run get Values on the form, so it syncs any secondary forms.
8026 this.form.getValues();
8028 var o = this.options;
8029 var method = this.getMethod();
8030 var isPost = method == 'POST';
8031 if(o.clientValidation === false || this.form.isValid()){
8033 if (this.form.progressUrl) {
8034 this.form.findField('UPLOAD_IDENTIFIER').setValue(
8035 (new Date() * 1) + '' + Math.random());
8040 Roo.Ajax.request(Roo.apply(this.createCallback(), {
8041 form:this.form.el.dom,
8042 url:this.getUrl(!isPost),
8044 params:isPost ? this.getParams() : null,
8045 isUpload: this.form.fileUpload,
8046 formData : this.form.formData
8049 this.uploadProgress();
8051 }else if (o.clientValidation !== false){ // client validation failed
8052 this.failureType = Roo.form.Action.CLIENT_INVALID;
8053 this.form.afterAction(this, false);
8057 success : function(response)
8059 this.uploadComplete= true;
8060 if (this.haveProgress) {
8061 Roo.MessageBox.hide();
8065 var result = this.processResponse(response);
8066 if(result === true || result.success){
8067 this.form.afterAction(this, true);
8071 this.form.markInvalid(result.errors);
8072 this.failureType = Roo.form.Action.SERVER_INVALID;
8074 this.form.afterAction(this, false);
8076 failure : function(response)
8078 this.uploadComplete= true;
8079 if (this.haveProgress) {
8080 Roo.MessageBox.hide();
8083 this.response = response;
8084 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8085 this.form.afterAction(this, false);
8088 handleResponse : function(response){
8089 if(this.form.errorReader){
8090 var rs = this.form.errorReader.read(response);
8093 for(var i = 0, len = rs.records.length; i < len; i++) {
8094 var r = rs.records[i];
8098 if(errors.length < 1){
8102 success : rs.success,
8108 ret = Roo.decode(response.responseText);
8112 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8122 Roo.form.Action.Load = function(form, options){
8123 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8124 this.reader = this.form.reader;
8127 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8132 Roo.Ajax.request(Roo.apply(
8133 this.createCallback(), {
8134 method:this.getMethod(),
8135 url:this.getUrl(false),
8136 params:this.getParams()
8140 success : function(response){
8142 var result = this.processResponse(response);
8143 if(result === true || !result.success || !result.data){
8144 this.failureType = Roo.form.Action.LOAD_FAILURE;
8145 this.form.afterAction(this, false);
8148 this.form.clearInvalid();
8149 this.form.setValues(result.data);
8150 this.form.afterAction(this, true);
8153 handleResponse : function(response){
8154 if(this.form.reader){
8155 var rs = this.form.reader.read(response);
8156 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8158 success : rs.success,
8162 return Roo.decode(response.responseText);
8166 Roo.form.Action.ACTION_TYPES = {
8167 'load' : Roo.form.Action.Load,
8168 'submit' : Roo.form.Action.Submit
8177 * @class Roo.bootstrap.Form
8178 * @extends Roo.bootstrap.Component
8179 * Bootstrap Form class
8180 * @cfg {String} method GET | POST (default POST)
8181 * @cfg {String} labelAlign top | left (default top)
8182 * @cfg {String} align left | right - for navbars
8183 * @cfg {Boolean} loadMask load mask when submit (default true)
8188 * @param {Object} config The config object
8192 Roo.bootstrap.Form = function(config){
8194 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8196 Roo.bootstrap.Form.popover.apply();
8200 * @event clientvalidation
8201 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8202 * @param {Form} this
8203 * @param {Boolean} valid true if the form has passed client-side validation
8205 clientvalidation: true,
8207 * @event beforeaction
8208 * Fires before any action is performed. Return false to cancel the action.
8209 * @param {Form} this
8210 * @param {Action} action The action to be performed
8214 * @event actionfailed
8215 * Fires when an action fails.
8216 * @param {Form} this
8217 * @param {Action} action The action that failed
8219 actionfailed : true,
8221 * @event actioncomplete
8222 * Fires when an action is completed.
8223 * @param {Form} this
8224 * @param {Action} action The action that completed
8226 actioncomplete : true
8230 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8233 * @cfg {String} method
8234 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8239 * The URL to use for form actions if one isn't supplied in the action options.
8242 * @cfg {Boolean} fileUpload
8243 * Set to true if this form is a file upload.
8247 * @cfg {Object} baseParams
8248 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8252 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8256 * @cfg {Sting} align (left|right) for navbar forms
8261 activeAction : null,
8264 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8265 * element by passing it or its id or mask the form itself by passing in true.
8268 waitMsgTarget : false,
8273 * @cfg {Boolean} errorMask (true|false) default false
8278 * @cfg {Number} maskOffset Default 100
8283 * @cfg {Boolean} maskBody
8287 getAutoCreate : function(){
8291 method : this.method || 'POST',
8292 id : this.id || Roo.id(),
8295 if (this.parent().xtype.match(/^Nav/)) {
8296 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8300 if (this.labelAlign == 'left' ) {
8301 cfg.cls += ' form-horizontal';
8307 initEvents : function()
8309 this.el.on('submit', this.onSubmit, this);
8310 // this was added as random key presses on the form where triggering form submit.
8311 this.el.on('keypress', function(e) {
8312 if (e.getCharCode() != 13) {
8315 // we might need to allow it for textareas.. and some other items.
8316 // check e.getTarget().
8318 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8322 Roo.log("keypress blocked");
8330 onSubmit : function(e){
8335 * Returns true if client-side validation on the form is successful.
8338 isValid : function(){
8339 var items = this.getItems();
8343 items.each(function(f){
8349 Roo.log('invalid field: ' + f.name);
8353 if(!target && f.el.isVisible(true)){
8359 if(this.errorMask && !valid){
8360 Roo.bootstrap.Form.popover.mask(this, target);
8367 * Returns true if any fields in this form have changed since their original load.
8370 isDirty : function(){
8372 var items = this.getItems();
8373 items.each(function(f){
8383 * Performs a predefined action (submit or load) or custom actions you define on this form.
8384 * @param {String} actionName The name of the action type
8385 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8386 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8387 * accept other config options):
8389 Property Type Description
8390 ---------------- --------------- ----------------------------------------------------------------------------------
8391 url String The url for the action (defaults to the form's url)
8392 method String The form method to use (defaults to the form's method, or POST if not defined)
8393 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8394 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8395 validate the form on the client (defaults to false)
8397 * @return {BasicForm} this
8399 doAction : function(action, options){
8400 if(typeof action == 'string'){
8401 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8403 if(this.fireEvent('beforeaction', this, action) !== false){
8404 this.beforeAction(action);
8405 action.run.defer(100, action);
8411 beforeAction : function(action){
8412 var o = action.options;
8417 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8419 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8422 // not really supported yet.. ??
8424 //if(this.waitMsgTarget === true){
8425 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8426 //}else if(this.waitMsgTarget){
8427 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8428 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8430 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8436 afterAction : function(action, success){
8437 this.activeAction = null;
8438 var o = action.options;
8443 Roo.get(document.body).unmask();
8449 //if(this.waitMsgTarget === true){
8450 // this.el.unmask();
8451 //}else if(this.waitMsgTarget){
8452 // this.waitMsgTarget.unmask();
8454 // Roo.MessageBox.updateProgress(1);
8455 // Roo.MessageBox.hide();
8462 Roo.callback(o.success, o.scope, [this, action]);
8463 this.fireEvent('actioncomplete', this, action);
8467 // failure condition..
8468 // we have a scenario where updates need confirming.
8469 // eg. if a locking scenario exists..
8470 // we look for { errors : { needs_confirm : true }} in the response.
8472 (typeof(action.result) != 'undefined') &&
8473 (typeof(action.result.errors) != 'undefined') &&
8474 (typeof(action.result.errors.needs_confirm) != 'undefined')
8477 Roo.log("not supported yet");
8480 Roo.MessageBox.confirm(
8481 "Change requires confirmation",
8482 action.result.errorMsg,
8487 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8497 Roo.callback(o.failure, o.scope, [this, action]);
8498 // show an error message if no failed handler is set..
8499 if (!this.hasListener('actionfailed')) {
8500 Roo.log("need to add dialog support");
8502 Roo.MessageBox.alert("Error",
8503 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8504 action.result.errorMsg :
8505 "Saving Failed, please check your entries or try again"
8510 this.fireEvent('actionfailed', this, action);
8515 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8516 * @param {String} id The value to search for
8519 findField : function(id){
8520 var items = this.getItems();
8521 var field = items.get(id);
8523 items.each(function(f){
8524 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8531 return field || null;
8534 * Mark fields in this form invalid in bulk.
8535 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8536 * @return {BasicForm} this
8538 markInvalid : function(errors){
8539 if(errors instanceof Array){
8540 for(var i = 0, len = errors.length; i < len; i++){
8541 var fieldError = errors[i];
8542 var f = this.findField(fieldError.id);
8544 f.markInvalid(fieldError.msg);
8550 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8551 field.markInvalid(errors[id]);
8555 //Roo.each(this.childForms || [], function (f) {
8556 // f.markInvalid(errors);
8563 * Set values for fields in this form in bulk.
8564 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8565 * @return {BasicForm} this
8567 setValues : function(values){
8568 if(values instanceof Array){ // array of objects
8569 for(var i = 0, len = values.length; i < len; i++){
8571 var f = this.findField(v.id);
8573 f.setValue(v.value);
8574 if(this.trackResetOnLoad){
8575 f.originalValue = f.getValue();
8579 }else{ // object hash
8582 if(typeof values[id] != 'function' && (field = this.findField(id))){
8584 if (field.setFromData &&
8586 field.displayField &&
8587 // combos' with local stores can
8588 // be queried via setValue()
8589 // to set their value..
8590 (field.store && !field.store.isLocal)
8594 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8595 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8596 field.setFromData(sd);
8598 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8600 field.setFromData(values);
8603 field.setValue(values[id]);
8607 if(this.trackResetOnLoad){
8608 field.originalValue = field.getValue();
8614 //Roo.each(this.childForms || [], function (f) {
8615 // f.setValues(values);
8622 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8623 * they are returned as an array.
8624 * @param {Boolean} asString
8627 getValues : function(asString){
8628 //if (this.childForms) {
8629 // copy values from the child forms
8630 // Roo.each(this.childForms, function (f) {
8631 // this.setValues(f.getValues());
8637 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8638 if(asString === true){
8641 return Roo.urlDecode(fs);
8645 * Returns the fields in this form as an object with key/value pairs.
8646 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8649 getFieldValues : function(with_hidden)
8651 var items = this.getItems();
8653 items.each(function(f){
8659 var v = f.getValue();
8661 if (f.inputType =='radio') {
8662 if (typeof(ret[f.getName()]) == 'undefined') {
8663 ret[f.getName()] = ''; // empty..
8666 if (!f.el.dom.checked) {
8674 if(f.xtype == 'MoneyField'){
8675 ret[f.currencyName] = f.getCurrency();
8678 // not sure if this supported any more..
8679 if ((typeof(v) == 'object') && f.getRawValue) {
8680 v = f.getRawValue() ; // dates..
8682 // combo boxes where name != hiddenName...
8683 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8684 ret[f.name] = f.getRawValue();
8686 ret[f.getName()] = v;
8693 * Clears all invalid messages in this form.
8694 * @return {BasicForm} this
8696 clearInvalid : function(){
8697 var items = this.getItems();
8699 items.each(function(f){
8708 * @return {BasicForm} this
8711 var items = this.getItems();
8712 items.each(function(f){
8716 Roo.each(this.childForms || [], function (f) {
8724 getItems : function()
8726 var r=new Roo.util.MixedCollection(false, function(o){
8727 return o.id || (o.id = Roo.id());
8729 var iter = function(el) {
8736 Roo.each(el.items,function(e) {
8745 hideFields : function(items)
8747 Roo.each(items, function(i){
8749 var f = this.findField(i);
8760 showFields : function(items)
8762 Roo.each(items, function(i){
8764 var f = this.findField(i);
8777 Roo.apply(Roo.bootstrap.Form, {
8804 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8805 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8806 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8807 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8810 this.maskEl.top.enableDisplayMode("block");
8811 this.maskEl.left.enableDisplayMode("block");
8812 this.maskEl.bottom.enableDisplayMode("block");
8813 this.maskEl.right.enableDisplayMode("block");
8815 this.toolTip = new Roo.bootstrap.Tooltip({
8816 cls : 'roo-form-error-popover',
8818 'left' : ['r-l', [-2,0], 'right'],
8819 'right' : ['l-r', [2,0], 'left'],
8820 'bottom' : ['tl-bl', [0,2], 'top'],
8821 'top' : [ 'bl-tl', [0,-2], 'bottom']
8825 this.toolTip.render(Roo.get(document.body));
8827 this.toolTip.el.enableDisplayMode("block");
8829 Roo.get(document.body).on('click', function(){
8833 Roo.get(document.body).on('touchstart', function(){
8837 this.isApplied = true
8840 mask : function(form, target)
8844 this.target = target;
8846 if(!this.form.errorMask || !target.el){
8850 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8852 Roo.log(scrollable);
8854 var ot = this.target.el.calcOffsetsTo(scrollable);
8856 var scrollTo = ot[1] - this.form.maskOffset;
8858 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8860 scrollable.scrollTo('top', scrollTo);
8862 var box = this.target.el.getBox();
8864 var zIndex = Roo.bootstrap.Modal.zIndex++;
8867 this.maskEl.top.setStyle('position', 'absolute');
8868 this.maskEl.top.setStyle('z-index', zIndex);
8869 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8870 this.maskEl.top.setLeft(0);
8871 this.maskEl.top.setTop(0);
8872 this.maskEl.top.show();
8874 this.maskEl.left.setStyle('position', 'absolute');
8875 this.maskEl.left.setStyle('z-index', zIndex);
8876 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8877 this.maskEl.left.setLeft(0);
8878 this.maskEl.left.setTop(box.y - this.padding);
8879 this.maskEl.left.show();
8881 this.maskEl.bottom.setStyle('position', 'absolute');
8882 this.maskEl.bottom.setStyle('z-index', zIndex);
8883 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8884 this.maskEl.bottom.setLeft(0);
8885 this.maskEl.bottom.setTop(box.bottom + this.padding);
8886 this.maskEl.bottom.show();
8888 this.maskEl.right.setStyle('position', 'absolute');
8889 this.maskEl.right.setStyle('z-index', zIndex);
8890 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8891 this.maskEl.right.setLeft(box.right + this.padding);
8892 this.maskEl.right.setTop(box.y - this.padding);
8893 this.maskEl.right.show();
8895 this.toolTip.bindEl = this.target.el;
8897 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8899 var tip = this.target.blankText;
8901 if(this.target.getValue() !== '' ) {
8903 if (this.target.invalidText.length) {
8904 tip = this.target.invalidText;
8905 } else if (this.target.regexText.length){
8906 tip = this.target.regexText;
8910 this.toolTip.show(tip);
8912 this.intervalID = window.setInterval(function() {
8913 Roo.bootstrap.Form.popover.unmask();
8916 window.onwheel = function(){ return false;};
8918 (function(){ this.isMasked = true; }).defer(500, this);
8924 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8928 this.maskEl.top.setStyle('position', 'absolute');
8929 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8930 this.maskEl.top.hide();
8932 this.maskEl.left.setStyle('position', 'absolute');
8933 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8934 this.maskEl.left.hide();
8936 this.maskEl.bottom.setStyle('position', 'absolute');
8937 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8938 this.maskEl.bottom.hide();
8940 this.maskEl.right.setStyle('position', 'absolute');
8941 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8942 this.maskEl.right.hide();
8944 this.toolTip.hide();
8946 this.toolTip.el.hide();
8948 window.onwheel = function(){ return true;};
8950 if(this.intervalID){
8951 window.clearInterval(this.intervalID);
8952 this.intervalID = false;
8955 this.isMasked = false;
8965 * Ext JS Library 1.1.1
8966 * Copyright(c) 2006-2007, Ext JS, LLC.
8968 * Originally Released Under LGPL - original licence link has changed is not relivant.
8971 * <script type="text/javascript">
8974 * @class Roo.form.VTypes
8975 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8978 Roo.form.VTypes = function(){
8979 // closure these in so they are only created once.
8980 var alpha = /^[a-zA-Z_]+$/;
8981 var alphanum = /^[a-zA-Z0-9_]+$/;
8982 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8983 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8985 // All these messages and functions are configurable
8988 * The function used to validate email addresses
8989 * @param {String} value The email address
8991 'email' : function(v){
8992 return email.test(v);
8995 * The error text to display when the email validation function returns false
8998 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
9000 * The keystroke filter mask to be applied on email input
9003 'emailMask' : /[a-z0-9_\.\-@]/i,
9006 * The function used to validate URLs
9007 * @param {String} value The URL
9009 'url' : function(v){
9013 * The error text to display when the url validation function returns false
9016 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
9019 * The function used to validate alpha values
9020 * @param {String} value The value
9022 'alpha' : function(v){
9023 return alpha.test(v);
9026 * The error text to display when the alpha validation function returns false
9029 'alphaText' : 'This field should only contain letters and _',
9031 * The keystroke filter mask to be applied on alpha input
9034 'alphaMask' : /[a-z_]/i,
9037 * The function used to validate alphanumeric values
9038 * @param {String} value The value
9040 'alphanum' : function(v){
9041 return alphanum.test(v);
9044 * The error text to display when the alphanumeric validation function returns false
9047 'alphanumText' : 'This field should only contain letters, numbers and _',
9049 * The keystroke filter mask to be applied on alphanumeric input
9052 'alphanumMask' : /[a-z0-9_]/i
9062 * @class Roo.bootstrap.Input
9063 * @extends Roo.bootstrap.Component
9064 * Bootstrap Input class
9065 * @cfg {Boolean} disabled is it disabled
9066 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9067 * @cfg {String} name name of the input
9068 * @cfg {string} fieldLabel - the label associated
9069 * @cfg {string} placeholder - placeholder to put in text.
9070 * @cfg {string} before - input group add on before
9071 * @cfg {string} after - input group add on after
9072 * @cfg {string} size - (lg|sm) or leave empty..
9073 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9074 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9075 * @cfg {Number} md colspan out of 12 for computer-sized screens
9076 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9077 * @cfg {string} value default value of the input
9078 * @cfg {Number} labelWidth set the width of label
9079 * @cfg {Number} labellg set the width of label (1-12)
9080 * @cfg {Number} labelmd set the width of label (1-12)
9081 * @cfg {Number} labelsm set the width of label (1-12)
9082 * @cfg {Number} labelxs set the width of label (1-12)
9083 * @cfg {String} labelAlign (top|left)
9084 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9085 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9086 * @cfg {String} indicatorpos (left|right) default left
9087 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9088 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9090 * @cfg {String} align (left|center|right) Default left
9091 * @cfg {Boolean} forceFeedback (true|false) Default false
9094 * Create a new Input
9095 * @param {Object} config The config object
9098 Roo.bootstrap.Input = function(config){
9100 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9105 * Fires when this field receives input focus.
9106 * @param {Roo.form.Field} this
9111 * Fires when this field loses input focus.
9112 * @param {Roo.form.Field} this
9117 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9118 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9119 * @param {Roo.form.Field} this
9120 * @param {Roo.EventObject} e The event object
9125 * Fires just before the field blurs if the field value has changed.
9126 * @param {Roo.form.Field} this
9127 * @param {Mixed} newValue The new value
9128 * @param {Mixed} oldValue The original value
9133 * Fires after the field has been marked as invalid.
9134 * @param {Roo.form.Field} this
9135 * @param {String} msg The validation message
9140 * Fires after the field has been validated with no errors.
9141 * @param {Roo.form.Field} this
9146 * Fires after the key up
9147 * @param {Roo.form.Field} this
9148 * @param {Roo.EventObject} e The event Object
9154 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9156 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9157 automatic validation (defaults to "keyup").
9159 validationEvent : "keyup",
9161 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9163 validateOnBlur : true,
9165 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9167 validationDelay : 250,
9169 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9171 focusClass : "x-form-focus", // not needed???
9175 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9177 invalidClass : "has-warning",
9180 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9182 validClass : "has-success",
9185 * @cfg {Boolean} hasFeedback (true|false) default true
9190 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9192 invalidFeedbackClass : "glyphicon-warning-sign",
9195 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9197 validFeedbackClass : "glyphicon-ok",
9200 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9202 selectOnFocus : false,
9205 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9209 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9214 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9216 disableKeyFilter : false,
9219 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9223 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9227 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9229 blankText : "Please complete this mandatory field",
9232 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9236 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9238 maxLength : Number.MAX_VALUE,
9240 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9242 minLengthText : "The minimum length for this field is {0}",
9244 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9246 maxLengthText : "The maximum length for this field is {0}",
9250 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9251 * If available, this function will be called only after the basic validators all return true, and will be passed the
9252 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9256 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9257 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9258 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9262 * @cfg {String} regexText -- Depricated - use Invalid Text
9267 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9273 autocomplete: false,
9292 formatedValue : false,
9293 forceFeedback : false,
9295 indicatorpos : 'left',
9305 parentLabelAlign : function()
9308 while (parent.parent()) {
9309 parent = parent.parent();
9310 if (typeof(parent.labelAlign) !='undefined') {
9311 return parent.labelAlign;
9318 getAutoCreate : function()
9320 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9326 if(this.inputType != 'hidden'){
9327 cfg.cls = 'form-group' //input-group
9333 type : this.inputType,
9335 cls : 'form-control',
9336 placeholder : this.placeholder || '',
9337 autocomplete : this.autocomplete || 'new-password'
9340 if(this.capture.length){
9341 input.capture = this.capture;
9344 if(this.accept.length){
9345 input.accept = this.accept + "/*";
9349 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9352 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9353 input.maxLength = this.maxLength;
9356 if (this.disabled) {
9357 input.disabled=true;
9360 if (this.readOnly) {
9361 input.readonly=true;
9365 input.name = this.name;
9369 input.cls += ' input-' + this.size;
9373 ['xs','sm','md','lg'].map(function(size){
9374 if (settings[size]) {
9375 cfg.cls += ' col-' + size + '-' + settings[size];
9379 var inputblock = input;
9383 cls: 'glyphicon form-control-feedback'
9386 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9389 cls : 'has-feedback',
9397 if (this.before || this.after) {
9400 cls : 'input-group',
9404 if (this.before && typeof(this.before) == 'string') {
9406 inputblock.cn.push({
9408 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9412 if (this.before && typeof(this.before) == 'object') {
9413 this.before = Roo.factory(this.before);
9415 inputblock.cn.push({
9417 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9418 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9422 inputblock.cn.push(input);
9424 if (this.after && typeof(this.after) == 'string') {
9425 inputblock.cn.push({
9427 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9431 if (this.after && typeof(this.after) == 'object') {
9432 this.after = Roo.factory(this.after);
9434 inputblock.cn.push({
9436 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9437 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9441 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9442 inputblock.cls += ' has-feedback';
9443 inputblock.cn.push(feedback);
9448 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9449 tooltip : 'This field is required'
9451 if (Roo.bootstrap.version == 4) {
9454 style : 'display-none'
9457 if (align ==='left' && this.fieldLabel.length) {
9459 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9466 cls : 'control-label col-form-label',
9467 html : this.fieldLabel
9478 var labelCfg = cfg.cn[1];
9479 var contentCfg = cfg.cn[2];
9481 if(this.indicatorpos == 'right'){
9486 cls : 'control-label col-form-label',
9490 html : this.fieldLabel
9504 labelCfg = cfg.cn[0];
9505 contentCfg = cfg.cn[1];
9509 if(this.labelWidth > 12){
9510 labelCfg.style = "width: " + this.labelWidth + 'px';
9513 if(this.labelWidth < 13 && this.labelmd == 0){
9514 this.labelmd = this.labelWidth;
9517 if(this.labellg > 0){
9518 labelCfg.cls += ' col-lg-' + this.labellg;
9519 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9522 if(this.labelmd > 0){
9523 labelCfg.cls += ' col-md-' + this.labelmd;
9524 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9527 if(this.labelsm > 0){
9528 labelCfg.cls += ' col-sm-' + this.labelsm;
9529 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9532 if(this.labelxs > 0){
9533 labelCfg.cls += ' col-xs-' + this.labelxs;
9534 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9538 } else if ( this.fieldLabel.length) {
9543 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9544 tooltip : 'This field is required'
9548 //cls : 'input-group-addon',
9549 html : this.fieldLabel
9557 if(this.indicatorpos == 'right'){
9562 //cls : 'input-group-addon',
9563 html : this.fieldLabel
9568 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9569 tooltip : 'This field is required'
9589 if (this.parentType === 'Navbar' && this.parent().bar) {
9590 cfg.cls += ' navbar-form';
9593 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9594 // on BS4 we do this only if not form
9595 cfg.cls += ' navbar-form';
9603 * return the real input element.
9605 inputEl: function ()
9607 return this.el.select('input.form-control',true).first();
9610 tooltipEl : function()
9612 return this.inputEl();
9615 indicatorEl : function()
9617 if (Roo.bootstrap.version == 4) {
9618 return false; // not enabled in v4 yet.
9621 var indicator = this.el.select('i.roo-required-indicator',true).first();
9631 setDisabled : function(v)
9633 var i = this.inputEl().dom;
9635 i.removeAttribute('disabled');
9639 i.setAttribute('disabled','true');
9641 initEvents : function()
9644 this.inputEl().on("keydown" , this.fireKey, this);
9645 this.inputEl().on("focus", this.onFocus, this);
9646 this.inputEl().on("blur", this.onBlur, this);
9648 this.inputEl().relayEvent('keyup', this);
9650 this.indicator = this.indicatorEl();
9653 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9656 // reference to original value for reset
9657 this.originalValue = this.getValue();
9658 //Roo.form.TextField.superclass.initEvents.call(this);
9659 if(this.validationEvent == 'keyup'){
9660 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9661 this.inputEl().on('keyup', this.filterValidation, this);
9663 else if(this.validationEvent !== false){
9664 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9667 if(this.selectOnFocus){
9668 this.on("focus", this.preFocus, this);
9671 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9672 this.inputEl().on("keypress", this.filterKeys, this);
9674 this.inputEl().relayEvent('keypress', this);
9677 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9678 this.el.on("click", this.autoSize, this);
9681 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9682 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9685 if (typeof(this.before) == 'object') {
9686 this.before.render(this.el.select('.roo-input-before',true).first());
9688 if (typeof(this.after) == 'object') {
9689 this.after.render(this.el.select('.roo-input-after',true).first());
9692 this.inputEl().on('change', this.onChange, this);
9695 filterValidation : function(e){
9696 if(!e.isNavKeyPress()){
9697 this.validationTask.delay(this.validationDelay);
9701 * Validates the field value
9702 * @return {Boolean} True if the value is valid, else false
9704 validate : function(){
9705 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9706 if(this.disabled || this.validateValue(this.getRawValue())){
9717 * Validates a value according to the field's validation rules and marks the field as invalid
9718 * if the validation fails
9719 * @param {Mixed} value The value to validate
9720 * @return {Boolean} True if the value is valid, else false
9722 validateValue : function(value)
9724 if(this.getVisibilityEl().hasClass('hidden')){
9728 if(value.length < 1) { // if it's blank
9729 if(this.allowBlank){
9735 if(value.length < this.minLength){
9738 if(value.length > this.maxLength){
9742 var vt = Roo.form.VTypes;
9743 if(!vt[this.vtype](value, this)){
9747 if(typeof this.validator == "function"){
9748 var msg = this.validator(value);
9752 if (typeof(msg) == 'string') {
9753 this.invalidText = msg;
9757 if(this.regex && !this.regex.test(value)){
9765 fireKey : function(e){
9766 //Roo.log('field ' + e.getKey());
9767 if(e.isNavKeyPress()){
9768 this.fireEvent("specialkey", this, e);
9771 focus : function (selectText){
9773 this.inputEl().focus();
9774 if(selectText === true){
9775 this.inputEl().dom.select();
9781 onFocus : function(){
9782 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9783 // this.el.addClass(this.focusClass);
9786 this.hasFocus = true;
9787 this.startValue = this.getValue();
9788 this.fireEvent("focus", this);
9792 beforeBlur : Roo.emptyFn,
9796 onBlur : function(){
9798 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9799 //this.el.removeClass(this.focusClass);
9801 this.hasFocus = false;
9802 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9805 var v = this.getValue();
9806 if(String(v) !== String(this.startValue)){
9807 this.fireEvent('change', this, v, this.startValue);
9809 this.fireEvent("blur", this);
9812 onChange : function(e)
9814 var v = this.getValue();
9815 if(String(v) !== String(this.startValue)){
9816 this.fireEvent('change', this, v, this.startValue);
9822 * Resets the current field value to the originally loaded value and clears any validation messages
9825 this.setValue(this.originalValue);
9829 * Returns the name of the field
9830 * @return {Mixed} name The name field
9832 getName: function(){
9836 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9837 * @return {Mixed} value The field value
9839 getValue : function(){
9841 var v = this.inputEl().getValue();
9846 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9847 * @return {Mixed} value The field value
9849 getRawValue : function(){
9850 var v = this.inputEl().getValue();
9856 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9857 * @param {Mixed} value The value to set
9859 setRawValue : function(v){
9860 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9863 selectText : function(start, end){
9864 var v = this.getRawValue();
9866 start = start === undefined ? 0 : start;
9867 end = end === undefined ? v.length : end;
9868 var d = this.inputEl().dom;
9869 if(d.setSelectionRange){
9870 d.setSelectionRange(start, end);
9871 }else if(d.createTextRange){
9872 var range = d.createTextRange();
9873 range.moveStart("character", start);
9874 range.moveEnd("character", v.length-end);
9881 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9882 * @param {Mixed} value The value to set
9884 setValue : function(v){
9887 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9893 processValue : function(value){
9894 if(this.stripCharsRe){
9895 var newValue = value.replace(this.stripCharsRe, '');
9896 if(newValue !== value){
9897 this.setRawValue(newValue);
9904 preFocus : function(){
9906 if(this.selectOnFocus){
9907 this.inputEl().dom.select();
9910 filterKeys : function(e){
9912 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9915 var c = e.getCharCode(), cc = String.fromCharCode(c);
9916 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9919 if(!this.maskRe.test(cc)){
9924 * Clear any invalid styles/messages for this field
9926 clearInvalid : function(){
9928 if(!this.el || this.preventMark){ // not rendered
9933 this.el.removeClass([this.invalidClass, 'is-invalid']);
9935 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9937 var feedback = this.el.select('.form-control-feedback', true).first();
9940 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9946 this.indicator.removeClass('visible');
9947 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9950 this.fireEvent('valid', this);
9954 * Mark this field as valid
9956 markValid : function()
9958 if(!this.el || this.preventMark){ // not rendered...
9962 this.el.removeClass([this.invalidClass, this.validClass]);
9963 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9965 var feedback = this.el.select('.form-control-feedback', true).first();
9968 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9972 this.indicator.removeClass('visible');
9973 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9980 if(this.allowBlank && !this.getRawValue().length){
9983 if (Roo.bootstrap.version == 3) {
9984 this.el.addClass(this.validClass);
9986 this.inputEl().addClass('is-valid');
9989 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9991 var feedback = this.el.select('.form-control-feedback', true).first();
9994 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9995 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10000 this.fireEvent('valid', this);
10004 * Mark this field as invalid
10005 * @param {String} msg The validation message
10007 markInvalid : function(msg)
10009 if(!this.el || this.preventMark){ // not rendered
10013 this.el.removeClass([this.invalidClass, this.validClass]);
10014 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10016 var feedback = this.el.select('.form-control-feedback', true).first();
10019 this.el.select('.form-control-feedback', true).first().removeClass(
10020 [this.invalidFeedbackClass, this.validFeedbackClass]);
10027 if(this.allowBlank && !this.getRawValue().length){
10031 if(this.indicator){
10032 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
10033 this.indicator.addClass('visible');
10035 if (Roo.bootstrap.version == 3) {
10036 this.el.addClass(this.invalidClass);
10038 this.inputEl().addClass('is-invalid');
10043 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10045 var feedback = this.el.select('.form-control-feedback', true).first();
10048 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10050 if(this.getValue().length || this.forceFeedback){
10051 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10058 this.fireEvent('invalid', this, msg);
10061 SafariOnKeyDown : function(event)
10063 // this is a workaround for a password hang bug on chrome/ webkit.
10064 if (this.inputEl().dom.type != 'password') {
10068 var isSelectAll = false;
10070 if(this.inputEl().dom.selectionEnd > 0){
10071 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10073 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10074 event.preventDefault();
10079 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10081 event.preventDefault();
10082 // this is very hacky as keydown always get's upper case.
10084 var cc = String.fromCharCode(event.getCharCode());
10085 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10089 adjustWidth : function(tag, w){
10090 tag = tag.toLowerCase();
10091 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10092 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10093 if(tag == 'input'){
10096 if(tag == 'textarea'){
10099 }else if(Roo.isOpera){
10100 if(tag == 'input'){
10103 if(tag == 'textarea'){
10111 setFieldLabel : function(v)
10113 if(!this.rendered){
10117 if(this.indicatorEl()){
10118 var ar = this.el.select('label > span',true);
10120 if (ar.elements.length) {
10121 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10122 this.fieldLabel = v;
10126 var br = this.el.select('label',true);
10128 if(br.elements.length) {
10129 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10130 this.fieldLabel = v;
10134 Roo.log('Cannot Found any of label > span || label in input');
10138 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10139 this.fieldLabel = v;
10154 * @class Roo.bootstrap.TextArea
10155 * @extends Roo.bootstrap.Input
10156 * Bootstrap TextArea class
10157 * @cfg {Number} cols Specifies the visible width of a text area
10158 * @cfg {Number} rows Specifies the visible number of lines in a text area
10159 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10160 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10161 * @cfg {string} html text
10164 * Create a new TextArea
10165 * @param {Object} config The config object
10168 Roo.bootstrap.TextArea = function(config){
10169 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10173 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10183 getAutoCreate : function(){
10185 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10191 if(this.inputType != 'hidden'){
10192 cfg.cls = 'form-group' //input-group
10200 value : this.value || '',
10201 html: this.html || '',
10202 cls : 'form-control',
10203 placeholder : this.placeholder || ''
10207 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10208 input.maxLength = this.maxLength;
10212 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10216 input.cols = this.cols;
10219 if (this.readOnly) {
10220 input.readonly = true;
10224 input.name = this.name;
10228 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10232 ['xs','sm','md','lg'].map(function(size){
10233 if (settings[size]) {
10234 cfg.cls += ' col-' + size + '-' + settings[size];
10238 var inputblock = input;
10240 if(this.hasFeedback && !this.allowBlank){
10244 cls: 'glyphicon form-control-feedback'
10248 cls : 'has-feedback',
10257 if (this.before || this.after) {
10260 cls : 'input-group',
10264 inputblock.cn.push({
10266 cls : 'input-group-addon',
10271 inputblock.cn.push(input);
10273 if(this.hasFeedback && !this.allowBlank){
10274 inputblock.cls += ' has-feedback';
10275 inputblock.cn.push(feedback);
10279 inputblock.cn.push({
10281 cls : 'input-group-addon',
10288 if (align ==='left' && this.fieldLabel.length) {
10293 cls : 'control-label',
10294 html : this.fieldLabel
10305 if(this.labelWidth > 12){
10306 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10309 if(this.labelWidth < 13 && this.labelmd == 0){
10310 this.labelmd = this.labelWidth;
10313 if(this.labellg > 0){
10314 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10315 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10318 if(this.labelmd > 0){
10319 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10320 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10323 if(this.labelsm > 0){
10324 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10325 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10328 if(this.labelxs > 0){
10329 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10330 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10333 } else if ( this.fieldLabel.length) {
10338 //cls : 'input-group-addon',
10339 html : this.fieldLabel
10357 if (this.disabled) {
10358 input.disabled=true;
10365 * return the real textarea element.
10367 inputEl: function ()
10369 return this.el.select('textarea.form-control',true).first();
10373 * Clear any invalid styles/messages for this field
10375 clearInvalid : function()
10378 if(!this.el || this.preventMark){ // not rendered
10382 var label = this.el.select('label', true).first();
10383 var icon = this.el.select('i.fa-star', true).first();
10388 this.el.removeClass( this.validClass);
10389 this.inputEl().removeClass('is-invalid');
10391 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10393 var feedback = this.el.select('.form-control-feedback', true).first();
10396 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10401 this.fireEvent('valid', this);
10405 * Mark this field as valid
10407 markValid : function()
10409 if(!this.el || this.preventMark){ // not rendered
10413 this.el.removeClass([this.invalidClass, this.validClass]);
10414 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10416 var feedback = this.el.select('.form-control-feedback', true).first();
10419 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10422 if(this.disabled || this.allowBlank){
10426 var label = this.el.select('label', true).first();
10427 var icon = this.el.select('i.fa-star', true).first();
10432 if (Roo.bootstrap.version == 3) {
10433 this.el.addClass(this.validClass);
10435 this.inputEl().addClass('is-valid');
10439 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10441 var feedback = this.el.select('.form-control-feedback', true).first();
10444 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10445 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10450 this.fireEvent('valid', this);
10454 * Mark this field as invalid
10455 * @param {String} msg The validation message
10457 markInvalid : function(msg)
10459 if(!this.el || this.preventMark){ // not rendered
10463 this.el.removeClass([this.invalidClass, this.validClass]);
10464 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10466 var feedback = this.el.select('.form-control-feedback', true).first();
10469 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10472 if(this.disabled || this.allowBlank){
10476 var label = this.el.select('label', true).first();
10477 var icon = this.el.select('i.fa-star', true).first();
10479 if(!this.getValue().length && label && !icon){
10480 this.el.createChild({
10482 cls : 'text-danger fa fa-lg fa-star',
10483 tooltip : 'This field is required',
10484 style : 'margin-right:5px;'
10488 if (Roo.bootstrap.version == 3) {
10489 this.el.addClass(this.invalidClass);
10491 this.inputEl().addClass('is-invalid');
10494 // fixme ... this may be depricated need to test..
10495 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10497 var feedback = this.el.select('.form-control-feedback', true).first();
10500 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10502 if(this.getValue().length || this.forceFeedback){
10503 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10510 this.fireEvent('invalid', this, msg);
10518 * trigger field - base class for combo..
10523 * @class Roo.bootstrap.TriggerField
10524 * @extends Roo.bootstrap.Input
10525 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10526 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10527 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10528 * for which you can provide a custom implementation. For example:
10530 var trigger = new Roo.bootstrap.TriggerField();
10531 trigger.onTriggerClick = myTriggerFn;
10532 trigger.applyTo('my-field');
10535 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10536 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10537 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10538 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10539 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10542 * Create a new TriggerField.
10543 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10544 * to the base TextField)
10546 Roo.bootstrap.TriggerField = function(config){
10547 this.mimicing = false;
10548 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10551 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10553 * @cfg {String} triggerClass A CSS class to apply to the trigger
10556 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10561 * @cfg {Boolean} removable (true|false) special filter default false
10565 /** @cfg {Boolean} grow @hide */
10566 /** @cfg {Number} growMin @hide */
10567 /** @cfg {Number} growMax @hide */
10573 autoSize: Roo.emptyFn,
10577 deferHeight : true,
10580 actionMode : 'wrap',
10585 getAutoCreate : function(){
10587 var align = this.labelAlign || this.parentLabelAlign();
10592 cls: 'form-group' //input-group
10599 type : this.inputType,
10600 cls : 'form-control',
10601 autocomplete: 'new-password',
10602 placeholder : this.placeholder || ''
10606 input.name = this.name;
10609 input.cls += ' input-' + this.size;
10612 if (this.disabled) {
10613 input.disabled=true;
10616 var inputblock = input;
10618 if(this.hasFeedback && !this.allowBlank){
10622 cls: 'glyphicon form-control-feedback'
10625 if(this.removable && !this.editable && !this.tickable){
10627 cls : 'has-feedback',
10633 cls : 'roo-combo-removable-btn close'
10640 cls : 'has-feedback',
10649 if(this.removable && !this.editable && !this.tickable){
10651 cls : 'roo-removable',
10657 cls : 'roo-combo-removable-btn close'
10664 if (this.before || this.after) {
10667 cls : 'input-group',
10671 inputblock.cn.push({
10673 cls : 'input-group-addon input-group-prepend input-group-text',
10678 inputblock.cn.push(input);
10680 if(this.hasFeedback && !this.allowBlank){
10681 inputblock.cls += ' has-feedback';
10682 inputblock.cn.push(feedback);
10686 inputblock.cn.push({
10688 cls : 'input-group-addon input-group-append input-group-text',
10697 var ibwrap = inputblock;
10702 cls: 'roo-select2-choices',
10706 cls: 'roo-select2-search-field',
10718 cls: 'roo-select2-container input-group',
10723 cls: 'form-hidden-field'
10729 if(!this.multiple && this.showToggleBtn){
10735 if (this.caret != false) {
10738 cls: 'fa fa-' + this.caret
10745 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10747 Roo.bootstrap.version == 3 ? caret : '',
10750 cls: 'combobox-clear',
10764 combobox.cls += ' roo-select2-container-multi';
10768 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10769 tooltip : 'This field is required'
10771 if (Roo.bootstrap.version == 4) {
10774 style : 'display:none'
10779 if (align ==='left' && this.fieldLabel.length) {
10781 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10788 cls : 'control-label',
10789 html : this.fieldLabel
10801 var labelCfg = cfg.cn[1];
10802 var contentCfg = cfg.cn[2];
10804 if(this.indicatorpos == 'right'){
10809 cls : 'control-label',
10813 html : this.fieldLabel
10827 labelCfg = cfg.cn[0];
10828 contentCfg = cfg.cn[1];
10831 if(this.labelWidth > 12){
10832 labelCfg.style = "width: " + this.labelWidth + 'px';
10835 if(this.labelWidth < 13 && this.labelmd == 0){
10836 this.labelmd = this.labelWidth;
10839 if(this.labellg > 0){
10840 labelCfg.cls += ' col-lg-' + this.labellg;
10841 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10844 if(this.labelmd > 0){
10845 labelCfg.cls += ' col-md-' + this.labelmd;
10846 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10849 if(this.labelsm > 0){
10850 labelCfg.cls += ' col-sm-' + this.labelsm;
10851 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10854 if(this.labelxs > 0){
10855 labelCfg.cls += ' col-xs-' + this.labelxs;
10856 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10859 } else if ( this.fieldLabel.length) {
10860 // Roo.log(" label");
10865 //cls : 'input-group-addon',
10866 html : this.fieldLabel
10874 if(this.indicatorpos == 'right'){
10882 html : this.fieldLabel
10896 // Roo.log(" no label && no align");
10903 ['xs','sm','md','lg'].map(function(size){
10904 if (settings[size]) {
10905 cfg.cls += ' col-' + size + '-' + settings[size];
10916 onResize : function(w, h){
10917 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10918 // if(typeof w == 'number'){
10919 // var x = w - this.trigger.getWidth();
10920 // this.inputEl().setWidth(this.adjustWidth('input', x));
10921 // this.trigger.setStyle('left', x+'px');
10926 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10929 getResizeEl : function(){
10930 return this.inputEl();
10934 getPositionEl : function(){
10935 return this.inputEl();
10939 alignErrorIcon : function(){
10940 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10944 initEvents : function(){
10948 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10949 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10950 if(!this.multiple && this.showToggleBtn){
10951 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10952 if(this.hideTrigger){
10953 this.trigger.setDisplayed(false);
10955 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10959 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10962 if(this.removable && !this.editable && !this.tickable){
10963 var close = this.closeTriggerEl();
10966 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10967 close.on('click', this.removeBtnClick, this, close);
10971 //this.trigger.addClassOnOver('x-form-trigger-over');
10972 //this.trigger.addClassOnClick('x-form-trigger-click');
10975 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10979 closeTriggerEl : function()
10981 var close = this.el.select('.roo-combo-removable-btn', true).first();
10982 return close ? close : false;
10985 removeBtnClick : function(e, h, el)
10987 e.preventDefault();
10989 if(this.fireEvent("remove", this) !== false){
10991 this.fireEvent("afterremove", this)
10995 createList : function()
10997 this.list = Roo.get(document.body).createChild({
10998 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10999 cls: 'typeahead typeahead-long dropdown-menu',
11000 style: 'display:none'
11003 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
11008 initTrigger : function(){
11013 onDestroy : function(){
11015 this.trigger.removeAllListeners();
11016 // this.trigger.remove();
11019 // this.wrap.remove();
11021 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
11025 onFocus : function(){
11026 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
11028 if(!this.mimicing){
11029 this.wrap.addClass('x-trigger-wrap-focus');
11030 this.mimicing = true;
11031 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
11032 if(this.monitorTab){
11033 this.el.on("keydown", this.checkTab, this);
11040 checkTab : function(e){
11041 if(e.getKey() == e.TAB){
11042 this.triggerBlur();
11047 onBlur : function(){
11052 mimicBlur : function(e, t){
11054 if(!this.wrap.contains(t) && this.validateBlur()){
11055 this.triggerBlur();
11061 triggerBlur : function(){
11062 this.mimicing = false;
11063 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11064 if(this.monitorTab){
11065 this.el.un("keydown", this.checkTab, this);
11067 //this.wrap.removeClass('x-trigger-wrap-focus');
11068 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11072 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11073 validateBlur : function(e, t){
11078 onDisable : function(){
11079 this.inputEl().dom.disabled = true;
11080 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11082 // this.wrap.addClass('x-item-disabled');
11087 onEnable : function(){
11088 this.inputEl().dom.disabled = false;
11089 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11091 // this.el.removeClass('x-item-disabled');
11096 onShow : function(){
11097 var ae = this.getActionEl();
11100 ae.dom.style.display = '';
11101 ae.dom.style.visibility = 'visible';
11107 onHide : function(){
11108 var ae = this.getActionEl();
11109 ae.dom.style.display = 'none';
11113 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11114 * by an implementing function.
11116 * @param {EventObject} e
11118 onTriggerClick : Roo.emptyFn
11122 * Ext JS Library 1.1.1
11123 * Copyright(c) 2006-2007, Ext JS, LLC.
11125 * Originally Released Under LGPL - original licence link has changed is not relivant.
11128 * <script type="text/javascript">
11133 * @class Roo.data.SortTypes
11135 * Defines the default sorting (casting?) comparison functions used when sorting data.
11137 Roo.data.SortTypes = {
11139 * Default sort that does nothing
11140 * @param {Mixed} s The value being converted
11141 * @return {Mixed} The comparison value
11143 none : function(s){
11148 * The regular expression used to strip tags
11152 stripTagsRE : /<\/?[^>]+>/gi,
11155 * Strips all HTML tags to sort on text only
11156 * @param {Mixed} s The value being converted
11157 * @return {String} The comparison value
11159 asText : function(s){
11160 return String(s).replace(this.stripTagsRE, "");
11164 * Strips all HTML tags to sort on text only - Case insensitive
11165 * @param {Mixed} s The value being converted
11166 * @return {String} The comparison value
11168 asUCText : function(s){
11169 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11173 * Case insensitive string
11174 * @param {Mixed} s The value being converted
11175 * @return {String} The comparison value
11177 asUCString : function(s) {
11178 return String(s).toUpperCase();
11183 * @param {Mixed} s The value being converted
11184 * @return {Number} The comparison value
11186 asDate : function(s) {
11190 if(s instanceof Date){
11191 return s.getTime();
11193 return Date.parse(String(s));
11198 * @param {Mixed} s The value being converted
11199 * @return {Float} The comparison value
11201 asFloat : function(s) {
11202 var val = parseFloat(String(s).replace(/,/g, ""));
11211 * @param {Mixed} s The value being converted
11212 * @return {Number} The comparison value
11214 asInt : function(s) {
11215 var val = parseInt(String(s).replace(/,/g, ""));
11223 * Ext JS Library 1.1.1
11224 * Copyright(c) 2006-2007, Ext JS, LLC.
11226 * Originally Released Under LGPL - original licence link has changed is not relivant.
11229 * <script type="text/javascript">
11233 * @class Roo.data.Record
11234 * Instances of this class encapsulate both record <em>definition</em> information, and record
11235 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11236 * to access Records cached in an {@link Roo.data.Store} object.<br>
11238 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11239 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11242 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11244 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11245 * {@link #create}. The parameters are the same.
11246 * @param {Array} data An associative Array of data values keyed by the field name.
11247 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11248 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11249 * not specified an integer id is generated.
11251 Roo.data.Record = function(data, id){
11252 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11257 * Generate a constructor for a specific record layout.
11258 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11259 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11260 * Each field definition object may contain the following properties: <ul>
11261 * <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,
11262 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11263 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11264 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11265 * is being used, then this is a string containing the javascript expression to reference the data relative to
11266 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11267 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11268 * this may be omitted.</p></li>
11269 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11270 * <ul><li>auto (Default, implies no conversion)</li>
11275 * <li>date</li></ul></p></li>
11276 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11277 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11278 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11279 * by the Reader into an object that will be stored in the Record. It is passed the
11280 * following parameters:<ul>
11281 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11283 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11285 * <br>usage:<br><pre><code>
11286 var TopicRecord = Roo.data.Record.create(
11287 {name: 'title', mapping: 'topic_title'},
11288 {name: 'author', mapping: 'username'},
11289 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11290 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11291 {name: 'lastPoster', mapping: 'user2'},
11292 {name: 'excerpt', mapping: 'post_text'}
11295 var myNewRecord = new TopicRecord({
11296 title: 'Do my job please',
11299 lastPost: new Date(),
11300 lastPoster: 'Animal',
11301 excerpt: 'No way dude!'
11303 myStore.add(myNewRecord);
11308 Roo.data.Record.create = function(o){
11309 var f = function(){
11310 f.superclass.constructor.apply(this, arguments);
11312 Roo.extend(f, Roo.data.Record);
11313 var p = f.prototype;
11314 p.fields = new Roo.util.MixedCollection(false, function(field){
11317 for(var i = 0, len = o.length; i < len; i++){
11318 p.fields.add(new Roo.data.Field(o[i]));
11320 f.getField = function(name){
11321 return p.fields.get(name);
11326 Roo.data.Record.AUTO_ID = 1000;
11327 Roo.data.Record.EDIT = 'edit';
11328 Roo.data.Record.REJECT = 'reject';
11329 Roo.data.Record.COMMIT = 'commit';
11331 Roo.data.Record.prototype = {
11333 * Readonly flag - true if this record has been modified.
11342 join : function(store){
11343 this.store = store;
11347 * Set the named field to the specified value.
11348 * @param {String} name The name of the field to set.
11349 * @param {Object} value The value to set the field to.
11351 set : function(name, value){
11352 if(this.data[name] == value){
11356 if(!this.modified){
11357 this.modified = {};
11359 if(typeof this.modified[name] == 'undefined'){
11360 this.modified[name] = this.data[name];
11362 this.data[name] = value;
11363 if(!this.editing && this.store){
11364 this.store.afterEdit(this);
11369 * Get the value of the named field.
11370 * @param {String} name The name of the field to get the value of.
11371 * @return {Object} The value of the field.
11373 get : function(name){
11374 return this.data[name];
11378 beginEdit : function(){
11379 this.editing = true;
11380 this.modified = {};
11384 cancelEdit : function(){
11385 this.editing = false;
11386 delete this.modified;
11390 endEdit : function(){
11391 this.editing = false;
11392 if(this.dirty && this.store){
11393 this.store.afterEdit(this);
11398 * Usually called by the {@link Roo.data.Store} which owns the Record.
11399 * Rejects all changes made to the Record since either creation, or the last commit operation.
11400 * Modified fields are reverted to their original values.
11402 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11403 * of reject operations.
11405 reject : function(){
11406 var m = this.modified;
11408 if(typeof m[n] != "function"){
11409 this.data[n] = m[n];
11412 this.dirty = false;
11413 delete this.modified;
11414 this.editing = false;
11416 this.store.afterReject(this);
11421 * Usually called by the {@link Roo.data.Store} which owns the Record.
11422 * Commits all changes made to the Record since either creation, or the last commit operation.
11424 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11425 * of commit operations.
11427 commit : function(){
11428 this.dirty = false;
11429 delete this.modified;
11430 this.editing = false;
11432 this.store.afterCommit(this);
11437 hasError : function(){
11438 return this.error != null;
11442 clearError : function(){
11447 * Creates a copy of this record.
11448 * @param {String} id (optional) A new record id if you don't want to use this record's id
11451 copy : function(newId) {
11452 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11456 * Ext JS Library 1.1.1
11457 * Copyright(c) 2006-2007, Ext JS, LLC.
11459 * Originally Released Under LGPL - original licence link has changed is not relivant.
11462 * <script type="text/javascript">
11468 * @class Roo.data.Store
11469 * @extends Roo.util.Observable
11470 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11471 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11473 * 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
11474 * has no knowledge of the format of the data returned by the Proxy.<br>
11476 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11477 * instances from the data object. These records are cached and made available through accessor functions.
11479 * Creates a new Store.
11480 * @param {Object} config A config object containing the objects needed for the Store to access data,
11481 * and read the data into Records.
11483 Roo.data.Store = function(config){
11484 this.data = new Roo.util.MixedCollection(false);
11485 this.data.getKey = function(o){
11488 this.baseParams = {};
11490 this.paramNames = {
11495 "multisort" : "_multisort"
11498 if(config && config.data){
11499 this.inlineData = config.data;
11500 delete config.data;
11503 Roo.apply(this, config);
11505 if(this.reader){ // reader passed
11506 this.reader = Roo.factory(this.reader, Roo.data);
11507 this.reader.xmodule = this.xmodule || false;
11508 if(!this.recordType){
11509 this.recordType = this.reader.recordType;
11511 if(this.reader.onMetaChange){
11512 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11516 if(this.recordType){
11517 this.fields = this.recordType.prototype.fields;
11519 this.modified = [];
11523 * @event datachanged
11524 * Fires when the data cache has changed, and a widget which is using this Store
11525 * as a Record cache should refresh its view.
11526 * @param {Store} this
11528 datachanged : true,
11530 * @event metachange
11531 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11532 * @param {Store} this
11533 * @param {Object} meta The JSON metadata
11538 * Fires when Records have been added to the Store
11539 * @param {Store} this
11540 * @param {Roo.data.Record[]} records The array of Records added
11541 * @param {Number} index The index at which the record(s) were added
11546 * Fires when a Record has been removed from the Store
11547 * @param {Store} this
11548 * @param {Roo.data.Record} record The Record that was removed
11549 * @param {Number} index The index at which the record was removed
11554 * Fires when a Record has been updated
11555 * @param {Store} this
11556 * @param {Roo.data.Record} record The Record that was updated
11557 * @param {String} operation The update operation being performed. Value may be one of:
11559 Roo.data.Record.EDIT
11560 Roo.data.Record.REJECT
11561 Roo.data.Record.COMMIT
11567 * Fires when the data cache has been cleared.
11568 * @param {Store} this
11572 * @event beforeload
11573 * Fires before a request is made for a new data object. If the beforeload handler returns false
11574 * the load action will be canceled.
11575 * @param {Store} this
11576 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11580 * @event beforeloadadd
11581 * Fires after a new set of Records has been loaded.
11582 * @param {Store} this
11583 * @param {Roo.data.Record[]} records The Records that were loaded
11584 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11586 beforeloadadd : true,
11589 * Fires after a new set of Records has been loaded, before they are added to the store.
11590 * @param {Store} this
11591 * @param {Roo.data.Record[]} records The Records that were loaded
11592 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11593 * @params {Object} return from reader
11597 * @event loadexception
11598 * Fires if an exception occurs in the Proxy during loading.
11599 * Called with the signature of the Proxy's "loadexception" event.
11600 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11603 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11604 * @param {Object} load options
11605 * @param {Object} jsonData from your request (normally this contains the Exception)
11607 loadexception : true
11611 this.proxy = Roo.factory(this.proxy, Roo.data);
11612 this.proxy.xmodule = this.xmodule || false;
11613 this.relayEvents(this.proxy, ["loadexception"]);
11615 this.sortToggle = {};
11616 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11618 Roo.data.Store.superclass.constructor.call(this);
11620 if(this.inlineData){
11621 this.loadData(this.inlineData);
11622 delete this.inlineData;
11626 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11628 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11629 * without a remote query - used by combo/forms at present.
11633 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11636 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11639 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11640 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11643 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11644 * on any HTTP request
11647 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11650 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11654 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11655 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11657 remoteSort : false,
11660 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11661 * loaded or when a record is removed. (defaults to false).
11663 pruneModifiedRecords : false,
11666 lastOptions : null,
11669 * Add Records to the Store and fires the add event.
11670 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11672 add : function(records){
11673 records = [].concat(records);
11674 for(var i = 0, len = records.length; i < len; i++){
11675 records[i].join(this);
11677 var index = this.data.length;
11678 this.data.addAll(records);
11679 this.fireEvent("add", this, records, index);
11683 * Remove a Record from the Store and fires the remove event.
11684 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11686 remove : function(record){
11687 var index = this.data.indexOf(record);
11688 this.data.removeAt(index);
11690 if(this.pruneModifiedRecords){
11691 this.modified.remove(record);
11693 this.fireEvent("remove", this, record, index);
11697 * Remove all Records from the Store and fires the clear event.
11699 removeAll : function(){
11701 if(this.pruneModifiedRecords){
11702 this.modified = [];
11704 this.fireEvent("clear", this);
11708 * Inserts Records to the Store at the given index and fires the add event.
11709 * @param {Number} index The start index at which to insert the passed Records.
11710 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11712 insert : function(index, records){
11713 records = [].concat(records);
11714 for(var i = 0, len = records.length; i < len; i++){
11715 this.data.insert(index, records[i]);
11716 records[i].join(this);
11718 this.fireEvent("add", this, records, index);
11722 * Get the index within the cache of the passed Record.
11723 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11724 * @return {Number} The index of the passed Record. Returns -1 if not found.
11726 indexOf : function(record){
11727 return this.data.indexOf(record);
11731 * Get the index within the cache of the Record with the passed id.
11732 * @param {String} id The id of the Record to find.
11733 * @return {Number} The index of the Record. Returns -1 if not found.
11735 indexOfId : function(id){
11736 return this.data.indexOfKey(id);
11740 * Get the Record with the specified id.
11741 * @param {String} id The id of the Record to find.
11742 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11744 getById : function(id){
11745 return this.data.key(id);
11749 * Get the Record at the specified index.
11750 * @param {Number} index The index of the Record to find.
11751 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11753 getAt : function(index){
11754 return this.data.itemAt(index);
11758 * Returns a range of Records between specified indices.
11759 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11760 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11761 * @return {Roo.data.Record[]} An array of Records
11763 getRange : function(start, end){
11764 return this.data.getRange(start, end);
11768 storeOptions : function(o){
11769 o = Roo.apply({}, o);
11772 this.lastOptions = o;
11776 * Loads the Record cache from the configured Proxy using the configured Reader.
11778 * If using remote paging, then the first load call must specify the <em>start</em>
11779 * and <em>limit</em> properties in the options.params property to establish the initial
11780 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11782 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11783 * and this call will return before the new data has been loaded. Perform any post-processing
11784 * in a callback function, or in a "load" event handler.</strong>
11786 * @param {Object} options An object containing properties which control loading options:<ul>
11787 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11788 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11789 * passed the following arguments:<ul>
11790 * <li>r : Roo.data.Record[]</li>
11791 * <li>options: Options object from the load call</li>
11792 * <li>success: Boolean success indicator</li></ul></li>
11793 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11794 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11797 load : function(options){
11798 options = options || {};
11799 if(this.fireEvent("beforeload", this, options) !== false){
11800 this.storeOptions(options);
11801 var p = Roo.apply(options.params || {}, this.baseParams);
11802 // if meta was not loaded from remote source.. try requesting it.
11803 if (!this.reader.metaFromRemote) {
11804 p._requestMeta = 1;
11806 if(this.sortInfo && this.remoteSort){
11807 var pn = this.paramNames;
11808 p[pn["sort"]] = this.sortInfo.field;
11809 p[pn["dir"]] = this.sortInfo.direction;
11811 if (this.multiSort) {
11812 var pn = this.paramNames;
11813 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11816 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11821 * Reloads the Record cache from the configured Proxy using the configured Reader and
11822 * the options from the last load operation performed.
11823 * @param {Object} options (optional) An object containing properties which may override the options
11824 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11825 * the most recently used options are reused).
11827 reload : function(options){
11828 this.load(Roo.applyIf(options||{}, this.lastOptions));
11832 // Called as a callback by the Reader during a load operation.
11833 loadRecords : function(o, options, success){
11834 if(!o || success === false){
11835 if(success !== false){
11836 this.fireEvent("load", this, [], options, o);
11838 if(options.callback){
11839 options.callback.call(options.scope || this, [], options, false);
11843 // if data returned failure - throw an exception.
11844 if (o.success === false) {
11845 // show a message if no listener is registered.
11846 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11847 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11849 // loadmask wil be hooked into this..
11850 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11853 var r = o.records, t = o.totalRecords || r.length;
11855 this.fireEvent("beforeloadadd", this, r, options, o);
11857 if(!options || options.add !== true){
11858 if(this.pruneModifiedRecords){
11859 this.modified = [];
11861 for(var i = 0, len = r.length; i < len; i++){
11865 this.data = this.snapshot;
11866 delete this.snapshot;
11869 this.data.addAll(r);
11870 this.totalLength = t;
11872 this.fireEvent("datachanged", this);
11874 this.totalLength = Math.max(t, this.data.length+r.length);
11878 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11880 var e = new Roo.data.Record({});
11882 e.set(this.parent.displayField, this.parent.emptyTitle);
11883 e.set(this.parent.valueField, '');
11888 this.fireEvent("load", this, r, options, o);
11889 if(options.callback){
11890 options.callback.call(options.scope || this, r, options, true);
11896 * Loads data from a passed data block. A Reader which understands the format of the data
11897 * must have been configured in the constructor.
11898 * @param {Object} data The data block from which to read the Records. The format of the data expected
11899 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11900 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11902 loadData : function(o, append){
11903 var r = this.reader.readRecords(o);
11904 this.loadRecords(r, {add: append}, true);
11908 * Gets the number of cached records.
11910 * <em>If using paging, this may not be the total size of the dataset. If the data object
11911 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11912 * the data set size</em>
11914 getCount : function(){
11915 return this.data.length || 0;
11919 * Gets the total number of records in the dataset as returned by the server.
11921 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11922 * the dataset size</em>
11924 getTotalCount : function(){
11925 return this.totalLength || 0;
11929 * Returns the sort state of the Store as an object with two properties:
11931 field {String} The name of the field by which the Records are sorted
11932 direction {String} The sort order, "ASC" or "DESC"
11935 getSortState : function(){
11936 return this.sortInfo;
11940 applySort : function(){
11941 if(this.sortInfo && !this.remoteSort){
11942 var s = this.sortInfo, f = s.field;
11943 var st = this.fields.get(f).sortType;
11944 var fn = function(r1, r2){
11945 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11946 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11948 this.data.sort(s.direction, fn);
11949 if(this.snapshot && this.snapshot != this.data){
11950 this.snapshot.sort(s.direction, fn);
11956 * Sets the default sort column and order to be used by the next load operation.
11957 * @param {String} fieldName The name of the field to sort by.
11958 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11960 setDefaultSort : function(field, dir){
11961 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11965 * Sort the Records.
11966 * If remote sorting is used, the sort is performed on the server, and the cache is
11967 * reloaded. If local sorting is used, the cache is sorted internally.
11968 * @param {String} fieldName The name of the field to sort by.
11969 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11971 sort : function(fieldName, dir){
11972 var f = this.fields.get(fieldName);
11974 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11976 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11977 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11982 this.sortToggle[f.name] = dir;
11983 this.sortInfo = {field: f.name, direction: dir};
11984 if(!this.remoteSort){
11986 this.fireEvent("datachanged", this);
11988 this.load(this.lastOptions);
11993 * Calls the specified function for each of the Records in the cache.
11994 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11995 * Returning <em>false</em> aborts and exits the iteration.
11996 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11998 each : function(fn, scope){
11999 this.data.each(fn, scope);
12003 * Gets all records modified since the last commit. Modified records are persisted across load operations
12004 * (e.g., during paging).
12005 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
12007 getModifiedRecords : function(){
12008 return this.modified;
12012 createFilterFn : function(property, value, anyMatch){
12013 if(!value.exec){ // not a regex
12014 value = String(value);
12015 if(value.length == 0){
12018 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
12020 return function(r){
12021 return value.test(r.data[property]);
12026 * Sums the value of <i>property</i> for each record between start and end and returns the result.
12027 * @param {String} property A field on your records
12028 * @param {Number} start The record index to start at (defaults to 0)
12029 * @param {Number} end The last record index to include (defaults to length - 1)
12030 * @return {Number} The sum
12032 sum : function(property, start, end){
12033 var rs = this.data.items, v = 0;
12034 start = start || 0;
12035 end = (end || end === 0) ? end : rs.length-1;
12037 for(var i = start; i <= end; i++){
12038 v += (rs[i].data[property] || 0);
12044 * Filter the records by a specified property.
12045 * @param {String} field A field on your records
12046 * @param {String/RegExp} value Either a string that the field
12047 * should start with or a RegExp to test against the field
12048 * @param {Boolean} anyMatch True to match any part not just the beginning
12050 filter : function(property, value, anyMatch){
12051 var fn = this.createFilterFn(property, value, anyMatch);
12052 return fn ? this.filterBy(fn) : this.clearFilter();
12056 * Filter by a function. The specified function will be called with each
12057 * record in this data source. If the function returns true the record is included,
12058 * otherwise it is filtered.
12059 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12060 * @param {Object} scope (optional) The scope of the function (defaults to this)
12062 filterBy : function(fn, scope){
12063 this.snapshot = this.snapshot || this.data;
12064 this.data = this.queryBy(fn, scope||this);
12065 this.fireEvent("datachanged", this);
12069 * Query the records by a specified property.
12070 * @param {String} field A field on your records
12071 * @param {String/RegExp} value Either a string that the field
12072 * should start with or a RegExp to test against the field
12073 * @param {Boolean} anyMatch True to match any part not just the beginning
12074 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12076 query : function(property, value, anyMatch){
12077 var fn = this.createFilterFn(property, value, anyMatch);
12078 return fn ? this.queryBy(fn) : this.data.clone();
12082 * Query by a function. The specified function will be called with each
12083 * record in this data source. If the function returns true the record is included
12085 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12086 * @param {Object} scope (optional) The scope of the function (defaults to this)
12087 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12089 queryBy : function(fn, scope){
12090 var data = this.snapshot || this.data;
12091 return data.filterBy(fn, scope||this);
12095 * Collects unique values for a particular dataIndex from this store.
12096 * @param {String} dataIndex The property to collect
12097 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12098 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12099 * @return {Array} An array of the unique values
12101 collect : function(dataIndex, allowNull, bypassFilter){
12102 var d = (bypassFilter === true && this.snapshot) ?
12103 this.snapshot.items : this.data.items;
12104 var v, sv, r = [], l = {};
12105 for(var i = 0, len = d.length; i < len; i++){
12106 v = d[i].data[dataIndex];
12108 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12117 * Revert to a view of the Record cache with no filtering applied.
12118 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12120 clearFilter : function(suppressEvent){
12121 if(this.snapshot && this.snapshot != this.data){
12122 this.data = this.snapshot;
12123 delete this.snapshot;
12124 if(suppressEvent !== true){
12125 this.fireEvent("datachanged", this);
12131 afterEdit : function(record){
12132 if(this.modified.indexOf(record) == -1){
12133 this.modified.push(record);
12135 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12139 afterReject : function(record){
12140 this.modified.remove(record);
12141 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12145 afterCommit : function(record){
12146 this.modified.remove(record);
12147 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12151 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12152 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12154 commitChanges : function(){
12155 var m = this.modified.slice(0);
12156 this.modified = [];
12157 for(var i = 0, len = m.length; i < len; i++){
12163 * Cancel outstanding changes on all changed records.
12165 rejectChanges : function(){
12166 var m = this.modified.slice(0);
12167 this.modified = [];
12168 for(var i = 0, len = m.length; i < len; i++){
12173 onMetaChange : function(meta, rtype, o){
12174 this.recordType = rtype;
12175 this.fields = rtype.prototype.fields;
12176 delete this.snapshot;
12177 this.sortInfo = meta.sortInfo || this.sortInfo;
12178 this.modified = [];
12179 this.fireEvent('metachange', this, this.reader.meta);
12182 moveIndex : function(data, type)
12184 var index = this.indexOf(data);
12186 var newIndex = index + type;
12190 this.insert(newIndex, data);
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 * @class Roo.data.SimpleStore
12206 * @extends Roo.data.Store
12207 * Small helper class to make creating Stores from Array data easier.
12208 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12209 * @cfg {Array} fields An array of field definition objects, or field name strings.
12210 * @cfg {Array} data The multi-dimensional array of data
12212 * @param {Object} config
12214 Roo.data.SimpleStore = function(config){
12215 Roo.data.SimpleStore.superclass.constructor.call(this, {
12217 reader: new Roo.data.ArrayReader({
12220 Roo.data.Record.create(config.fields)
12222 proxy : new Roo.data.MemoryProxy(config.data)
12226 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12228 * Ext JS Library 1.1.1
12229 * Copyright(c) 2006-2007, Ext JS, LLC.
12231 * Originally Released Under LGPL - original licence link has changed is not relivant.
12234 * <script type="text/javascript">
12239 * @extends Roo.data.Store
12240 * @class Roo.data.JsonStore
12241 * Small helper class to make creating Stores for JSON data easier. <br/>
12243 var store = new Roo.data.JsonStore({
12244 url: 'get-images.php',
12246 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12249 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12250 * JsonReader and HttpProxy (unless inline data is provided).</b>
12251 * @cfg {Array} fields An array of field definition objects, or field name strings.
12253 * @param {Object} config
12255 Roo.data.JsonStore = function(c){
12256 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12257 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12258 reader: new Roo.data.JsonReader(c, c.fields)
12261 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12263 * Ext JS Library 1.1.1
12264 * Copyright(c) 2006-2007, Ext JS, LLC.
12266 * Originally Released Under LGPL - original licence link has changed is not relivant.
12269 * <script type="text/javascript">
12273 Roo.data.Field = function(config){
12274 if(typeof config == "string"){
12275 config = {name: config};
12277 Roo.apply(this, config);
12280 this.type = "auto";
12283 var st = Roo.data.SortTypes;
12284 // named sortTypes are supported, here we look them up
12285 if(typeof this.sortType == "string"){
12286 this.sortType = st[this.sortType];
12289 // set default sortType for strings and dates
12290 if(!this.sortType){
12293 this.sortType = st.asUCString;
12296 this.sortType = st.asDate;
12299 this.sortType = st.none;
12304 var stripRe = /[\$,%]/g;
12306 // prebuilt conversion function for this field, instead of
12307 // switching every time we're reading a value
12309 var cv, dateFormat = this.dateFormat;
12314 cv = function(v){ return v; };
12317 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12321 return v !== undefined && v !== null && v !== '' ?
12322 parseInt(String(v).replace(stripRe, ""), 10) : '';
12327 return v !== undefined && v !== null && v !== '' ?
12328 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12333 cv = function(v){ return v === true || v === "true" || v == 1; };
12340 if(v instanceof Date){
12344 if(dateFormat == "timestamp"){
12345 return new Date(v*1000);
12347 return Date.parseDate(v, dateFormat);
12349 var parsed = Date.parse(v);
12350 return parsed ? new Date(parsed) : null;
12359 Roo.data.Field.prototype = {
12367 * Ext JS Library 1.1.1
12368 * Copyright(c) 2006-2007, Ext JS, LLC.
12370 * Originally Released Under LGPL - original licence link has changed is not relivant.
12373 * <script type="text/javascript">
12376 // Base class for reading structured data from a data source. This class is intended to be
12377 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12380 * @class Roo.data.DataReader
12381 * Base class for reading structured data from a data source. This class is intended to be
12382 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12385 Roo.data.DataReader = function(meta, recordType){
12389 this.recordType = recordType instanceof Array ?
12390 Roo.data.Record.create(recordType) : recordType;
12393 Roo.data.DataReader.prototype = {
12395 * Create an empty record
12396 * @param {Object} data (optional) - overlay some values
12397 * @return {Roo.data.Record} record created.
12399 newRow : function(d) {
12401 this.recordType.prototype.fields.each(function(c) {
12403 case 'int' : da[c.name] = 0; break;
12404 case 'date' : da[c.name] = new Date(); break;
12405 case 'float' : da[c.name] = 0.0; break;
12406 case 'boolean' : da[c.name] = false; break;
12407 default : da[c.name] = ""; break;
12411 return new this.recordType(Roo.apply(da, d));
12416 * Ext JS Library 1.1.1
12417 * Copyright(c) 2006-2007, Ext JS, LLC.
12419 * Originally Released Under LGPL - original licence link has changed is not relivant.
12422 * <script type="text/javascript">
12426 * @class Roo.data.DataProxy
12427 * @extends Roo.data.Observable
12428 * This class is an abstract base class for implementations which provide retrieval of
12429 * unformatted data objects.<br>
12431 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12432 * (of the appropriate type which knows how to parse the data object) to provide a block of
12433 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12435 * Custom implementations must implement the load method as described in
12436 * {@link Roo.data.HttpProxy#load}.
12438 Roo.data.DataProxy = function(){
12441 * @event beforeload
12442 * Fires before a network request is made to retrieve a data object.
12443 * @param {Object} This DataProxy object.
12444 * @param {Object} params The params parameter to the load function.
12449 * Fires before the load method's callback is called.
12450 * @param {Object} This DataProxy object.
12451 * @param {Object} o The data object.
12452 * @param {Object} arg The callback argument object passed to the load function.
12456 * @event loadexception
12457 * Fires if an Exception occurs during data retrieval.
12458 * @param {Object} This DataProxy object.
12459 * @param {Object} o The data object.
12460 * @param {Object} arg The callback argument object passed to the load function.
12461 * @param {Object} e The Exception.
12463 loadexception : true
12465 Roo.data.DataProxy.superclass.constructor.call(this);
12468 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12471 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12475 * Ext JS Library 1.1.1
12476 * Copyright(c) 2006-2007, Ext JS, LLC.
12478 * Originally Released Under LGPL - original licence link has changed is not relivant.
12481 * <script type="text/javascript">
12484 * @class Roo.data.MemoryProxy
12485 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12486 * to the Reader when its load method is called.
12488 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12490 Roo.data.MemoryProxy = function(data){
12494 Roo.data.MemoryProxy.superclass.constructor.call(this);
12498 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12501 * Load data from the requested source (in this case an in-memory
12502 * data object passed to the constructor), read the data object into
12503 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12504 * process that block using the passed callback.
12505 * @param {Object} params This parameter is not used by the MemoryProxy class.
12506 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12507 * object into a block of Roo.data.Records.
12508 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12509 * The function must be passed <ul>
12510 * <li>The Record block object</li>
12511 * <li>The "arg" argument from the load function</li>
12512 * <li>A boolean success indicator</li>
12514 * @param {Object} scope The scope in which to call the callback
12515 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12517 load : function(params, reader, callback, scope, arg){
12518 params = params || {};
12521 result = reader.readRecords(params.data ? params.data :this.data);
12523 this.fireEvent("loadexception", this, arg, null, e);
12524 callback.call(scope, null, arg, false);
12527 callback.call(scope, result, arg, true);
12531 update : function(params, records){
12536 * Ext JS Library 1.1.1
12537 * Copyright(c) 2006-2007, Ext JS, LLC.
12539 * Originally Released Under LGPL - original licence link has changed is not relivant.
12542 * <script type="text/javascript">
12545 * @class Roo.data.HttpProxy
12546 * @extends Roo.data.DataProxy
12547 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12548 * configured to reference a certain URL.<br><br>
12550 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12551 * from which the running page was served.<br><br>
12553 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12555 * Be aware that to enable the browser to parse an XML document, the server must set
12556 * the Content-Type header in the HTTP response to "text/xml".
12558 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12559 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12560 * will be used to make the request.
12562 Roo.data.HttpProxy = function(conn){
12563 Roo.data.HttpProxy.superclass.constructor.call(this);
12564 // is conn a conn config or a real conn?
12566 this.useAjax = !conn || !conn.events;
12570 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12571 // thse are take from connection...
12574 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12577 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12578 * extra parameters to each request made by this object. (defaults to undefined)
12581 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12582 * to each request made by this object. (defaults to undefined)
12585 * @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)
12588 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12591 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12597 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12601 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12602 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12603 * a finer-grained basis than the DataProxy events.
12605 getConnection : function(){
12606 return this.useAjax ? Roo.Ajax : this.conn;
12610 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12611 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12612 * process that block using the passed callback.
12613 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12614 * for the request to the remote server.
12615 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12616 * object into a block of Roo.data.Records.
12617 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12618 * The function must be passed <ul>
12619 * <li>The Record block object</li>
12620 * <li>The "arg" argument from the load function</li>
12621 * <li>A boolean success indicator</li>
12623 * @param {Object} scope The scope in which to call the callback
12624 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12626 load : function(params, reader, callback, scope, arg){
12627 if(this.fireEvent("beforeload", this, params) !== false){
12629 params : params || {},
12631 callback : callback,
12636 callback : this.loadResponse,
12640 Roo.applyIf(o, this.conn);
12641 if(this.activeRequest){
12642 Roo.Ajax.abort(this.activeRequest);
12644 this.activeRequest = Roo.Ajax.request(o);
12646 this.conn.request(o);
12649 callback.call(scope||this, null, arg, false);
12654 loadResponse : function(o, success, response){
12655 delete this.activeRequest;
12657 this.fireEvent("loadexception", this, o, response);
12658 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12663 result = o.reader.read(response);
12665 this.fireEvent("loadexception", this, o, response, e);
12666 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12670 this.fireEvent("load", this, o, o.request.arg);
12671 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12675 update : function(dataSet){
12680 updateResponse : function(dataSet){
12685 * Ext JS Library 1.1.1
12686 * Copyright(c) 2006-2007, Ext JS, LLC.
12688 * Originally Released Under LGPL - original licence link has changed is not relivant.
12691 * <script type="text/javascript">
12695 * @class Roo.data.ScriptTagProxy
12696 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12697 * other than the originating domain of the running page.<br><br>
12699 * <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
12700 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12702 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12703 * source code that is used as the source inside a <script> tag.<br><br>
12705 * In order for the browser to process the returned data, the server must wrap the data object
12706 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12707 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12708 * depending on whether the callback name was passed:
12711 boolean scriptTag = false;
12712 String cb = request.getParameter("callback");
12715 response.setContentType("text/javascript");
12717 response.setContentType("application/x-json");
12719 Writer out = response.getWriter();
12721 out.write(cb + "(");
12723 out.print(dataBlock.toJsonString());
12730 * @param {Object} config A configuration object.
12732 Roo.data.ScriptTagProxy = function(config){
12733 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12734 Roo.apply(this, config);
12735 this.head = document.getElementsByTagName("head")[0];
12738 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12740 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12742 * @cfg {String} url The URL from which to request the data object.
12745 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12749 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12750 * the server the name of the callback function set up by the load call to process the returned data object.
12751 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12752 * javascript output which calls this named function passing the data object as its only parameter.
12754 callbackParam : "callback",
12756 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12757 * name to the request.
12762 * Load data from the configured URL, read the data object into
12763 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12764 * process that block using the passed callback.
12765 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12766 * for the request to the remote server.
12767 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12768 * object into a block of Roo.data.Records.
12769 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12770 * The function must be passed <ul>
12771 * <li>The Record block object</li>
12772 * <li>The "arg" argument from the load function</li>
12773 * <li>A boolean success indicator</li>
12775 * @param {Object} scope The scope in which to call the callback
12776 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12778 load : function(params, reader, callback, scope, arg){
12779 if(this.fireEvent("beforeload", this, params) !== false){
12781 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12783 var url = this.url;
12784 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12786 url += "&_dc=" + (new Date().getTime());
12788 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12791 cb : "stcCallback"+transId,
12792 scriptId : "stcScript"+transId,
12796 callback : callback,
12802 window[trans.cb] = function(o){
12803 conn.handleResponse(o, trans);
12806 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12808 if(this.autoAbort !== false){
12812 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12814 var script = document.createElement("script");
12815 script.setAttribute("src", url);
12816 script.setAttribute("type", "text/javascript");
12817 script.setAttribute("id", trans.scriptId);
12818 this.head.appendChild(script);
12820 this.trans = trans;
12822 callback.call(scope||this, null, arg, false);
12827 isLoading : function(){
12828 return this.trans ? true : false;
12832 * Abort the current server request.
12834 abort : function(){
12835 if(this.isLoading()){
12836 this.destroyTrans(this.trans);
12841 destroyTrans : function(trans, isLoaded){
12842 this.head.removeChild(document.getElementById(trans.scriptId));
12843 clearTimeout(trans.timeoutId);
12845 window[trans.cb] = undefined;
12847 delete window[trans.cb];
12850 // if hasn't been loaded, wait for load to remove it to prevent script error
12851 window[trans.cb] = function(){
12852 window[trans.cb] = undefined;
12854 delete window[trans.cb];
12861 handleResponse : function(o, trans){
12862 this.trans = false;
12863 this.destroyTrans(trans, true);
12866 result = trans.reader.readRecords(o);
12868 this.fireEvent("loadexception", this, o, trans.arg, e);
12869 trans.callback.call(trans.scope||window, null, trans.arg, false);
12872 this.fireEvent("load", this, o, trans.arg);
12873 trans.callback.call(trans.scope||window, result, trans.arg, true);
12877 handleFailure : function(trans){
12878 this.trans = false;
12879 this.destroyTrans(trans, false);
12880 this.fireEvent("loadexception", this, null, trans.arg);
12881 trans.callback.call(trans.scope||window, null, trans.arg, false);
12885 * Ext JS Library 1.1.1
12886 * Copyright(c) 2006-2007, Ext JS, LLC.
12888 * Originally Released Under LGPL - original licence link has changed is not relivant.
12891 * <script type="text/javascript">
12895 * @class Roo.data.JsonReader
12896 * @extends Roo.data.DataReader
12897 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12898 * based on mappings in a provided Roo.data.Record constructor.
12900 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12901 * in the reply previously.
12906 var RecordDef = Roo.data.Record.create([
12907 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12908 {name: 'occupation'} // This field will use "occupation" as the mapping.
12910 var myReader = new Roo.data.JsonReader({
12911 totalProperty: "results", // The property which contains the total dataset size (optional)
12912 root: "rows", // The property which contains an Array of row objects
12913 id: "id" // The property within each row object that provides an ID for the record (optional)
12917 * This would consume a JSON file like this:
12919 { 'results': 2, 'rows': [
12920 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12921 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12924 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12925 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12926 * paged from the remote server.
12927 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12928 * @cfg {String} root name of the property which contains the Array of row objects.
12929 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12930 * @cfg {Array} fields Array of field definition objects
12932 * Create a new JsonReader
12933 * @param {Object} meta Metadata configuration options
12934 * @param {Object} recordType Either an Array of field definition objects,
12935 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12937 Roo.data.JsonReader = function(meta, recordType){
12940 // set some defaults:
12941 Roo.applyIf(meta, {
12942 totalProperty: 'total',
12943 successProperty : 'success',
12948 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12950 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12953 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12954 * Used by Store query builder to append _requestMeta to params.
12957 metaFromRemote : false,
12959 * This method is only used by a DataProxy which has retrieved data from a remote server.
12960 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12961 * @return {Object} data A data block which is used by an Roo.data.Store object as
12962 * a cache of Roo.data.Records.
12964 read : function(response){
12965 var json = response.responseText;
12967 var o = /* eval:var:o */ eval("("+json+")");
12969 throw {message: "JsonReader.read: Json object not found"};
12975 this.metaFromRemote = true;
12976 this.meta = o.metaData;
12977 this.recordType = Roo.data.Record.create(o.metaData.fields);
12978 this.onMetaChange(this.meta, this.recordType, o);
12980 return this.readRecords(o);
12983 // private function a store will implement
12984 onMetaChange : function(meta, recordType, o){
12991 simpleAccess: function(obj, subsc) {
12998 getJsonAccessor: function(){
13000 return function(expr) {
13002 return(re.test(expr))
13003 ? new Function("obj", "return obj." + expr)
13008 return Roo.emptyFn;
13013 * Create a data block containing Roo.data.Records from an XML document.
13014 * @param {Object} o An object which contains an Array of row objects in the property specified
13015 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
13016 * which contains the total size of the dataset.
13017 * @return {Object} data A data block which is used by an Roo.data.Store object as
13018 * a cache of Roo.data.Records.
13020 readRecords : function(o){
13022 * After any data loads, the raw JSON data is available for further custom processing.
13026 var s = this.meta, Record = this.recordType,
13027 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
13029 // Generate extraction functions for the totalProperty, the root, the id, and for each field
13031 if(s.totalProperty) {
13032 this.getTotal = this.getJsonAccessor(s.totalProperty);
13034 if(s.successProperty) {
13035 this.getSuccess = this.getJsonAccessor(s.successProperty);
13037 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
13039 var g = this.getJsonAccessor(s.id);
13040 this.getId = function(rec) {
13042 return (r === undefined || r === "") ? null : r;
13045 this.getId = function(){return null;};
13048 for(var jj = 0; jj < fl; jj++){
13050 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
13051 this.ef[jj] = this.getJsonAccessor(map);
13055 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13056 if(s.totalProperty){
13057 var vt = parseInt(this.getTotal(o), 10);
13062 if(s.successProperty){
13063 var vs = this.getSuccess(o);
13064 if(vs === false || vs === 'false'){
13069 for(var i = 0; i < c; i++){
13072 var id = this.getId(n);
13073 for(var j = 0; j < fl; j++){
13075 var v = this.ef[j](n);
13077 Roo.log('missing convert for ' + f.name);
13081 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13083 var record = new Record(values, id);
13085 records[i] = record;
13091 totalRecords : totalRecords
13096 * Ext JS Library 1.1.1
13097 * Copyright(c) 2006-2007, Ext JS, LLC.
13099 * Originally Released Under LGPL - original licence link has changed is not relivant.
13102 * <script type="text/javascript">
13106 * @class Roo.data.ArrayReader
13107 * @extends Roo.data.DataReader
13108 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13109 * Each element of that Array represents a row of data fields. The
13110 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13111 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13115 var RecordDef = Roo.data.Record.create([
13116 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13117 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13119 var myReader = new Roo.data.ArrayReader({
13120 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13124 * This would consume an Array like this:
13126 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13130 * Create a new JsonReader
13131 * @param {Object} meta Metadata configuration options.
13132 * @param {Object|Array} recordType Either an Array of field definition objects
13134 * @cfg {Array} fields Array of field definition objects
13135 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13136 * as specified to {@link Roo.data.Record#create},
13137 * or an {@link Roo.data.Record} object
13140 * created using {@link Roo.data.Record#create}.
13142 Roo.data.ArrayReader = function(meta, recordType){
13145 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13148 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13150 * Create a data block containing Roo.data.Records from an XML document.
13151 * @param {Object} o An Array of row objects which represents the dataset.
13152 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13153 * a cache of Roo.data.Records.
13155 readRecords : function(o){
13156 var sid = this.meta ? this.meta.id : null;
13157 var recordType = this.recordType, fields = recordType.prototype.fields;
13160 for(var i = 0; i < root.length; i++){
13163 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13164 for(var j = 0, jlen = fields.length; j < jlen; j++){
13165 var f = fields.items[j];
13166 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13167 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13169 values[f.name] = v;
13171 var record = new recordType(values, id);
13173 records[records.length] = record;
13177 totalRecords : records.length
13186 * @class Roo.bootstrap.ComboBox
13187 * @extends Roo.bootstrap.TriggerField
13188 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13189 * @cfg {Boolean} append (true|false) default false
13190 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13191 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13192 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13193 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13194 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13195 * @cfg {Boolean} animate default true
13196 * @cfg {Boolean} emptyResultText only for touch device
13197 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13198 * @cfg {String} emptyTitle default ''
13200 * Create a new ComboBox.
13201 * @param {Object} config Configuration options
13203 Roo.bootstrap.ComboBox = function(config){
13204 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13208 * Fires when the dropdown list is expanded
13209 * @param {Roo.bootstrap.ComboBox} combo This combo box
13214 * Fires when the dropdown list is collapsed
13215 * @param {Roo.bootstrap.ComboBox} combo This combo box
13219 * @event beforeselect
13220 * Fires before a list item is selected. Return false to cancel the selection.
13221 * @param {Roo.bootstrap.ComboBox} combo This combo box
13222 * @param {Roo.data.Record} record The data record returned from the underlying store
13223 * @param {Number} index The index of the selected item in the dropdown list
13225 'beforeselect' : true,
13228 * Fires when a list item is selected
13229 * @param {Roo.bootstrap.ComboBox} combo This combo box
13230 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13231 * @param {Number} index The index of the selected item in the dropdown list
13235 * @event beforequery
13236 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13237 * The event object passed has these properties:
13238 * @param {Roo.bootstrap.ComboBox} combo This combo box
13239 * @param {String} query The query
13240 * @param {Boolean} forceAll true to force "all" query
13241 * @param {Boolean} cancel true to cancel the query
13242 * @param {Object} e The query event object
13244 'beforequery': true,
13247 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13248 * @param {Roo.bootstrap.ComboBox} combo This combo box
13253 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13254 * @param {Roo.bootstrap.ComboBox} combo This combo box
13255 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13260 * Fires when the remove value from the combobox array
13261 * @param {Roo.bootstrap.ComboBox} combo This combo box
13265 * @event afterremove
13266 * Fires when the remove value from the combobox array
13267 * @param {Roo.bootstrap.ComboBox} combo This combo box
13269 'afterremove' : true,
13271 * @event specialfilter
13272 * Fires when specialfilter
13273 * @param {Roo.bootstrap.ComboBox} combo This combo box
13275 'specialfilter' : true,
13278 * Fires when tick the element
13279 * @param {Roo.bootstrap.ComboBox} combo This combo box
13283 * @event touchviewdisplay
13284 * Fires when touch view require special display (default is using displayField)
13285 * @param {Roo.bootstrap.ComboBox} combo This combo box
13286 * @param {Object} cfg set html .
13288 'touchviewdisplay' : true
13293 this.tickItems = [];
13295 this.selectedIndex = -1;
13296 if(this.mode == 'local'){
13297 if(config.queryDelay === undefined){
13298 this.queryDelay = 10;
13300 if(config.minChars === undefined){
13306 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13309 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13310 * rendering into an Roo.Editor, defaults to false)
13313 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13314 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13317 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13320 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13321 * the dropdown list (defaults to undefined, with no header element)
13325 * @cfg {String/Roo.Template} tpl The template to use to render the output
13329 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13331 listWidth: undefined,
13333 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13334 * mode = 'remote' or 'text' if mode = 'local')
13336 displayField: undefined,
13339 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13340 * mode = 'remote' or 'value' if mode = 'local').
13341 * Note: use of a valueField requires the user make a selection
13342 * in order for a value to be mapped.
13344 valueField: undefined,
13346 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13351 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13352 * field's data value (defaults to the underlying DOM element's name)
13354 hiddenName: undefined,
13356 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13360 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13362 selectedClass: 'active',
13365 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13369 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13370 * anchor positions (defaults to 'tl-bl')
13372 listAlign: 'tl-bl?',
13374 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13378 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13379 * query specified by the allQuery config option (defaults to 'query')
13381 triggerAction: 'query',
13383 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13384 * (defaults to 4, does not apply if editable = false)
13388 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13389 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13393 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13394 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13398 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13399 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13403 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13404 * when editable = true (defaults to false)
13406 selectOnFocus:false,
13408 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13410 queryParam: 'query',
13412 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13413 * when mode = 'remote' (defaults to 'Loading...')
13415 loadingText: 'Loading...',
13417 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13421 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13425 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13426 * traditional select (defaults to true)
13430 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13434 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13438 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13439 * listWidth has a higher value)
13443 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13444 * allow the user to set arbitrary text into the field (defaults to false)
13446 forceSelection:false,
13448 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13449 * if typeAhead = true (defaults to 250)
13451 typeAheadDelay : 250,
13453 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13454 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13456 valueNotFoundText : undefined,
13458 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13460 blockFocus : false,
13463 * @cfg {Boolean} disableClear Disable showing of clear button.
13465 disableClear : false,
13467 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13469 alwaysQuery : false,
13472 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13477 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13479 invalidClass : "has-warning",
13482 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13484 validClass : "has-success",
13487 * @cfg {Boolean} specialFilter (true|false) special filter default false
13489 specialFilter : false,
13492 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13494 mobileTouchView : true,
13497 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13499 useNativeIOS : false,
13502 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13504 mobile_restrict_height : false,
13506 ios_options : false,
13518 btnPosition : 'right',
13519 triggerList : true,
13520 showToggleBtn : true,
13522 emptyResultText: 'Empty',
13523 triggerText : 'Select',
13526 // element that contains real text value.. (when hidden is used..)
13528 getAutoCreate : function()
13533 * Render classic select for iso
13536 if(Roo.isIOS && this.useNativeIOS){
13537 cfg = this.getAutoCreateNativeIOS();
13545 if(Roo.isTouch && this.mobileTouchView){
13546 cfg = this.getAutoCreateTouchView();
13553 if(!this.tickable){
13554 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13559 * ComboBox with tickable selections
13562 var align = this.labelAlign || this.parentLabelAlign();
13565 cls : 'form-group roo-combobox-tickable' //input-group
13568 var btn_text_select = '';
13569 var btn_text_done = '';
13570 var btn_text_cancel = '';
13572 if (this.btn_text_show) {
13573 btn_text_select = 'Select';
13574 btn_text_done = 'Done';
13575 btn_text_cancel = 'Cancel';
13580 cls : 'tickable-buttons',
13585 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13586 //html : this.triggerText
13587 html: btn_text_select
13593 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13595 html: btn_text_done
13601 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13603 html: btn_text_cancel
13609 buttons.cn.unshift({
13611 cls: 'roo-select2-search-field-input'
13617 Roo.each(buttons.cn, function(c){
13619 c.cls += ' btn-' + _this.size;
13622 if (_this.disabled) {
13629 style : 'display: contents',
13634 cls: 'form-hidden-field'
13638 cls: 'roo-select2-choices',
13642 cls: 'roo-select2-search-field',
13653 cls: 'roo-select2-container input-group roo-select2-container-multi',
13659 // cls: 'typeahead typeahead-long dropdown-menu',
13660 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13665 if(this.hasFeedback && !this.allowBlank){
13669 cls: 'glyphicon form-control-feedback'
13672 combobox.cn.push(feedback);
13677 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13678 tooltip : 'This field is required'
13680 if (Roo.bootstrap.version == 4) {
13683 style : 'display:none'
13686 if (align ==='left' && this.fieldLabel.length) {
13688 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13695 cls : 'control-label col-form-label',
13696 html : this.fieldLabel
13708 var labelCfg = cfg.cn[1];
13709 var contentCfg = cfg.cn[2];
13712 if(this.indicatorpos == 'right'){
13718 cls : 'control-label col-form-label',
13722 html : this.fieldLabel
13738 labelCfg = cfg.cn[0];
13739 contentCfg = cfg.cn[1];
13743 if(this.labelWidth > 12){
13744 labelCfg.style = "width: " + this.labelWidth + 'px';
13747 if(this.labelWidth < 13 && this.labelmd == 0){
13748 this.labelmd = this.labelWidth;
13751 if(this.labellg > 0){
13752 labelCfg.cls += ' col-lg-' + this.labellg;
13753 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13756 if(this.labelmd > 0){
13757 labelCfg.cls += ' col-md-' + this.labelmd;
13758 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13761 if(this.labelsm > 0){
13762 labelCfg.cls += ' col-sm-' + this.labelsm;
13763 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13766 if(this.labelxs > 0){
13767 labelCfg.cls += ' col-xs-' + this.labelxs;
13768 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13772 } else if ( this.fieldLabel.length) {
13773 // Roo.log(" label");
13778 //cls : 'input-group-addon',
13779 html : this.fieldLabel
13784 if(this.indicatorpos == 'right'){
13788 //cls : 'input-group-addon',
13789 html : this.fieldLabel
13799 // Roo.log(" no label && no align");
13806 ['xs','sm','md','lg'].map(function(size){
13807 if (settings[size]) {
13808 cfg.cls += ' col-' + size + '-' + settings[size];
13816 _initEventsCalled : false,
13819 initEvents: function()
13821 if (this._initEventsCalled) { // as we call render... prevent looping...
13824 this._initEventsCalled = true;
13827 throw "can not find store for combo";
13830 this.indicator = this.indicatorEl();
13832 this.store = Roo.factory(this.store, Roo.data);
13833 this.store.parent = this;
13835 // if we are building from html. then this element is so complex, that we can not really
13836 // use the rendered HTML.
13837 // so we have to trash and replace the previous code.
13838 if (Roo.XComponent.build_from_html) {
13839 // remove this element....
13840 var e = this.el.dom, k=0;
13841 while (e ) { e = e.previousSibling; ++k;}
13846 this.rendered = false;
13848 this.render(this.parent().getChildContainer(true), k);
13851 if(Roo.isIOS && this.useNativeIOS){
13852 this.initIOSView();
13860 if(Roo.isTouch && this.mobileTouchView){
13861 this.initTouchView();
13866 this.initTickableEvents();
13870 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13872 if(this.hiddenName){
13874 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13876 this.hiddenField.dom.value =
13877 this.hiddenValue !== undefined ? this.hiddenValue :
13878 this.value !== undefined ? this.value : '';
13880 // prevent input submission
13881 this.el.dom.removeAttribute('name');
13882 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13887 // this.el.dom.setAttribute('autocomplete', 'off');
13890 var cls = 'x-combo-list';
13892 //this.list = new Roo.Layer({
13893 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13899 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13900 _this.list.setWidth(lw);
13903 this.list.on('mouseover', this.onViewOver, this);
13904 this.list.on('mousemove', this.onViewMove, this);
13905 this.list.on('scroll', this.onViewScroll, this);
13908 this.list.swallowEvent('mousewheel');
13909 this.assetHeight = 0;
13912 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13913 this.assetHeight += this.header.getHeight();
13916 this.innerList = this.list.createChild({cls:cls+'-inner'});
13917 this.innerList.on('mouseover', this.onViewOver, this);
13918 this.innerList.on('mousemove', this.onViewMove, this);
13919 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13921 if(this.allowBlank && !this.pageSize && !this.disableClear){
13922 this.footer = this.list.createChild({cls:cls+'-ft'});
13923 this.pageTb = new Roo.Toolbar(this.footer);
13927 this.footer = this.list.createChild({cls:cls+'-ft'});
13928 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13929 {pageSize: this.pageSize});
13933 if (this.pageTb && this.allowBlank && !this.disableClear) {
13935 this.pageTb.add(new Roo.Toolbar.Fill(), {
13936 cls: 'x-btn-icon x-btn-clear',
13938 handler: function()
13941 _this.clearValue();
13942 _this.onSelect(false, -1);
13947 this.assetHeight += this.footer.getHeight();
13952 this.tpl = Roo.bootstrap.version == 4 ?
13953 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13954 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13957 this.view = new Roo.View(this.list, this.tpl, {
13958 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13960 //this.view.wrapEl.setDisplayed(false);
13961 this.view.on('click', this.onViewClick, this);
13964 this.store.on('beforeload', this.onBeforeLoad, this);
13965 this.store.on('load', this.onLoad, this);
13966 this.store.on('loadexception', this.onLoadException, this);
13968 if(this.resizable){
13969 this.resizer = new Roo.Resizable(this.list, {
13970 pinned:true, handles:'se'
13972 this.resizer.on('resize', function(r, w, h){
13973 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13974 this.listWidth = w;
13975 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13976 this.restrictHeight();
13978 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13981 if(!this.editable){
13982 this.editable = true;
13983 this.setEditable(false);
13988 if (typeof(this.events.add.listeners) != 'undefined') {
13990 this.addicon = this.wrap.createChild(
13991 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13993 this.addicon.on('click', function(e) {
13994 this.fireEvent('add', this);
13997 if (typeof(this.events.edit.listeners) != 'undefined') {
13999 this.editicon = this.wrap.createChild(
14000 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
14001 if (this.addicon) {
14002 this.editicon.setStyle('margin-left', '40px');
14004 this.editicon.on('click', function(e) {
14006 // we fire even if inothing is selected..
14007 this.fireEvent('edit', this, this.lastData );
14013 this.keyNav = new Roo.KeyNav(this.inputEl(), {
14014 "up" : function(e){
14015 this.inKeyMode = true;
14019 "down" : function(e){
14020 if(!this.isExpanded()){
14021 this.onTriggerClick();
14023 this.inKeyMode = true;
14028 "enter" : function(e){
14029 // this.onViewClick();
14033 if(this.fireEvent("specialkey", this, e)){
14034 this.onViewClick(false);
14040 "esc" : function(e){
14044 "tab" : function(e){
14047 if(this.fireEvent("specialkey", this, e)){
14048 this.onViewClick(false);
14056 doRelay : function(foo, bar, hname){
14057 if(hname == 'down' || this.scope.isExpanded()){
14058 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14067 this.queryDelay = Math.max(this.queryDelay || 10,
14068 this.mode == 'local' ? 10 : 250);
14071 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14073 if(this.typeAhead){
14074 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14076 if(this.editable !== false){
14077 this.inputEl().on("keyup", this.onKeyUp, this);
14079 if(this.forceSelection){
14080 this.inputEl().on('blur', this.doForce, this);
14084 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14085 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14089 initTickableEvents: function()
14093 if(this.hiddenName){
14095 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14097 this.hiddenField.dom.value =
14098 this.hiddenValue !== undefined ? this.hiddenValue :
14099 this.value !== undefined ? this.value : '';
14101 // prevent input submission
14102 this.el.dom.removeAttribute('name');
14103 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14108 // this.list = this.el.select('ul.dropdown-menu',true).first();
14110 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14111 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14112 if(this.triggerList){
14113 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14116 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14117 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14119 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14120 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14122 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14123 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14125 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14126 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14127 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14130 this.cancelBtn.hide();
14135 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14136 _this.list.setWidth(lw);
14139 this.list.on('mouseover', this.onViewOver, this);
14140 this.list.on('mousemove', this.onViewMove, this);
14142 this.list.on('scroll', this.onViewScroll, this);
14145 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14146 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14149 this.view = new Roo.View(this.list, this.tpl, {
14154 selectedClass: this.selectedClass
14157 //this.view.wrapEl.setDisplayed(false);
14158 this.view.on('click', this.onViewClick, this);
14162 this.store.on('beforeload', this.onBeforeLoad, this);
14163 this.store.on('load', this.onLoad, this);
14164 this.store.on('loadexception', this.onLoadException, this);
14167 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14168 "up" : function(e){
14169 this.inKeyMode = true;
14173 "down" : function(e){
14174 this.inKeyMode = true;
14178 "enter" : function(e){
14179 if(this.fireEvent("specialkey", this, e)){
14180 this.onViewClick(false);
14186 "esc" : function(e){
14187 this.onTickableFooterButtonClick(e, false, false);
14190 "tab" : function(e){
14191 this.fireEvent("specialkey", this, e);
14193 this.onTickableFooterButtonClick(e, false, false);
14200 doRelay : function(e, fn, key){
14201 if(this.scope.isExpanded()){
14202 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14211 this.queryDelay = Math.max(this.queryDelay || 10,
14212 this.mode == 'local' ? 10 : 250);
14215 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14217 if(this.typeAhead){
14218 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14221 if(this.editable !== false){
14222 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14225 this.indicator = this.indicatorEl();
14227 if(this.indicator){
14228 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14229 this.indicator.hide();
14234 onDestroy : function(){
14236 this.view.setStore(null);
14237 this.view.el.removeAllListeners();
14238 this.view.el.remove();
14239 this.view.purgeListeners();
14242 this.list.dom.innerHTML = '';
14246 this.store.un('beforeload', this.onBeforeLoad, this);
14247 this.store.un('load', this.onLoad, this);
14248 this.store.un('loadexception', this.onLoadException, this);
14250 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14254 fireKey : function(e){
14255 if(e.isNavKeyPress() && !this.list.isVisible()){
14256 this.fireEvent("specialkey", this, e);
14261 onResize: function(w, h){
14262 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14264 // if(typeof w != 'number'){
14265 // // we do not handle it!?!?
14268 // var tw = this.trigger.getWidth();
14269 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14270 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14272 // this.inputEl().setWidth( this.adjustWidth('input', x));
14274 // //this.trigger.setStyle('left', x+'px');
14276 // if(this.list && this.listWidth === undefined){
14277 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14278 // this.list.setWidth(lw);
14279 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14287 * Allow or prevent the user from directly editing the field text. If false is passed,
14288 * the user will only be able to select from the items defined in the dropdown list. This method
14289 * is the runtime equivalent of setting the 'editable' config option at config time.
14290 * @param {Boolean} value True to allow the user to directly edit the field text
14292 setEditable : function(value){
14293 if(value == this.editable){
14296 this.editable = value;
14298 this.inputEl().dom.setAttribute('readOnly', true);
14299 this.inputEl().on('mousedown', this.onTriggerClick, this);
14300 this.inputEl().addClass('x-combo-noedit');
14302 this.inputEl().dom.setAttribute('readOnly', false);
14303 this.inputEl().un('mousedown', this.onTriggerClick, this);
14304 this.inputEl().removeClass('x-combo-noedit');
14310 onBeforeLoad : function(combo,opts){
14311 if(!this.hasFocus){
14315 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14317 this.restrictHeight();
14318 this.selectedIndex = -1;
14322 onLoad : function(){
14324 this.hasQuery = false;
14326 if(!this.hasFocus){
14330 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14331 this.loading.hide();
14334 if(this.store.getCount() > 0){
14337 this.restrictHeight();
14338 if(this.lastQuery == this.allQuery){
14339 if(this.editable && !this.tickable){
14340 this.inputEl().dom.select();
14344 !this.selectByValue(this.value, true) &&
14347 !this.store.lastOptions ||
14348 typeof(this.store.lastOptions.add) == 'undefined' ||
14349 this.store.lastOptions.add != true
14352 this.select(0, true);
14355 if(this.autoFocus){
14358 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14359 this.taTask.delay(this.typeAheadDelay);
14363 this.onEmptyResults();
14369 onLoadException : function()
14371 this.hasQuery = false;
14373 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14374 this.loading.hide();
14377 if(this.tickable && this.editable){
14382 // only causes errors at present
14383 //Roo.log(this.store.reader.jsonData);
14384 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14386 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14392 onTypeAhead : function(){
14393 if(this.store.getCount() > 0){
14394 var r = this.store.getAt(0);
14395 var newValue = r.data[this.displayField];
14396 var len = newValue.length;
14397 var selStart = this.getRawValue().length;
14399 if(selStart != len){
14400 this.setRawValue(newValue);
14401 this.selectText(selStart, newValue.length);
14407 onSelect : function(record, index){
14409 if(this.fireEvent('beforeselect', this, record, index) !== false){
14411 this.setFromData(index > -1 ? record.data : false);
14414 this.fireEvent('select', this, record, index);
14419 * Returns the currently selected field value or empty string if no value is set.
14420 * @return {String} value The selected value
14422 getValue : function()
14424 if(Roo.isIOS && this.useNativeIOS){
14425 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14429 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14432 if(this.valueField){
14433 return typeof this.value != 'undefined' ? this.value : '';
14435 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14439 getRawValue : function()
14441 if(Roo.isIOS && this.useNativeIOS){
14442 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14445 var v = this.inputEl().getValue();
14451 * Clears any text/value currently set in the field
14453 clearValue : function(){
14455 if(this.hiddenField){
14456 this.hiddenField.dom.value = '';
14459 this.setRawValue('');
14460 this.lastSelectionText = '';
14461 this.lastData = false;
14463 var close = this.closeTriggerEl();
14474 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14475 * will be displayed in the field. If the value does not match the data value of an existing item,
14476 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14477 * Otherwise the field will be blank (although the value will still be set).
14478 * @param {String} value The value to match
14480 setValue : function(v)
14482 if(Roo.isIOS && this.useNativeIOS){
14483 this.setIOSValue(v);
14493 if(this.valueField){
14494 var r = this.findRecord(this.valueField, v);
14496 text = r.data[this.displayField];
14497 }else if(this.valueNotFoundText !== undefined){
14498 text = this.valueNotFoundText;
14501 this.lastSelectionText = text;
14502 if(this.hiddenField){
14503 this.hiddenField.dom.value = v;
14505 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14508 var close = this.closeTriggerEl();
14511 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14517 * @property {Object} the last set data for the element
14522 * Sets the value of the field based on a object which is related to the record format for the store.
14523 * @param {Object} value the value to set as. or false on reset?
14525 setFromData : function(o){
14532 var dv = ''; // display value
14533 var vv = ''; // value value..
14535 if (this.displayField) {
14536 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14538 // this is an error condition!!!
14539 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14542 if(this.valueField){
14543 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14546 var close = this.closeTriggerEl();
14549 if(dv.length || vv * 1 > 0){
14551 this.blockFocus=true;
14557 if(this.hiddenField){
14558 this.hiddenField.dom.value = vv;
14560 this.lastSelectionText = dv;
14561 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14565 // no hidden field.. - we store the value in 'value', but still display
14566 // display field!!!!
14567 this.lastSelectionText = dv;
14568 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14575 reset : function(){
14576 // overridden so that last data is reset..
14583 this.setValue(this.originalValue);
14584 //this.clearInvalid();
14585 this.lastData = false;
14587 this.view.clearSelections();
14593 findRecord : function(prop, value){
14595 if(this.store.getCount() > 0){
14596 this.store.each(function(r){
14597 if(r.data[prop] == value){
14607 getName: function()
14609 // returns hidden if it's set..
14610 if (!this.rendered) {return ''};
14611 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14615 onViewMove : function(e, t){
14616 this.inKeyMode = false;
14620 onViewOver : function(e, t){
14621 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14624 var item = this.view.findItemFromChild(t);
14627 var index = this.view.indexOf(item);
14628 this.select(index, false);
14633 onViewClick : function(view, doFocus, el, e)
14635 var index = this.view.getSelectedIndexes()[0];
14637 var r = this.store.getAt(index);
14641 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14648 Roo.each(this.tickItems, function(v,k){
14650 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14652 _this.tickItems.splice(k, 1);
14654 if(typeof(e) == 'undefined' && view == false){
14655 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14667 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14668 this.tickItems.push(r.data);
14671 if(typeof(e) == 'undefined' && view == false){
14672 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14679 this.onSelect(r, index);
14681 if(doFocus !== false && !this.blockFocus){
14682 this.inputEl().focus();
14687 restrictHeight : function(){
14688 //this.innerList.dom.style.height = '';
14689 //var inner = this.innerList.dom;
14690 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14691 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14692 //this.list.beginUpdate();
14693 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14694 this.list.alignTo(this.inputEl(), this.listAlign);
14695 this.list.alignTo(this.inputEl(), this.listAlign);
14696 //this.list.endUpdate();
14700 onEmptyResults : function(){
14702 if(this.tickable && this.editable){
14703 this.hasFocus = false;
14704 this.restrictHeight();
14712 * Returns true if the dropdown list is expanded, else false.
14714 isExpanded : function(){
14715 return this.list.isVisible();
14719 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14720 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14721 * @param {String} value The data value of the item to select
14722 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14723 * selected item if it is not currently in view (defaults to true)
14724 * @return {Boolean} True if the value matched an item in the list, else false
14726 selectByValue : function(v, scrollIntoView){
14727 if(v !== undefined && v !== null){
14728 var r = this.findRecord(this.valueField || this.displayField, v);
14730 this.select(this.store.indexOf(r), scrollIntoView);
14738 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14739 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14740 * @param {Number} index The zero-based index of the list item to select
14741 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14742 * selected item if it is not currently in view (defaults to true)
14744 select : function(index, scrollIntoView){
14745 this.selectedIndex = index;
14746 this.view.select(index);
14747 if(scrollIntoView !== false){
14748 var el = this.view.getNode(index);
14750 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14753 this.list.scrollChildIntoView(el, false);
14759 selectNext : function(){
14760 var ct = this.store.getCount();
14762 if(this.selectedIndex == -1){
14764 }else if(this.selectedIndex < ct-1){
14765 this.select(this.selectedIndex+1);
14771 selectPrev : function(){
14772 var ct = this.store.getCount();
14774 if(this.selectedIndex == -1){
14776 }else if(this.selectedIndex != 0){
14777 this.select(this.selectedIndex-1);
14783 onKeyUp : function(e){
14784 if(this.editable !== false && !e.isSpecialKey()){
14785 this.lastKey = e.getKey();
14786 this.dqTask.delay(this.queryDelay);
14791 validateBlur : function(){
14792 return !this.list || !this.list.isVisible();
14796 initQuery : function(){
14798 var v = this.getRawValue();
14800 if(this.tickable && this.editable){
14801 v = this.tickableInputEl().getValue();
14808 doForce : function(){
14809 if(this.inputEl().dom.value.length > 0){
14810 this.inputEl().dom.value =
14811 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14817 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14818 * query allowing the query action to be canceled if needed.
14819 * @param {String} query The SQL query to execute
14820 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14821 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14822 * saved in the current store (defaults to false)
14824 doQuery : function(q, forceAll){
14826 if(q === undefined || q === null){
14831 forceAll: forceAll,
14835 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14840 forceAll = qe.forceAll;
14841 if(forceAll === true || (q.length >= this.minChars)){
14843 this.hasQuery = true;
14845 if(this.lastQuery != q || this.alwaysQuery){
14846 this.lastQuery = q;
14847 if(this.mode == 'local'){
14848 this.selectedIndex = -1;
14850 this.store.clearFilter();
14853 if(this.specialFilter){
14854 this.fireEvent('specialfilter', this);
14859 this.store.filter(this.displayField, q);
14862 this.store.fireEvent("datachanged", this.store);
14869 this.store.baseParams[this.queryParam] = q;
14871 var options = {params : this.getParams(q)};
14874 options.add = true;
14875 options.params.start = this.page * this.pageSize;
14878 this.store.load(options);
14881 * this code will make the page width larger, at the beginning, the list not align correctly,
14882 * we should expand the list on onLoad
14883 * so command out it
14888 this.selectedIndex = -1;
14893 this.loadNext = false;
14897 getParams : function(q){
14899 //p[this.queryParam] = q;
14903 p.limit = this.pageSize;
14909 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14911 collapse : function(){
14912 if(!this.isExpanded()){
14918 this.hasFocus = false;
14922 this.cancelBtn.hide();
14923 this.trigger.show();
14926 this.tickableInputEl().dom.value = '';
14927 this.tickableInputEl().blur();
14932 Roo.get(document).un('mousedown', this.collapseIf, this);
14933 Roo.get(document).un('mousewheel', this.collapseIf, this);
14934 if (!this.editable) {
14935 Roo.get(document).un('keydown', this.listKeyPress, this);
14937 this.fireEvent('collapse', this);
14943 collapseIf : function(e){
14944 var in_combo = e.within(this.el);
14945 var in_list = e.within(this.list);
14946 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14948 if (in_combo || in_list || is_list) {
14949 //e.stopPropagation();
14954 this.onTickableFooterButtonClick(e, false, false);
14962 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14964 expand : function(){
14966 if(this.isExpanded() || !this.hasFocus){
14970 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14971 this.list.setWidth(lw);
14977 this.restrictHeight();
14981 this.tickItems = Roo.apply([], this.item);
14984 this.cancelBtn.show();
14985 this.trigger.hide();
14988 this.tickableInputEl().focus();
14993 Roo.get(document).on('mousedown', this.collapseIf, this);
14994 Roo.get(document).on('mousewheel', this.collapseIf, this);
14995 if (!this.editable) {
14996 Roo.get(document).on('keydown', this.listKeyPress, this);
14999 this.fireEvent('expand', this);
15003 // Implements the default empty TriggerField.onTriggerClick function
15004 onTriggerClick : function(e)
15006 Roo.log('trigger click');
15008 if(this.disabled || !this.triggerList){
15013 this.loadNext = false;
15015 if(this.isExpanded()){
15017 if (!this.blockFocus) {
15018 this.inputEl().focus();
15022 this.hasFocus = true;
15023 if(this.triggerAction == 'all') {
15024 this.doQuery(this.allQuery, true);
15026 this.doQuery(this.getRawValue());
15028 if (!this.blockFocus) {
15029 this.inputEl().focus();
15034 onTickableTriggerClick : function(e)
15041 this.loadNext = false;
15042 this.hasFocus = true;
15044 if(this.triggerAction == 'all') {
15045 this.doQuery(this.allQuery, true);
15047 this.doQuery(this.getRawValue());
15051 onSearchFieldClick : function(e)
15053 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15054 this.onTickableFooterButtonClick(e, false, false);
15058 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15063 this.loadNext = false;
15064 this.hasFocus = true;
15066 if(this.triggerAction == 'all') {
15067 this.doQuery(this.allQuery, true);
15069 this.doQuery(this.getRawValue());
15073 listKeyPress : function(e)
15075 //Roo.log('listkeypress');
15076 // scroll to first matching element based on key pres..
15077 if (e.isSpecialKey()) {
15080 var k = String.fromCharCode(e.getKey()).toUpperCase();
15083 var csel = this.view.getSelectedNodes();
15084 var cselitem = false;
15086 var ix = this.view.indexOf(csel[0]);
15087 cselitem = this.store.getAt(ix);
15088 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15094 this.store.each(function(v) {
15096 // start at existing selection.
15097 if (cselitem.id == v.id) {
15103 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15104 match = this.store.indexOf(v);
15110 if (match === false) {
15111 return true; // no more action?
15114 this.view.select(match);
15115 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15116 sn.scrollIntoView(sn.dom.parentNode, false);
15119 onViewScroll : function(e, t){
15121 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){
15125 this.hasQuery = true;
15127 this.loading = this.list.select('.loading', true).first();
15129 if(this.loading === null){
15130 this.list.createChild({
15132 cls: 'loading roo-select2-more-results roo-select2-active',
15133 html: 'Loading more results...'
15136 this.loading = this.list.select('.loading', true).first();
15138 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15140 this.loading.hide();
15143 this.loading.show();
15148 this.loadNext = true;
15150 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15155 addItem : function(o)
15157 var dv = ''; // display value
15159 if (this.displayField) {
15160 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15162 // this is an error condition!!!
15163 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15170 var choice = this.choices.createChild({
15172 cls: 'roo-select2-search-choice',
15181 cls: 'roo-select2-search-choice-close fa fa-times',
15186 }, this.searchField);
15188 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15190 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15198 this.inputEl().dom.value = '';
15203 onRemoveItem : function(e, _self, o)
15205 e.preventDefault();
15207 this.lastItem = Roo.apply([], this.item);
15209 var index = this.item.indexOf(o.data) * 1;
15212 Roo.log('not this item?!');
15216 this.item.splice(index, 1);
15221 this.fireEvent('remove', this, e);
15227 syncValue : function()
15229 if(!this.item.length){
15236 Roo.each(this.item, function(i){
15237 if(_this.valueField){
15238 value.push(i[_this.valueField]);
15245 this.value = value.join(',');
15247 if(this.hiddenField){
15248 this.hiddenField.dom.value = this.value;
15251 this.store.fireEvent("datachanged", this.store);
15256 clearItem : function()
15258 if(!this.multiple){
15264 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15272 if(this.tickable && !Roo.isTouch){
15273 this.view.refresh();
15277 inputEl: function ()
15279 if(Roo.isIOS && this.useNativeIOS){
15280 return this.el.select('select.roo-ios-select', true).first();
15283 if(Roo.isTouch && this.mobileTouchView){
15284 return this.el.select('input.form-control',true).first();
15288 return this.searchField;
15291 return this.el.select('input.form-control',true).first();
15294 onTickableFooterButtonClick : function(e, btn, el)
15296 e.preventDefault();
15298 this.lastItem = Roo.apply([], this.item);
15300 if(btn && btn.name == 'cancel'){
15301 this.tickItems = Roo.apply([], this.item);
15310 Roo.each(this.tickItems, function(o){
15318 validate : function()
15320 if(this.getVisibilityEl().hasClass('hidden')){
15324 var v = this.getRawValue();
15327 v = this.getValue();
15330 if(this.disabled || this.allowBlank || v.length){
15335 this.markInvalid();
15339 tickableInputEl : function()
15341 if(!this.tickable || !this.editable){
15342 return this.inputEl();
15345 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15349 getAutoCreateTouchView : function()
15354 cls: 'form-group' //input-group
15360 type : this.inputType,
15361 cls : 'form-control x-combo-noedit',
15362 autocomplete: 'new-password',
15363 placeholder : this.placeholder || '',
15368 input.name = this.name;
15372 input.cls += ' input-' + this.size;
15375 if (this.disabled) {
15376 input.disabled = true;
15387 inputblock.cls += ' input-group';
15389 inputblock.cn.unshift({
15391 cls : 'input-group-addon input-group-prepend input-group-text',
15396 if(this.removable && !this.multiple){
15397 inputblock.cls += ' roo-removable';
15399 inputblock.cn.push({
15402 cls : 'roo-combo-removable-btn close'
15406 if(this.hasFeedback && !this.allowBlank){
15408 inputblock.cls += ' has-feedback';
15410 inputblock.cn.push({
15412 cls: 'glyphicon form-control-feedback'
15419 inputblock.cls += (this.before) ? '' : ' input-group';
15421 inputblock.cn.push({
15423 cls : 'input-group-addon input-group-append input-group-text',
15429 var ibwrap = inputblock;
15434 cls: 'roo-select2-choices',
15438 cls: 'roo-select2-search-field',
15451 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15456 cls: 'form-hidden-field'
15462 if(!this.multiple && this.showToggleBtn){
15468 if (this.caret != false) {
15471 cls: 'fa fa-' + this.caret
15478 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15480 Roo.bootstrap.version == 3 ? caret : '',
15483 cls: 'combobox-clear',
15497 combobox.cls += ' roo-select2-container-multi';
15500 var align = this.labelAlign || this.parentLabelAlign();
15502 if (align ==='left' && this.fieldLabel.length) {
15507 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15508 tooltip : 'This field is required'
15512 cls : 'control-label col-form-label',
15513 html : this.fieldLabel
15524 var labelCfg = cfg.cn[1];
15525 var contentCfg = cfg.cn[2];
15528 if(this.indicatorpos == 'right'){
15533 cls : 'control-label col-form-label',
15537 html : this.fieldLabel
15541 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15542 tooltip : 'This field is required'
15555 labelCfg = cfg.cn[0];
15556 contentCfg = cfg.cn[1];
15561 if(this.labelWidth > 12){
15562 labelCfg.style = "width: " + this.labelWidth + 'px';
15565 if(this.labelWidth < 13 && this.labelmd == 0){
15566 this.labelmd = this.labelWidth;
15569 if(this.labellg > 0){
15570 labelCfg.cls += ' col-lg-' + this.labellg;
15571 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15574 if(this.labelmd > 0){
15575 labelCfg.cls += ' col-md-' + this.labelmd;
15576 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15579 if(this.labelsm > 0){
15580 labelCfg.cls += ' col-sm-' + this.labelsm;
15581 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15584 if(this.labelxs > 0){
15585 labelCfg.cls += ' col-xs-' + this.labelxs;
15586 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15590 } else if ( this.fieldLabel.length) {
15594 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15595 tooltip : 'This field is required'
15599 cls : 'control-label',
15600 html : this.fieldLabel
15611 if(this.indicatorpos == 'right'){
15615 cls : 'control-label',
15616 html : this.fieldLabel,
15620 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15621 tooltip : 'This field is required'
15638 var settings = this;
15640 ['xs','sm','md','lg'].map(function(size){
15641 if (settings[size]) {
15642 cfg.cls += ' col-' + size + '-' + settings[size];
15649 initTouchView : function()
15651 this.renderTouchView();
15653 this.touchViewEl.on('scroll', function(){
15654 this.el.dom.scrollTop = 0;
15657 this.originalValue = this.getValue();
15659 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15661 this.inputEl().on("click", this.showTouchView, this);
15662 if (this.triggerEl) {
15663 this.triggerEl.on("click", this.showTouchView, this);
15667 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15668 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15670 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15672 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15673 this.store.on('load', this.onTouchViewLoad, this);
15674 this.store.on('loadexception', this.onTouchViewLoadException, this);
15676 if(this.hiddenName){
15678 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15680 this.hiddenField.dom.value =
15681 this.hiddenValue !== undefined ? this.hiddenValue :
15682 this.value !== undefined ? this.value : '';
15684 this.el.dom.removeAttribute('name');
15685 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15689 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15690 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15693 if(this.removable && !this.multiple){
15694 var close = this.closeTriggerEl();
15696 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15697 close.on('click', this.removeBtnClick, this, close);
15701 * fix the bug in Safari iOS8
15703 this.inputEl().on("focus", function(e){
15704 document.activeElement.blur();
15707 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15714 renderTouchView : function()
15716 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15717 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15719 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15720 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15722 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15723 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15724 this.touchViewBodyEl.setStyle('overflow', 'auto');
15726 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15727 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15729 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15730 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15734 showTouchView : function()
15740 this.touchViewHeaderEl.hide();
15742 if(this.modalTitle.length){
15743 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15744 this.touchViewHeaderEl.show();
15747 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15748 this.touchViewEl.show();
15750 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15752 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15753 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15755 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15757 if(this.modalTitle.length){
15758 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15761 this.touchViewBodyEl.setHeight(bodyHeight);
15765 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15767 this.touchViewEl.addClass('in');
15770 if(this._touchViewMask){
15771 Roo.get(document.body).addClass("x-body-masked");
15772 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15773 this._touchViewMask.setStyle('z-index', 10000);
15774 this._touchViewMask.addClass('show');
15777 this.doTouchViewQuery();
15781 hideTouchView : function()
15783 this.touchViewEl.removeClass('in');
15787 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15789 this.touchViewEl.setStyle('display', 'none');
15792 if(this._touchViewMask){
15793 this._touchViewMask.removeClass('show');
15794 Roo.get(document.body).removeClass("x-body-masked");
15798 setTouchViewValue : function()
15805 Roo.each(this.tickItems, function(o){
15810 this.hideTouchView();
15813 doTouchViewQuery : function()
15822 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15826 if(!this.alwaysQuery || this.mode == 'local'){
15827 this.onTouchViewLoad();
15834 onTouchViewBeforeLoad : function(combo,opts)
15840 onTouchViewLoad : function()
15842 if(this.store.getCount() < 1){
15843 this.onTouchViewEmptyResults();
15847 this.clearTouchView();
15849 var rawValue = this.getRawValue();
15851 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15853 this.tickItems = [];
15855 this.store.data.each(function(d, rowIndex){
15856 var row = this.touchViewListGroup.createChild(template);
15858 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15859 row.addClass(d.data.cls);
15862 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15865 html : d.data[this.displayField]
15868 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15869 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15872 row.removeClass('selected');
15873 if(!this.multiple && this.valueField &&
15874 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15877 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15878 row.addClass('selected');
15881 if(this.multiple && this.valueField &&
15882 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15886 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15887 this.tickItems.push(d.data);
15890 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15894 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15896 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15898 if(this.modalTitle.length){
15899 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15902 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15904 if(this.mobile_restrict_height && listHeight < bodyHeight){
15905 this.touchViewBodyEl.setHeight(listHeight);
15910 if(firstChecked && listHeight > bodyHeight){
15911 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15916 onTouchViewLoadException : function()
15918 this.hideTouchView();
15921 onTouchViewEmptyResults : function()
15923 this.clearTouchView();
15925 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15927 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15931 clearTouchView : function()
15933 this.touchViewListGroup.dom.innerHTML = '';
15936 onTouchViewClick : function(e, el, o)
15938 e.preventDefault();
15941 var rowIndex = o.rowIndex;
15943 var r = this.store.getAt(rowIndex);
15945 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15947 if(!this.multiple){
15948 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15949 c.dom.removeAttribute('checked');
15952 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15954 this.setFromData(r.data);
15956 var close = this.closeTriggerEl();
15962 this.hideTouchView();
15964 this.fireEvent('select', this, r, rowIndex);
15969 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15970 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15971 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15975 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15976 this.addItem(r.data);
15977 this.tickItems.push(r.data);
15981 getAutoCreateNativeIOS : function()
15984 cls: 'form-group' //input-group,
15989 cls : 'roo-ios-select'
15993 combobox.name = this.name;
15996 if (this.disabled) {
15997 combobox.disabled = true;
16000 var settings = this;
16002 ['xs','sm','md','lg'].map(function(size){
16003 if (settings[size]) {
16004 cfg.cls += ' col-' + size + '-' + settings[size];
16014 initIOSView : function()
16016 this.store.on('load', this.onIOSViewLoad, this);
16021 onIOSViewLoad : function()
16023 if(this.store.getCount() < 1){
16027 this.clearIOSView();
16029 if(this.allowBlank) {
16031 var default_text = '-- SELECT --';
16033 if(this.placeholder.length){
16034 default_text = this.placeholder;
16037 if(this.emptyTitle.length){
16038 default_text += ' - ' + this.emptyTitle + ' -';
16041 var opt = this.inputEl().createChild({
16044 html : default_text
16048 o[this.valueField] = 0;
16049 o[this.displayField] = default_text;
16051 this.ios_options.push({
16058 this.store.data.each(function(d, rowIndex){
16062 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16063 html = d.data[this.displayField];
16068 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16069 value = d.data[this.valueField];
16078 if(this.value == d.data[this.valueField]){
16079 option['selected'] = true;
16082 var opt = this.inputEl().createChild(option);
16084 this.ios_options.push({
16091 this.inputEl().on('change', function(){
16092 this.fireEvent('select', this);
16097 clearIOSView: function()
16099 this.inputEl().dom.innerHTML = '';
16101 this.ios_options = [];
16104 setIOSValue: function(v)
16108 if(!this.ios_options){
16112 Roo.each(this.ios_options, function(opts){
16114 opts.el.dom.removeAttribute('selected');
16116 if(opts.data[this.valueField] != v){
16120 opts.el.dom.setAttribute('selected', true);
16126 * @cfg {Boolean} grow
16130 * @cfg {Number} growMin
16134 * @cfg {Number} growMax
16143 Roo.apply(Roo.bootstrap.ComboBox, {
16147 cls: 'modal-header',
16169 cls: 'list-group-item',
16173 cls: 'roo-combobox-list-group-item-value'
16177 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16191 listItemCheckbox : {
16193 cls: 'list-group-item',
16197 cls: 'roo-combobox-list-group-item-value'
16201 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16217 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16222 cls: 'modal-footer',
16230 cls: 'col-xs-6 text-left',
16233 cls: 'btn btn-danger roo-touch-view-cancel',
16239 cls: 'col-xs-6 text-right',
16242 cls: 'btn btn-success roo-touch-view-ok',
16253 Roo.apply(Roo.bootstrap.ComboBox, {
16255 touchViewTemplate : {
16257 cls: 'modal fade roo-combobox-touch-view',
16261 cls: 'modal-dialog',
16262 style : 'position:fixed', // we have to fix position....
16266 cls: 'modal-content',
16268 Roo.bootstrap.ComboBox.header,
16269 Roo.bootstrap.ComboBox.body,
16270 Roo.bootstrap.ComboBox.footer
16279 * Ext JS Library 1.1.1
16280 * Copyright(c) 2006-2007, Ext JS, LLC.
16282 * Originally Released Under LGPL - original licence link has changed is not relivant.
16285 * <script type="text/javascript">
16290 * @extends Roo.util.Observable
16291 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16292 * This class also supports single and multi selection modes. <br>
16293 * Create a data model bound view:
16295 var store = new Roo.data.Store(...);
16297 var view = new Roo.View({
16299 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16301 singleSelect: true,
16302 selectedClass: "ydataview-selected",
16306 // listen for node click?
16307 view.on("click", function(vw, index, node, e){
16308 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16312 dataModel.load("foobar.xml");
16314 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16316 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16317 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16319 * Note: old style constructor is still suported (container, template, config)
16322 * Create a new View
16323 * @param {Object} config The config object
16326 Roo.View = function(config, depreciated_tpl, depreciated_config){
16328 this.parent = false;
16330 if (typeof(depreciated_tpl) == 'undefined') {
16331 // new way.. - universal constructor.
16332 Roo.apply(this, config);
16333 this.el = Roo.get(this.el);
16336 this.el = Roo.get(config);
16337 this.tpl = depreciated_tpl;
16338 Roo.apply(this, depreciated_config);
16340 this.wrapEl = this.el.wrap().wrap();
16341 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16344 if(typeof(this.tpl) == "string"){
16345 this.tpl = new Roo.Template(this.tpl);
16347 // support xtype ctors..
16348 this.tpl = new Roo.factory(this.tpl, Roo);
16352 this.tpl.compile();
16357 * @event beforeclick
16358 * Fires before a click is processed. Returns false to cancel the default action.
16359 * @param {Roo.View} this
16360 * @param {Number} index The index of the target node
16361 * @param {HTMLElement} node The target node
16362 * @param {Roo.EventObject} e The raw event object
16364 "beforeclick" : true,
16367 * Fires when a template node is clicked.
16368 * @param {Roo.View} this
16369 * @param {Number} index The index of the target node
16370 * @param {HTMLElement} node The target node
16371 * @param {Roo.EventObject} e The raw event object
16376 * Fires when a template node is double clicked.
16377 * @param {Roo.View} this
16378 * @param {Number} index The index of the target node
16379 * @param {HTMLElement} node The target node
16380 * @param {Roo.EventObject} e The raw event object
16384 * @event contextmenu
16385 * Fires when a template node is right clicked.
16386 * @param {Roo.View} this
16387 * @param {Number} index The index of the target node
16388 * @param {HTMLElement} node The target node
16389 * @param {Roo.EventObject} e The raw event object
16391 "contextmenu" : true,
16393 * @event selectionchange
16394 * Fires when the selected nodes change.
16395 * @param {Roo.View} this
16396 * @param {Array} selections Array of the selected nodes
16398 "selectionchange" : true,
16401 * @event beforeselect
16402 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16403 * @param {Roo.View} this
16404 * @param {HTMLElement} node The node to be selected
16405 * @param {Array} selections Array of currently selected nodes
16407 "beforeselect" : true,
16409 * @event preparedata
16410 * Fires on every row to render, to allow you to change the data.
16411 * @param {Roo.View} this
16412 * @param {Object} data to be rendered (change this)
16414 "preparedata" : true
16422 "click": this.onClick,
16423 "dblclick": this.onDblClick,
16424 "contextmenu": this.onContextMenu,
16428 this.selections = [];
16430 this.cmp = new Roo.CompositeElementLite([]);
16432 this.store = Roo.factory(this.store, Roo.data);
16433 this.setStore(this.store, true);
16436 if ( this.footer && this.footer.xtype) {
16438 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16440 this.footer.dataSource = this.store;
16441 this.footer.container = fctr;
16442 this.footer = Roo.factory(this.footer, Roo);
16443 fctr.insertFirst(this.el);
16445 // this is a bit insane - as the paging toolbar seems to detach the el..
16446 // dom.parentNode.parentNode.parentNode
16447 // they get detached?
16451 Roo.View.superclass.constructor.call(this);
16456 Roo.extend(Roo.View, Roo.util.Observable, {
16459 * @cfg {Roo.data.Store} store Data store to load data from.
16464 * @cfg {String|Roo.Element} el The container element.
16469 * @cfg {String|Roo.Template} tpl The template used by this View
16473 * @cfg {String} dataName the named area of the template to use as the data area
16474 * Works with domtemplates roo-name="name"
16478 * @cfg {String} selectedClass The css class to add to selected nodes
16480 selectedClass : "x-view-selected",
16482 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16487 * @cfg {String} text to display on mask (default Loading)
16491 * @cfg {Boolean} multiSelect Allow multiple selection
16493 multiSelect : false,
16495 * @cfg {Boolean} singleSelect Allow single selection
16497 singleSelect: false,
16500 * @cfg {Boolean} toggleSelect - selecting
16502 toggleSelect : false,
16505 * @cfg {Boolean} tickable - selecting
16510 * Returns the element this view is bound to.
16511 * @return {Roo.Element}
16513 getEl : function(){
16514 return this.wrapEl;
16520 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16522 refresh : function(){
16523 //Roo.log('refresh');
16526 // if we are using something like 'domtemplate', then
16527 // the what gets used is:
16528 // t.applySubtemplate(NAME, data, wrapping data..)
16529 // the outer template then get' applied with
16530 // the store 'extra data'
16531 // and the body get's added to the
16532 // roo-name="data" node?
16533 // <span class='roo-tpl-{name}'></span> ?????
16537 this.clearSelections();
16538 this.el.update("");
16540 var records = this.store.getRange();
16541 if(records.length < 1) {
16543 // is this valid?? = should it render a template??
16545 this.el.update(this.emptyText);
16549 if (this.dataName) {
16550 this.el.update(t.apply(this.store.meta)); //????
16551 el = this.el.child('.roo-tpl-' + this.dataName);
16554 for(var i = 0, len = records.length; i < len; i++){
16555 var data = this.prepareData(records[i].data, i, records[i]);
16556 this.fireEvent("preparedata", this, data, i, records[i]);
16558 var d = Roo.apply({}, data);
16561 Roo.apply(d, {'roo-id' : Roo.id()});
16565 Roo.each(this.parent.item, function(item){
16566 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16569 Roo.apply(d, {'roo-data-checked' : 'checked'});
16573 html[html.length] = Roo.util.Format.trim(
16575 t.applySubtemplate(this.dataName, d, this.store.meta) :
16582 el.update(html.join(""));
16583 this.nodes = el.dom.childNodes;
16584 this.updateIndexes(0);
16589 * Function to override to reformat the data that is sent to
16590 * the template for each node.
16591 * DEPRICATED - use the preparedata event handler.
16592 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16593 * a JSON object for an UpdateManager bound view).
16595 prepareData : function(data, index, record)
16597 this.fireEvent("preparedata", this, data, index, record);
16601 onUpdate : function(ds, record){
16602 // Roo.log('on update');
16603 this.clearSelections();
16604 var index = this.store.indexOf(record);
16605 var n = this.nodes[index];
16606 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16607 n.parentNode.removeChild(n);
16608 this.updateIndexes(index, index);
16614 onAdd : function(ds, records, index)
16616 //Roo.log(['on Add', ds, records, index] );
16617 this.clearSelections();
16618 if(this.nodes.length == 0){
16622 var n = this.nodes[index];
16623 for(var i = 0, len = records.length; i < len; i++){
16624 var d = this.prepareData(records[i].data, i, records[i]);
16626 this.tpl.insertBefore(n, d);
16629 this.tpl.append(this.el, d);
16632 this.updateIndexes(index);
16635 onRemove : function(ds, record, index){
16636 // Roo.log('onRemove');
16637 this.clearSelections();
16638 var el = this.dataName ?
16639 this.el.child('.roo-tpl-' + this.dataName) :
16642 el.dom.removeChild(this.nodes[index]);
16643 this.updateIndexes(index);
16647 * Refresh an individual node.
16648 * @param {Number} index
16650 refreshNode : function(index){
16651 this.onUpdate(this.store, this.store.getAt(index));
16654 updateIndexes : function(startIndex, endIndex){
16655 var ns = this.nodes;
16656 startIndex = startIndex || 0;
16657 endIndex = endIndex || ns.length - 1;
16658 for(var i = startIndex; i <= endIndex; i++){
16659 ns[i].nodeIndex = i;
16664 * Changes the data store this view uses and refresh the view.
16665 * @param {Store} store
16667 setStore : function(store, initial){
16668 if(!initial && this.store){
16669 this.store.un("datachanged", this.refresh);
16670 this.store.un("add", this.onAdd);
16671 this.store.un("remove", this.onRemove);
16672 this.store.un("update", this.onUpdate);
16673 this.store.un("clear", this.refresh);
16674 this.store.un("beforeload", this.onBeforeLoad);
16675 this.store.un("load", this.onLoad);
16676 this.store.un("loadexception", this.onLoad);
16680 store.on("datachanged", this.refresh, this);
16681 store.on("add", this.onAdd, this);
16682 store.on("remove", this.onRemove, this);
16683 store.on("update", this.onUpdate, this);
16684 store.on("clear", this.refresh, this);
16685 store.on("beforeload", this.onBeforeLoad, this);
16686 store.on("load", this.onLoad, this);
16687 store.on("loadexception", this.onLoad, this);
16695 * onbeforeLoad - masks the loading area.
16698 onBeforeLoad : function(store,opts)
16700 //Roo.log('onBeforeLoad');
16702 this.el.update("");
16704 this.el.mask(this.mask ? this.mask : "Loading" );
16706 onLoad : function ()
16713 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16714 * @param {HTMLElement} node
16715 * @return {HTMLElement} The template node
16717 findItemFromChild : function(node){
16718 var el = this.dataName ?
16719 this.el.child('.roo-tpl-' + this.dataName,true) :
16722 if(!node || node.parentNode == el){
16725 var p = node.parentNode;
16726 while(p && p != el){
16727 if(p.parentNode == el){
16736 onClick : function(e){
16737 var item = this.findItemFromChild(e.getTarget());
16739 var index = this.indexOf(item);
16740 if(this.onItemClick(item, index, e) !== false){
16741 this.fireEvent("click", this, index, item, e);
16744 this.clearSelections();
16749 onContextMenu : function(e){
16750 var item = this.findItemFromChild(e.getTarget());
16752 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16757 onDblClick : function(e){
16758 var item = this.findItemFromChild(e.getTarget());
16760 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16764 onItemClick : function(item, index, e)
16766 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16769 if (this.toggleSelect) {
16770 var m = this.isSelected(item) ? 'unselect' : 'select';
16773 _t[m](item, true, false);
16776 if(this.multiSelect || this.singleSelect){
16777 if(this.multiSelect && e.shiftKey && this.lastSelection){
16778 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16780 this.select(item, this.multiSelect && e.ctrlKey);
16781 this.lastSelection = item;
16784 if(!this.tickable){
16785 e.preventDefault();
16793 * Get the number of selected nodes.
16796 getSelectionCount : function(){
16797 return this.selections.length;
16801 * Get the currently selected nodes.
16802 * @return {Array} An array of HTMLElements
16804 getSelectedNodes : function(){
16805 return this.selections;
16809 * Get the indexes of the selected nodes.
16812 getSelectedIndexes : function(){
16813 var indexes = [], s = this.selections;
16814 for(var i = 0, len = s.length; i < len; i++){
16815 indexes.push(s[i].nodeIndex);
16821 * Clear all selections
16822 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16824 clearSelections : function(suppressEvent){
16825 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16826 this.cmp.elements = this.selections;
16827 this.cmp.removeClass(this.selectedClass);
16828 this.selections = [];
16829 if(!suppressEvent){
16830 this.fireEvent("selectionchange", this, this.selections);
16836 * Returns true if the passed node is selected
16837 * @param {HTMLElement/Number} node The node or node index
16838 * @return {Boolean}
16840 isSelected : function(node){
16841 var s = this.selections;
16845 node = this.getNode(node);
16846 return s.indexOf(node) !== -1;
16851 * @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
16852 * @param {Boolean} keepExisting (optional) true to keep existing selections
16853 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16855 select : function(nodeInfo, keepExisting, suppressEvent){
16856 if(nodeInfo instanceof Array){
16858 this.clearSelections(true);
16860 for(var i = 0, len = nodeInfo.length; i < len; i++){
16861 this.select(nodeInfo[i], true, true);
16865 var node = this.getNode(nodeInfo);
16866 if(!node || this.isSelected(node)){
16867 return; // already selected.
16870 this.clearSelections(true);
16873 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16874 Roo.fly(node).addClass(this.selectedClass);
16875 this.selections.push(node);
16876 if(!suppressEvent){
16877 this.fireEvent("selectionchange", this, this.selections);
16885 * @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
16886 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16887 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16889 unselect : function(nodeInfo, keepExisting, suppressEvent)
16891 if(nodeInfo instanceof Array){
16892 Roo.each(this.selections, function(s) {
16893 this.unselect(s, nodeInfo);
16897 var node = this.getNode(nodeInfo);
16898 if(!node || !this.isSelected(node)){
16899 //Roo.log("not selected");
16900 return; // not selected.
16904 Roo.each(this.selections, function(s) {
16906 Roo.fly(node).removeClass(this.selectedClass);
16913 this.selections= ns;
16914 this.fireEvent("selectionchange", this, this.selections);
16918 * Gets a template node.
16919 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16920 * @return {HTMLElement} The node or null if it wasn't found
16922 getNode : function(nodeInfo){
16923 if(typeof nodeInfo == "string"){
16924 return document.getElementById(nodeInfo);
16925 }else if(typeof nodeInfo == "number"){
16926 return this.nodes[nodeInfo];
16932 * Gets a range template nodes.
16933 * @param {Number} startIndex
16934 * @param {Number} endIndex
16935 * @return {Array} An array of nodes
16937 getNodes : function(start, end){
16938 var ns = this.nodes;
16939 start = start || 0;
16940 end = typeof end == "undefined" ? ns.length - 1 : end;
16943 for(var i = start; i <= end; i++){
16947 for(var i = start; i >= end; i--){
16955 * Finds the index of the passed node
16956 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16957 * @return {Number} The index of the node or -1
16959 indexOf : function(node){
16960 node = this.getNode(node);
16961 if(typeof node.nodeIndex == "number"){
16962 return node.nodeIndex;
16964 var ns = this.nodes;
16965 for(var i = 0, len = ns.length; i < len; i++){
16976 * based on jquery fullcalendar
16980 Roo.bootstrap = Roo.bootstrap || {};
16982 * @class Roo.bootstrap.Calendar
16983 * @extends Roo.bootstrap.Component
16984 * Bootstrap Calendar class
16985 * @cfg {Boolean} loadMask (true|false) default false
16986 * @cfg {Object} header generate the user specific header of the calendar, default false
16989 * Create a new Container
16990 * @param {Object} config The config object
16995 Roo.bootstrap.Calendar = function(config){
16996 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
17000 * Fires when a date is selected
17001 * @param {DatePicker} this
17002 * @param {Date} date The selected date
17006 * @event monthchange
17007 * Fires when the displayed month changes
17008 * @param {DatePicker} this
17009 * @param {Date} date The selected month
17011 'monthchange': true,
17013 * @event evententer
17014 * Fires when mouse over an event
17015 * @param {Calendar} this
17016 * @param {event} Event
17018 'evententer': true,
17020 * @event eventleave
17021 * Fires when the mouse leaves an
17022 * @param {Calendar} this
17025 'eventleave': true,
17027 * @event eventclick
17028 * Fires when the mouse click an
17029 * @param {Calendar} this
17038 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
17041 * @cfg {Number} startDay
17042 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
17050 getAutoCreate : function(){
17053 var fc_button = function(name, corner, style, content ) {
17054 return Roo.apply({},{
17056 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17058 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17061 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17072 style : 'width:100%',
17079 cls : 'fc-header-left',
17081 fc_button('prev', 'left', 'arrow', '‹' ),
17082 fc_button('next', 'right', 'arrow', '›' ),
17083 { tag: 'span', cls: 'fc-header-space' },
17084 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17092 cls : 'fc-header-center',
17096 cls: 'fc-header-title',
17099 html : 'month / year'
17107 cls : 'fc-header-right',
17109 /* fc_button('month', 'left', '', 'month' ),
17110 fc_button('week', '', '', 'week' ),
17111 fc_button('day', 'right', '', 'day' )
17123 header = this.header;
17126 var cal_heads = function() {
17128 // fixme - handle this.
17130 for (var i =0; i < Date.dayNames.length; i++) {
17131 var d = Date.dayNames[i];
17134 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17135 html : d.substring(0,3)
17139 ret[0].cls += ' fc-first';
17140 ret[6].cls += ' fc-last';
17143 var cal_cell = function(n) {
17146 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17151 cls: 'fc-day-number',
17155 cls: 'fc-day-content',
17159 style: 'position: relative;' // height: 17px;
17171 var cal_rows = function() {
17174 for (var r = 0; r < 6; r++) {
17181 for (var i =0; i < Date.dayNames.length; i++) {
17182 var d = Date.dayNames[i];
17183 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17186 row.cn[0].cls+=' fc-first';
17187 row.cn[0].cn[0].style = 'min-height:90px';
17188 row.cn[6].cls+=' fc-last';
17192 ret[0].cls += ' fc-first';
17193 ret[4].cls += ' fc-prev-last';
17194 ret[5].cls += ' fc-last';
17201 cls: 'fc-border-separate',
17202 style : 'width:100%',
17210 cls : 'fc-first fc-last',
17228 cls : 'fc-content',
17229 style : "position: relative;",
17232 cls : 'fc-view fc-view-month fc-grid',
17233 style : 'position: relative',
17234 unselectable : 'on',
17237 cls : 'fc-event-container',
17238 style : 'position:absolute;z-index:8;top:0;left:0;'
17256 initEvents : function()
17259 throw "can not find store for calendar";
17265 style: "text-align:center",
17269 style: "background-color:white;width:50%;margin:250 auto",
17273 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17284 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17286 var size = this.el.select('.fc-content', true).first().getSize();
17287 this.maskEl.setSize(size.width, size.height);
17288 this.maskEl.enableDisplayMode("block");
17289 if(!this.loadMask){
17290 this.maskEl.hide();
17293 this.store = Roo.factory(this.store, Roo.data);
17294 this.store.on('load', this.onLoad, this);
17295 this.store.on('beforeload', this.onBeforeLoad, this);
17299 this.cells = this.el.select('.fc-day',true);
17300 //Roo.log(this.cells);
17301 this.textNodes = this.el.query('.fc-day-number');
17302 this.cells.addClassOnOver('fc-state-hover');
17304 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17305 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17306 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17307 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17309 this.on('monthchange', this.onMonthChange, this);
17311 this.update(new Date().clearTime());
17314 resize : function() {
17315 var sz = this.el.getSize();
17317 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17318 this.el.select('.fc-day-content div',true).setHeight(34);
17323 showPrevMonth : function(e){
17324 this.update(this.activeDate.add("mo", -1));
17326 showToday : function(e){
17327 this.update(new Date().clearTime());
17330 showNextMonth : function(e){
17331 this.update(this.activeDate.add("mo", 1));
17335 showPrevYear : function(){
17336 this.update(this.activeDate.add("y", -1));
17340 showNextYear : function(){
17341 this.update(this.activeDate.add("y", 1));
17346 update : function(date)
17348 var vd = this.activeDate;
17349 this.activeDate = date;
17350 // if(vd && this.el){
17351 // var t = date.getTime();
17352 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17353 // Roo.log('using add remove');
17355 // this.fireEvent('monthchange', this, date);
17357 // this.cells.removeClass("fc-state-highlight");
17358 // this.cells.each(function(c){
17359 // if(c.dateValue == t){
17360 // c.addClass("fc-state-highlight");
17361 // setTimeout(function(){
17362 // try{c.dom.firstChild.focus();}catch(e){}
17372 var days = date.getDaysInMonth();
17374 var firstOfMonth = date.getFirstDateOfMonth();
17375 var startingPos = firstOfMonth.getDay()-this.startDay;
17377 if(startingPos < this.startDay){
17381 var pm = date.add(Date.MONTH, -1);
17382 var prevStart = pm.getDaysInMonth()-startingPos;
17384 this.cells = this.el.select('.fc-day',true);
17385 this.textNodes = this.el.query('.fc-day-number');
17386 this.cells.addClassOnOver('fc-state-hover');
17388 var cells = this.cells.elements;
17389 var textEls = this.textNodes;
17391 Roo.each(cells, function(cell){
17392 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17395 days += startingPos;
17397 // convert everything to numbers so it's fast
17398 var day = 86400000;
17399 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17402 //Roo.log(prevStart);
17404 var today = new Date().clearTime().getTime();
17405 var sel = date.clearTime().getTime();
17406 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17407 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17408 var ddMatch = this.disabledDatesRE;
17409 var ddText = this.disabledDatesText;
17410 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17411 var ddaysText = this.disabledDaysText;
17412 var format = this.format;
17414 var setCellClass = function(cal, cell){
17418 //Roo.log('set Cell Class');
17420 var t = d.getTime();
17424 cell.dateValue = t;
17426 cell.className += " fc-today";
17427 cell.className += " fc-state-highlight";
17428 cell.title = cal.todayText;
17431 // disable highlight in other month..
17432 //cell.className += " fc-state-highlight";
17437 cell.className = " fc-state-disabled";
17438 cell.title = cal.minText;
17442 cell.className = " fc-state-disabled";
17443 cell.title = cal.maxText;
17447 if(ddays.indexOf(d.getDay()) != -1){
17448 cell.title = ddaysText;
17449 cell.className = " fc-state-disabled";
17452 if(ddMatch && format){
17453 var fvalue = d.dateFormat(format);
17454 if(ddMatch.test(fvalue)){
17455 cell.title = ddText.replace("%0", fvalue);
17456 cell.className = " fc-state-disabled";
17460 if (!cell.initialClassName) {
17461 cell.initialClassName = cell.dom.className;
17464 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17469 for(; i < startingPos; i++) {
17470 textEls[i].innerHTML = (++prevStart);
17471 d.setDate(d.getDate()+1);
17473 cells[i].className = "fc-past fc-other-month";
17474 setCellClass(this, cells[i]);
17479 for(; i < days; i++){
17480 intDay = i - startingPos + 1;
17481 textEls[i].innerHTML = (intDay);
17482 d.setDate(d.getDate()+1);
17484 cells[i].className = ''; // "x-date-active";
17485 setCellClass(this, cells[i]);
17489 for(; i < 42; i++) {
17490 textEls[i].innerHTML = (++extraDays);
17491 d.setDate(d.getDate()+1);
17493 cells[i].className = "fc-future fc-other-month";
17494 setCellClass(this, cells[i]);
17497 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17499 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17501 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17502 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17504 if(totalRows != 6){
17505 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17506 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17509 this.fireEvent('monthchange', this, date);
17513 if(!this.internalRender){
17514 var main = this.el.dom.firstChild;
17515 var w = main.offsetWidth;
17516 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17517 Roo.fly(main).setWidth(w);
17518 this.internalRender = true;
17519 // opera does not respect the auto grow header center column
17520 // then, after it gets a width opera refuses to recalculate
17521 // without a second pass
17522 if(Roo.isOpera && !this.secondPass){
17523 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17524 this.secondPass = true;
17525 this.update.defer(10, this, [date]);
17532 findCell : function(dt) {
17533 dt = dt.clearTime().getTime();
17535 this.cells.each(function(c){
17536 //Roo.log("check " +c.dateValue + '?=' + dt);
17537 if(c.dateValue == dt){
17547 findCells : function(ev) {
17548 var s = ev.start.clone().clearTime().getTime();
17550 var e= ev.end.clone().clearTime().getTime();
17553 this.cells.each(function(c){
17554 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17556 if(c.dateValue > e){
17559 if(c.dateValue < s){
17568 // findBestRow: function(cells)
17572 // for (var i =0 ; i < cells.length;i++) {
17573 // ret = Math.max(cells[i].rows || 0,ret);
17580 addItem : function(ev)
17582 // look for vertical location slot in
17583 var cells = this.findCells(ev);
17585 // ev.row = this.findBestRow(cells);
17587 // work out the location.
17591 for(var i =0; i < cells.length; i++) {
17593 cells[i].row = cells[0].row;
17596 cells[i].row = cells[i].row + 1;
17606 if (crow.start.getY() == cells[i].getY()) {
17608 crow.end = cells[i];
17625 cells[0].events.push(ev);
17627 this.calevents.push(ev);
17630 clearEvents: function() {
17632 if(!this.calevents){
17636 Roo.each(this.cells.elements, function(c){
17642 Roo.each(this.calevents, function(e) {
17643 Roo.each(e.els, function(el) {
17644 el.un('mouseenter' ,this.onEventEnter, this);
17645 el.un('mouseleave' ,this.onEventLeave, this);
17650 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17656 renderEvents: function()
17660 this.cells.each(function(c) {
17669 if(c.row != c.events.length){
17670 r = 4 - (4 - (c.row - c.events.length));
17673 c.events = ev.slice(0, r);
17674 c.more = ev.slice(r);
17676 if(c.more.length && c.more.length == 1){
17677 c.events.push(c.more.pop());
17680 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17684 this.cells.each(function(c) {
17686 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17689 for (var e = 0; e < c.events.length; e++){
17690 var ev = c.events[e];
17691 var rows = ev.rows;
17693 for(var i = 0; i < rows.length; i++) {
17695 // how many rows should it span..
17698 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17699 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17701 unselectable : "on",
17704 cls: 'fc-event-inner',
17708 // cls: 'fc-event-time',
17709 // html : cells.length > 1 ? '' : ev.time
17713 cls: 'fc-event-title',
17714 html : String.format('{0}', ev.title)
17721 cls: 'ui-resizable-handle ui-resizable-e',
17722 html : '  '
17729 cfg.cls += ' fc-event-start';
17731 if ((i+1) == rows.length) {
17732 cfg.cls += ' fc-event-end';
17735 var ctr = _this.el.select('.fc-event-container',true).first();
17736 var cg = ctr.createChild(cfg);
17738 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17739 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17741 var r = (c.more.length) ? 1 : 0;
17742 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17743 cg.setWidth(ebox.right - sbox.x -2);
17745 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17746 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17747 cg.on('click', _this.onEventClick, _this, ev);
17758 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17759 style : 'position: absolute',
17760 unselectable : "on",
17763 cls: 'fc-event-inner',
17767 cls: 'fc-event-title',
17775 cls: 'ui-resizable-handle ui-resizable-e',
17776 html : '  '
17782 var ctr = _this.el.select('.fc-event-container',true).first();
17783 var cg = ctr.createChild(cfg);
17785 var sbox = c.select('.fc-day-content',true).first().getBox();
17786 var ebox = c.select('.fc-day-content',true).first().getBox();
17788 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17789 cg.setWidth(ebox.right - sbox.x -2);
17791 cg.on('click', _this.onMoreEventClick, _this, c.more);
17801 onEventEnter: function (e, el,event,d) {
17802 this.fireEvent('evententer', this, el, event);
17805 onEventLeave: function (e, el,event,d) {
17806 this.fireEvent('eventleave', this, el, event);
17809 onEventClick: function (e, el,event,d) {
17810 this.fireEvent('eventclick', this, el, event);
17813 onMonthChange: function () {
17817 onMoreEventClick: function(e, el, more)
17821 this.calpopover.placement = 'right';
17822 this.calpopover.setTitle('More');
17824 this.calpopover.setContent('');
17826 var ctr = this.calpopover.el.select('.popover-content', true).first();
17828 Roo.each(more, function(m){
17830 cls : 'fc-event-hori fc-event-draggable',
17833 var cg = ctr.createChild(cfg);
17835 cg.on('click', _this.onEventClick, _this, m);
17838 this.calpopover.show(el);
17843 onLoad: function ()
17845 this.calevents = [];
17848 if(this.store.getCount() > 0){
17849 this.store.data.each(function(d){
17852 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17853 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17854 time : d.data.start_time,
17855 title : d.data.title,
17856 description : d.data.description,
17857 venue : d.data.venue
17862 this.renderEvents();
17864 if(this.calevents.length && this.loadMask){
17865 this.maskEl.hide();
17869 onBeforeLoad: function()
17871 this.clearEvents();
17873 this.maskEl.show();
17887 * @class Roo.bootstrap.Popover
17888 * @extends Roo.bootstrap.Component
17889 * Bootstrap Popover class
17890 * @cfg {String} html contents of the popover (or false to use children..)
17891 * @cfg {String} title of popover (or false to hide)
17892 * @cfg {String} placement how it is placed
17893 * @cfg {String} trigger click || hover (or false to trigger manually)
17894 * @cfg {String} over what (parent or false to trigger manually.)
17895 * @cfg {Number} delay - delay before showing
17898 * Create a new Popover
17899 * @param {Object} config The config object
17902 Roo.bootstrap.Popover = function(config){
17903 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17909 * After the popover show
17911 * @param {Roo.bootstrap.Popover} this
17916 * After the popover hide
17918 * @param {Roo.bootstrap.Popover} this
17924 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17926 title: 'Fill in a title',
17929 placement : 'right',
17930 trigger : 'hover', // hover
17936 can_build_overlaid : false,
17938 getChildContainer : function()
17940 return this.el.select('.popover-content',true).first();
17943 getAutoCreate : function(){
17946 cls : 'popover roo-dynamic',
17947 style: 'display:block',
17953 cls : 'popover-inner',
17957 cls: 'popover-title popover-header',
17961 cls : 'popover-content popover-body',
17972 setTitle: function(str)
17975 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17977 setContent: function(str)
17980 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17982 // as it get's added to the bottom of the page.
17983 onRender : function(ct, position)
17985 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17987 var cfg = Roo.apply({}, this.getAutoCreate());
17991 cfg.cls += ' ' + this.cls;
17994 cfg.style = this.style;
17996 //Roo.log("adding to ");
17997 this.el = Roo.get(document.body).createChild(cfg, position);
17998 // Roo.log(this.el);
18003 initEvents : function()
18005 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
18006 this.el.enableDisplayMode('block');
18008 if (this.over === false) {
18011 if (this.triggers === false) {
18014 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18015 var triggers = this.trigger ? this.trigger.split(' ') : [];
18016 Roo.each(triggers, function(trigger) {
18018 if (trigger == 'click') {
18019 on_el.on('click', this.toggle, this);
18020 } else if (trigger != 'manual') {
18021 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
18022 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
18024 on_el.on(eventIn ,this.enter, this);
18025 on_el.on(eventOut, this.leave, this);
18036 toggle : function () {
18037 this.hoverState == 'in' ? this.leave() : this.enter();
18040 enter : function () {
18042 clearTimeout(this.timeout);
18044 this.hoverState = 'in';
18046 if (!this.delay || !this.delay.show) {
18051 this.timeout = setTimeout(function () {
18052 if (_t.hoverState == 'in') {
18055 }, this.delay.show)
18058 leave : function() {
18059 clearTimeout(this.timeout);
18061 this.hoverState = 'out';
18063 if (!this.delay || !this.delay.hide) {
18068 this.timeout = setTimeout(function () {
18069 if (_t.hoverState == 'out') {
18072 }, this.delay.hide)
18075 show : function (on_el)
18078 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18082 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18083 if (this.html !== false) {
18084 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18086 this.el.removeClass([
18087 'fade','top','bottom', 'left', 'right','in',
18088 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18090 if (!this.title.length) {
18091 this.el.select('.popover-title',true).hide();
18094 var placement = typeof this.placement == 'function' ?
18095 this.placement.call(this, this.el, on_el) :
18098 var autoToken = /\s?auto?\s?/i;
18099 var autoPlace = autoToken.test(placement);
18101 placement = placement.replace(autoToken, '') || 'top';
18105 //this.el.setXY([0,0]);
18107 this.el.dom.style.display='block';
18108 this.el.addClass(placement);
18110 //this.el.appendTo(on_el);
18112 var p = this.getPosition();
18113 var box = this.el.getBox();
18118 var align = Roo.bootstrap.Popover.alignment[placement];
18121 this.el.alignTo(on_el, align[0],align[1]);
18122 //var arrow = this.el.select('.arrow',true).first();
18123 //arrow.set(align[2],
18125 this.el.addClass('in');
18128 if (this.el.hasClass('fade')) {
18132 this.hoverState = 'in';
18134 this.fireEvent('show', this);
18139 this.el.setXY([0,0]);
18140 this.el.removeClass('in');
18142 this.hoverState = null;
18144 this.fireEvent('hide', this);
18149 Roo.bootstrap.Popover.alignment = {
18150 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18151 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18152 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18153 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18164 * @class Roo.bootstrap.Progress
18165 * @extends Roo.bootstrap.Component
18166 * Bootstrap Progress class
18167 * @cfg {Boolean} striped striped of the progress bar
18168 * @cfg {Boolean} active animated of the progress bar
18172 * Create a new Progress
18173 * @param {Object} config The config object
18176 Roo.bootstrap.Progress = function(config){
18177 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18180 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18185 getAutoCreate : function(){
18193 cfg.cls += ' progress-striped';
18197 cfg.cls += ' active';
18216 * @class Roo.bootstrap.ProgressBar
18217 * @extends Roo.bootstrap.Component
18218 * Bootstrap ProgressBar class
18219 * @cfg {Number} aria_valuenow aria-value now
18220 * @cfg {Number} aria_valuemin aria-value min
18221 * @cfg {Number} aria_valuemax aria-value max
18222 * @cfg {String} label label for the progress bar
18223 * @cfg {String} panel (success | info | warning | danger )
18224 * @cfg {String} role role of the progress bar
18225 * @cfg {String} sr_only text
18229 * Create a new ProgressBar
18230 * @param {Object} config The config object
18233 Roo.bootstrap.ProgressBar = function(config){
18234 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18237 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18241 aria_valuemax : 100,
18247 getAutoCreate : function()
18252 cls: 'progress-bar',
18253 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18265 cfg.role = this.role;
18268 if(this.aria_valuenow){
18269 cfg['aria-valuenow'] = this.aria_valuenow;
18272 if(this.aria_valuemin){
18273 cfg['aria-valuemin'] = this.aria_valuemin;
18276 if(this.aria_valuemax){
18277 cfg['aria-valuemax'] = this.aria_valuemax;
18280 if(this.label && !this.sr_only){
18281 cfg.html = this.label;
18285 cfg.cls += ' progress-bar-' + this.panel;
18291 update : function(aria_valuenow)
18293 this.aria_valuenow = aria_valuenow;
18295 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18310 * @class Roo.bootstrap.TabGroup
18311 * @extends Roo.bootstrap.Column
18312 * Bootstrap Column class
18313 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18314 * @cfg {Boolean} carousel true to make the group behave like a carousel
18315 * @cfg {Boolean} bullets show bullets for the panels
18316 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18317 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18318 * @cfg {Boolean} showarrow (true|false) show arrow default true
18321 * Create a new TabGroup
18322 * @param {Object} config The config object
18325 Roo.bootstrap.TabGroup = function(config){
18326 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18328 this.navId = Roo.id();
18331 Roo.bootstrap.TabGroup.register(this);
18335 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18338 transition : false,
18343 slideOnTouch : false,
18346 getAutoCreate : function()
18348 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18350 cfg.cls += ' tab-content';
18352 if (this.carousel) {
18353 cfg.cls += ' carousel slide';
18356 cls : 'carousel-inner',
18360 if(this.bullets && !Roo.isTouch){
18363 cls : 'carousel-bullets',
18367 if(this.bullets_cls){
18368 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18375 cfg.cn[0].cn.push(bullets);
18378 if(this.showarrow){
18379 cfg.cn[0].cn.push({
18381 class : 'carousel-arrow',
18385 class : 'carousel-prev',
18389 class : 'fa fa-chevron-left'
18395 class : 'carousel-next',
18399 class : 'fa fa-chevron-right'
18412 initEvents: function()
18414 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18415 // this.el.on("touchstart", this.onTouchStart, this);
18418 if(this.autoslide){
18421 this.slideFn = window.setInterval(function() {
18422 _this.showPanelNext();
18426 if(this.showarrow){
18427 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18428 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18434 // onTouchStart : function(e, el, o)
18436 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18440 // this.showPanelNext();
18444 getChildContainer : function()
18446 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18450 * register a Navigation item
18451 * @param {Roo.bootstrap.NavItem} the navitem to add
18453 register : function(item)
18455 this.tabs.push( item);
18456 item.navId = this.navId; // not really needed..
18461 getActivePanel : function()
18464 Roo.each(this.tabs, function(t) {
18474 getPanelByName : function(n)
18477 Roo.each(this.tabs, function(t) {
18478 if (t.tabId == n) {
18486 indexOfPanel : function(p)
18489 Roo.each(this.tabs, function(t,i) {
18490 if (t.tabId == p.tabId) {
18499 * show a specific panel
18500 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18501 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18503 showPanel : function (pan)
18505 if(this.transition || typeof(pan) == 'undefined'){
18506 Roo.log("waiting for the transitionend");
18510 if (typeof(pan) == 'number') {
18511 pan = this.tabs[pan];
18514 if (typeof(pan) == 'string') {
18515 pan = this.getPanelByName(pan);
18518 var cur = this.getActivePanel();
18521 Roo.log('pan or acitve pan is undefined');
18525 if (pan.tabId == this.getActivePanel().tabId) {
18529 if (false === cur.fireEvent('beforedeactivate')) {
18533 if(this.bullets > 0 && !Roo.isTouch){
18534 this.setActiveBullet(this.indexOfPanel(pan));
18537 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18539 //class="carousel-item carousel-item-next carousel-item-left"
18541 this.transition = true;
18542 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18543 var lr = dir == 'next' ? 'left' : 'right';
18544 pan.el.addClass(dir); // or prev
18545 pan.el.addClass('carousel-item-' + dir); // or prev
18546 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18547 cur.el.addClass(lr); // or right
18548 pan.el.addClass(lr);
18549 cur.el.addClass('carousel-item-' +lr); // or right
18550 pan.el.addClass('carousel-item-' +lr);
18554 cur.el.on('transitionend', function() {
18555 Roo.log("trans end?");
18557 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18558 pan.setActive(true);
18560 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18561 cur.setActive(false);
18563 _this.transition = false;
18565 }, this, { single: true } );
18570 cur.setActive(false);
18571 pan.setActive(true);
18576 showPanelNext : function()
18578 var i = this.indexOfPanel(this.getActivePanel());
18580 if (i >= this.tabs.length - 1 && !this.autoslide) {
18584 if (i >= this.tabs.length - 1 && this.autoslide) {
18588 this.showPanel(this.tabs[i+1]);
18591 showPanelPrev : function()
18593 var i = this.indexOfPanel(this.getActivePanel());
18595 if (i < 1 && !this.autoslide) {
18599 if (i < 1 && this.autoslide) {
18600 i = this.tabs.length;
18603 this.showPanel(this.tabs[i-1]);
18607 addBullet: function()
18609 if(!this.bullets || Roo.isTouch){
18612 var ctr = this.el.select('.carousel-bullets',true).first();
18613 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18614 var bullet = ctr.createChild({
18615 cls : 'bullet bullet-' + i
18616 },ctr.dom.lastChild);
18621 bullet.on('click', (function(e, el, o, ii, t){
18623 e.preventDefault();
18625 this.showPanel(ii);
18627 if(this.autoslide && this.slideFn){
18628 clearInterval(this.slideFn);
18629 this.slideFn = window.setInterval(function() {
18630 _this.showPanelNext();
18634 }).createDelegate(this, [i, bullet], true));
18639 setActiveBullet : function(i)
18645 Roo.each(this.el.select('.bullet', true).elements, function(el){
18646 el.removeClass('selected');
18649 var bullet = this.el.select('.bullet-' + i, true).first();
18655 bullet.addClass('selected');
18666 Roo.apply(Roo.bootstrap.TabGroup, {
18670 * register a Navigation Group
18671 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18673 register : function(navgrp)
18675 this.groups[navgrp.navId] = navgrp;
18679 * fetch a Navigation Group based on the navigation ID
18680 * if one does not exist , it will get created.
18681 * @param {string} the navgroup to add
18682 * @returns {Roo.bootstrap.NavGroup} the navgroup
18684 get: function(navId) {
18685 if (typeof(this.groups[navId]) == 'undefined') {
18686 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18688 return this.groups[navId] ;
18703 * @class Roo.bootstrap.TabPanel
18704 * @extends Roo.bootstrap.Component
18705 * Bootstrap TabPanel class
18706 * @cfg {Boolean} active panel active
18707 * @cfg {String} html panel content
18708 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18709 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18710 * @cfg {String} href click to link..
18714 * Create a new TabPanel
18715 * @param {Object} config The config object
18718 Roo.bootstrap.TabPanel = function(config){
18719 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18723 * Fires when the active status changes
18724 * @param {Roo.bootstrap.TabPanel} this
18725 * @param {Boolean} state the new state
18730 * @event beforedeactivate
18731 * Fires before a tab is de-activated - can be used to do validation on a form.
18732 * @param {Roo.bootstrap.TabPanel} this
18733 * @return {Boolean} false if there is an error
18736 'beforedeactivate': true
18739 this.tabId = this.tabId || Roo.id();
18743 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18751 getAutoCreate : function(){
18756 // item is needed for carousel - not sure if it has any effect otherwise
18757 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18758 html: this.html || ''
18762 cfg.cls += ' active';
18766 cfg.tabId = this.tabId;
18774 initEvents: function()
18776 var p = this.parent();
18778 this.navId = this.navId || p.navId;
18780 if (typeof(this.navId) != 'undefined') {
18781 // not really needed.. but just in case.. parent should be a NavGroup.
18782 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18786 var i = tg.tabs.length - 1;
18788 if(this.active && tg.bullets > 0 && i < tg.bullets){
18789 tg.setActiveBullet(i);
18793 this.el.on('click', this.onClick, this);
18796 this.el.on("touchstart", this.onTouchStart, this);
18797 this.el.on("touchmove", this.onTouchMove, this);
18798 this.el.on("touchend", this.onTouchEnd, this);
18803 onRender : function(ct, position)
18805 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18808 setActive : function(state)
18810 Roo.log("panel - set active " + this.tabId + "=" + state);
18812 this.active = state;
18814 this.el.removeClass('active');
18816 } else if (!this.el.hasClass('active')) {
18817 this.el.addClass('active');
18820 this.fireEvent('changed', this, state);
18823 onClick : function(e)
18825 e.preventDefault();
18827 if(!this.href.length){
18831 window.location.href = this.href;
18840 onTouchStart : function(e)
18842 this.swiping = false;
18844 this.startX = e.browserEvent.touches[0].clientX;
18845 this.startY = e.browserEvent.touches[0].clientY;
18848 onTouchMove : function(e)
18850 this.swiping = true;
18852 this.endX = e.browserEvent.touches[0].clientX;
18853 this.endY = e.browserEvent.touches[0].clientY;
18856 onTouchEnd : function(e)
18863 var tabGroup = this.parent();
18865 if(this.endX > this.startX){ // swiping right
18866 tabGroup.showPanelPrev();
18870 if(this.startX > this.endX){ // swiping left
18871 tabGroup.showPanelNext();
18890 * @class Roo.bootstrap.DateField
18891 * @extends Roo.bootstrap.Input
18892 * Bootstrap DateField class
18893 * @cfg {Number} weekStart default 0
18894 * @cfg {String} viewMode default empty, (months|years)
18895 * @cfg {String} minViewMode default empty, (months|years)
18896 * @cfg {Number} startDate default -Infinity
18897 * @cfg {Number} endDate default Infinity
18898 * @cfg {Boolean} todayHighlight default false
18899 * @cfg {Boolean} todayBtn default false
18900 * @cfg {Boolean} calendarWeeks default false
18901 * @cfg {Object} daysOfWeekDisabled default empty
18902 * @cfg {Boolean} singleMode default false (true | false)
18904 * @cfg {Boolean} keyboardNavigation default true
18905 * @cfg {String} language default en
18908 * Create a new DateField
18909 * @param {Object} config The config object
18912 Roo.bootstrap.DateField = function(config){
18913 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18917 * Fires when this field show.
18918 * @param {Roo.bootstrap.DateField} this
18919 * @param {Mixed} date The date value
18924 * Fires when this field hide.
18925 * @param {Roo.bootstrap.DateField} this
18926 * @param {Mixed} date The date value
18931 * Fires when select a date.
18932 * @param {Roo.bootstrap.DateField} this
18933 * @param {Mixed} date The date value
18937 * @event beforeselect
18938 * Fires when before select a date.
18939 * @param {Roo.bootstrap.DateField} this
18940 * @param {Mixed} date The date value
18942 beforeselect : true
18946 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18949 * @cfg {String} format
18950 * The default date format string which can be overriden for localization support. The format must be
18951 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18955 * @cfg {String} altFormats
18956 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18957 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18959 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18967 todayHighlight : false,
18973 keyboardNavigation: true,
18975 calendarWeeks: false,
18977 startDate: -Infinity,
18981 daysOfWeekDisabled: [],
18985 singleMode : false,
18987 UTCDate: function()
18989 return new Date(Date.UTC.apply(Date, arguments));
18992 UTCToday: function()
18994 var today = new Date();
18995 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18998 getDate: function() {
18999 var d = this.getUTCDate();
19000 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
19003 getUTCDate: function() {
19007 setDate: function(d) {
19008 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
19011 setUTCDate: function(d) {
19013 this.setValue(this.formatDate(this.date));
19016 onRender: function(ct, position)
19019 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
19021 this.language = this.language || 'en';
19022 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
19023 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
19025 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
19026 this.format = this.format || 'm/d/y';
19027 this.isInline = false;
19028 this.isInput = true;
19029 this.component = this.el.select('.add-on', true).first() || false;
19030 this.component = (this.component && this.component.length === 0) ? false : this.component;
19031 this.hasInput = this.component && this.inputEl().length;
19033 if (typeof(this.minViewMode === 'string')) {
19034 switch (this.minViewMode) {
19036 this.minViewMode = 1;
19039 this.minViewMode = 2;
19042 this.minViewMode = 0;
19047 if (typeof(this.viewMode === 'string')) {
19048 switch (this.viewMode) {
19061 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19063 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19065 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19067 this.picker().on('mousedown', this.onMousedown, this);
19068 this.picker().on('click', this.onClick, this);
19070 this.picker().addClass('datepicker-dropdown');
19072 this.startViewMode = this.viewMode;
19074 if(this.singleMode){
19075 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19076 v.setVisibilityMode(Roo.Element.DISPLAY);
19080 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19081 v.setStyle('width', '189px');
19085 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19086 if(!this.calendarWeeks){
19091 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19092 v.attr('colspan', function(i, val){
19093 return parseInt(val) + 1;
19098 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19100 this.setStartDate(this.startDate);
19101 this.setEndDate(this.endDate);
19103 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19110 if(this.isInline) {
19115 picker : function()
19117 return this.pickerEl;
19118 // return this.el.select('.datepicker', true).first();
19121 fillDow: function()
19123 var dowCnt = this.weekStart;
19132 if(this.calendarWeeks){
19140 while (dowCnt < this.weekStart + 7) {
19144 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19148 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19151 fillMonths: function()
19154 var months = this.picker().select('>.datepicker-months td', true).first();
19156 months.dom.innerHTML = '';
19162 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19165 months.createChild(month);
19172 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;
19174 if (this.date < this.startDate) {
19175 this.viewDate = new Date(this.startDate);
19176 } else if (this.date > this.endDate) {
19177 this.viewDate = new Date(this.endDate);
19179 this.viewDate = new Date(this.date);
19187 var d = new Date(this.viewDate),
19188 year = d.getUTCFullYear(),
19189 month = d.getUTCMonth(),
19190 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19191 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19192 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19193 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19194 currentDate = this.date && this.date.valueOf(),
19195 today = this.UTCToday();
19197 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19199 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19201 // this.picker.select('>tfoot th.today').
19202 // .text(dates[this.language].today)
19203 // .toggle(this.todayBtn !== false);
19205 this.updateNavArrows();
19208 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19210 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19212 prevMonth.setUTCDate(day);
19214 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19216 var nextMonth = new Date(prevMonth);
19218 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19220 nextMonth = nextMonth.valueOf();
19222 var fillMonths = false;
19224 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19226 while(prevMonth.valueOf() <= nextMonth) {
19229 if (prevMonth.getUTCDay() === this.weekStart) {
19231 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19239 if(this.calendarWeeks){
19240 // ISO 8601: First week contains first thursday.
19241 // ISO also states week starts on Monday, but we can be more abstract here.
19243 // Start of current week: based on weekstart/current date
19244 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19245 // Thursday of this week
19246 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19247 // First Thursday of year, year from thursday
19248 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19249 // Calendar week: ms between thursdays, div ms per day, div 7 days
19250 calWeek = (th - yth) / 864e5 / 7 + 1;
19252 fillMonths.cn.push({
19260 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19262 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19265 if (this.todayHighlight &&
19266 prevMonth.getUTCFullYear() == today.getFullYear() &&
19267 prevMonth.getUTCMonth() == today.getMonth() &&
19268 prevMonth.getUTCDate() == today.getDate()) {
19269 clsName += ' today';
19272 if (currentDate && prevMonth.valueOf() === currentDate) {
19273 clsName += ' active';
19276 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19277 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19278 clsName += ' disabled';
19281 fillMonths.cn.push({
19283 cls: 'day ' + clsName,
19284 html: prevMonth.getDate()
19287 prevMonth.setDate(prevMonth.getDate()+1);
19290 var currentYear = this.date && this.date.getUTCFullYear();
19291 var currentMonth = this.date && this.date.getUTCMonth();
19293 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19295 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19296 v.removeClass('active');
19298 if(currentYear === year && k === currentMonth){
19299 v.addClass('active');
19302 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19303 v.addClass('disabled');
19309 year = parseInt(year/10, 10) * 10;
19311 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19313 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19316 for (var i = -1; i < 11; i++) {
19317 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19319 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19327 showMode: function(dir)
19330 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19333 Roo.each(this.picker().select('>div',true).elements, function(v){
19334 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19337 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19342 if(this.isInline) {
19346 this.picker().removeClass(['bottom', 'top']);
19348 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19350 * place to the top of element!
19354 this.picker().addClass('top');
19355 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19360 this.picker().addClass('bottom');
19362 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19365 parseDate : function(value)
19367 if(!value || value instanceof Date){
19370 var v = Date.parseDate(value, this.format);
19371 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19372 v = Date.parseDate(value, 'Y-m-d');
19374 if(!v && this.altFormats){
19375 if(!this.altFormatsArray){
19376 this.altFormatsArray = this.altFormats.split("|");
19378 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19379 v = Date.parseDate(value, this.altFormatsArray[i]);
19385 formatDate : function(date, fmt)
19387 return (!date || !(date instanceof Date)) ?
19388 date : date.dateFormat(fmt || this.format);
19391 onFocus : function()
19393 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19397 onBlur : function()
19399 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19401 var d = this.inputEl().getValue();
19408 showPopup : function()
19410 this.picker().show();
19414 this.fireEvent('showpopup', this, this.date);
19417 hidePopup : function()
19419 if(this.isInline) {
19422 this.picker().hide();
19423 this.viewMode = this.startViewMode;
19426 this.fireEvent('hidepopup', this, this.date);
19430 onMousedown: function(e)
19432 e.stopPropagation();
19433 e.preventDefault();
19438 Roo.bootstrap.DateField.superclass.keyup.call(this);
19442 setValue: function(v)
19444 if(this.fireEvent('beforeselect', this, v) !== false){
19445 var d = new Date(this.parseDate(v) ).clearTime();
19447 if(isNaN(d.getTime())){
19448 this.date = this.viewDate = '';
19449 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19453 v = this.formatDate(d);
19455 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19457 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19461 this.fireEvent('select', this, this.date);
19465 getValue: function()
19467 return this.formatDate(this.date);
19470 fireKey: function(e)
19472 if (!this.picker().isVisible()){
19473 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19479 var dateChanged = false,
19481 newDate, newViewDate;
19486 e.preventDefault();
19490 if (!this.keyboardNavigation) {
19493 dir = e.keyCode == 37 ? -1 : 1;
19496 newDate = this.moveYear(this.date, dir);
19497 newViewDate = this.moveYear(this.viewDate, dir);
19498 } else if (e.shiftKey){
19499 newDate = this.moveMonth(this.date, dir);
19500 newViewDate = this.moveMonth(this.viewDate, dir);
19502 newDate = new Date(this.date);
19503 newDate.setUTCDate(this.date.getUTCDate() + dir);
19504 newViewDate = new Date(this.viewDate);
19505 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19507 if (this.dateWithinRange(newDate)){
19508 this.date = newDate;
19509 this.viewDate = newViewDate;
19510 this.setValue(this.formatDate(this.date));
19512 e.preventDefault();
19513 dateChanged = true;
19518 if (!this.keyboardNavigation) {
19521 dir = e.keyCode == 38 ? -1 : 1;
19523 newDate = this.moveYear(this.date, dir);
19524 newViewDate = this.moveYear(this.viewDate, dir);
19525 } else if (e.shiftKey){
19526 newDate = this.moveMonth(this.date, dir);
19527 newViewDate = this.moveMonth(this.viewDate, dir);
19529 newDate = new Date(this.date);
19530 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19531 newViewDate = new Date(this.viewDate);
19532 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19534 if (this.dateWithinRange(newDate)){
19535 this.date = newDate;
19536 this.viewDate = newViewDate;
19537 this.setValue(this.formatDate(this.date));
19539 e.preventDefault();
19540 dateChanged = true;
19544 this.setValue(this.formatDate(this.date));
19546 e.preventDefault();
19549 this.setValue(this.formatDate(this.date));
19563 onClick: function(e)
19565 e.stopPropagation();
19566 e.preventDefault();
19568 var target = e.getTarget();
19570 if(target.nodeName.toLowerCase() === 'i'){
19571 target = Roo.get(target).dom.parentNode;
19574 var nodeName = target.nodeName;
19575 var className = target.className;
19576 var html = target.innerHTML;
19577 //Roo.log(nodeName);
19579 switch(nodeName.toLowerCase()) {
19581 switch(className) {
19587 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19588 switch(this.viewMode){
19590 this.viewDate = this.moveMonth(this.viewDate, dir);
19594 this.viewDate = this.moveYear(this.viewDate, dir);
19600 var date = new Date();
19601 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19603 this.setValue(this.formatDate(this.date));
19610 if (className.indexOf('disabled') < 0) {
19611 this.viewDate.setUTCDate(1);
19612 if (className.indexOf('month') > -1) {
19613 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19615 var year = parseInt(html, 10) || 0;
19616 this.viewDate.setUTCFullYear(year);
19620 if(this.singleMode){
19621 this.setValue(this.formatDate(this.viewDate));
19632 //Roo.log(className);
19633 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19634 var day = parseInt(html, 10) || 1;
19635 var year = this.viewDate.getUTCFullYear(),
19636 month = this.viewDate.getUTCMonth();
19638 if (className.indexOf('old') > -1) {
19645 } else if (className.indexOf('new') > -1) {
19653 //Roo.log([year,month,day]);
19654 this.date = this.UTCDate(year, month, day,0,0,0,0);
19655 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19657 //Roo.log(this.formatDate(this.date));
19658 this.setValue(this.formatDate(this.date));
19665 setStartDate: function(startDate)
19667 this.startDate = startDate || -Infinity;
19668 if (this.startDate !== -Infinity) {
19669 this.startDate = this.parseDate(this.startDate);
19672 this.updateNavArrows();
19675 setEndDate: function(endDate)
19677 this.endDate = endDate || Infinity;
19678 if (this.endDate !== Infinity) {
19679 this.endDate = this.parseDate(this.endDate);
19682 this.updateNavArrows();
19685 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19687 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19688 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19689 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19691 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19692 return parseInt(d, 10);
19695 this.updateNavArrows();
19698 updateNavArrows: function()
19700 if(this.singleMode){
19704 var d = new Date(this.viewDate),
19705 year = d.getUTCFullYear(),
19706 month = d.getUTCMonth();
19708 Roo.each(this.picker().select('.prev', true).elements, function(v){
19710 switch (this.viewMode) {
19713 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19719 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19726 Roo.each(this.picker().select('.next', true).elements, function(v){
19728 switch (this.viewMode) {
19731 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19737 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19745 moveMonth: function(date, dir)
19750 var new_date = new Date(date.valueOf()),
19751 day = new_date.getUTCDate(),
19752 month = new_date.getUTCMonth(),
19753 mag = Math.abs(dir),
19755 dir = dir > 0 ? 1 : -1;
19758 // If going back one month, make sure month is not current month
19759 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19761 return new_date.getUTCMonth() == month;
19763 // If going forward one month, make sure month is as expected
19764 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19766 return new_date.getUTCMonth() != new_month;
19768 new_month = month + dir;
19769 new_date.setUTCMonth(new_month);
19770 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19771 if (new_month < 0 || new_month > 11) {
19772 new_month = (new_month + 12) % 12;
19775 // For magnitudes >1, move one month at a time...
19776 for (var i=0; i<mag; i++) {
19777 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19778 new_date = this.moveMonth(new_date, dir);
19780 // ...then reset the day, keeping it in the new month
19781 new_month = new_date.getUTCMonth();
19782 new_date.setUTCDate(day);
19784 return new_month != new_date.getUTCMonth();
19787 // Common date-resetting loop -- if date is beyond end of month, make it
19790 new_date.setUTCDate(--day);
19791 new_date.setUTCMonth(new_month);
19796 moveYear: function(date, dir)
19798 return this.moveMonth(date, dir*12);
19801 dateWithinRange: function(date)
19803 return date >= this.startDate && date <= this.endDate;
19809 this.picker().remove();
19812 validateValue : function(value)
19814 if(this.getVisibilityEl().hasClass('hidden')){
19818 if(value.length < 1) {
19819 if(this.allowBlank){
19825 if(value.length < this.minLength){
19828 if(value.length > this.maxLength){
19832 var vt = Roo.form.VTypes;
19833 if(!vt[this.vtype](value, this)){
19837 if(typeof this.validator == "function"){
19838 var msg = this.validator(value);
19844 if(this.regex && !this.regex.test(value)){
19848 if(typeof(this.parseDate(value)) == 'undefined'){
19852 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19856 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19866 this.date = this.viewDate = '';
19868 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19873 Roo.apply(Roo.bootstrap.DateField, {
19884 html: '<i class="fa fa-arrow-left"/>'
19894 html: '<i class="fa fa-arrow-right"/>'
19936 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19937 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19938 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19939 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19940 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19953 navFnc: 'FullYear',
19958 navFnc: 'FullYear',
19963 Roo.apply(Roo.bootstrap.DateField, {
19967 cls: 'datepicker dropdown-menu roo-dynamic',
19971 cls: 'datepicker-days',
19975 cls: 'table-condensed',
19977 Roo.bootstrap.DateField.head,
19981 Roo.bootstrap.DateField.footer
19988 cls: 'datepicker-months',
19992 cls: 'table-condensed',
19994 Roo.bootstrap.DateField.head,
19995 Roo.bootstrap.DateField.content,
19996 Roo.bootstrap.DateField.footer
20003 cls: 'datepicker-years',
20007 cls: 'table-condensed',
20009 Roo.bootstrap.DateField.head,
20010 Roo.bootstrap.DateField.content,
20011 Roo.bootstrap.DateField.footer
20030 * @class Roo.bootstrap.TimeField
20031 * @extends Roo.bootstrap.Input
20032 * Bootstrap DateField class
20036 * Create a new TimeField
20037 * @param {Object} config The config object
20040 Roo.bootstrap.TimeField = function(config){
20041 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
20045 * Fires when this field show.
20046 * @param {Roo.bootstrap.DateField} thisthis
20047 * @param {Mixed} date The date value
20052 * Fires when this field hide.
20053 * @param {Roo.bootstrap.DateField} this
20054 * @param {Mixed} date The date value
20059 * Fires when select a date.
20060 * @param {Roo.bootstrap.DateField} this
20061 * @param {Mixed} date The date value
20067 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20070 * @cfg {String} format
20071 * The default time format string which can be overriden for localization support. The format must be
20072 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20076 onRender: function(ct, position)
20079 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20081 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20083 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20085 this.pop = this.picker().select('>.datepicker-time',true).first();
20086 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20088 this.picker().on('mousedown', this.onMousedown, this);
20089 this.picker().on('click', this.onClick, this);
20091 this.picker().addClass('datepicker-dropdown');
20096 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20097 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20098 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20099 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20100 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20101 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20105 fireKey: function(e){
20106 if (!this.picker().isVisible()){
20107 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20113 e.preventDefault();
20121 this.onTogglePeriod();
20124 this.onIncrementMinutes();
20127 this.onDecrementMinutes();
20136 onClick: function(e) {
20137 e.stopPropagation();
20138 e.preventDefault();
20141 picker : function()
20143 return this.el.select('.datepicker', true).first();
20146 fillTime: function()
20148 var time = this.pop.select('tbody', true).first();
20150 time.dom.innerHTML = '';
20165 cls: 'hours-up glyphicon glyphicon-chevron-up'
20185 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20206 cls: 'timepicker-hour',
20221 cls: 'timepicker-minute',
20236 cls: 'btn btn-primary period',
20258 cls: 'hours-down glyphicon glyphicon-chevron-down'
20278 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20296 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20303 var hours = this.time.getHours();
20304 var minutes = this.time.getMinutes();
20317 hours = hours - 12;
20321 hours = '0' + hours;
20325 minutes = '0' + minutes;
20328 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20329 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20330 this.pop.select('button', true).first().dom.innerHTML = period;
20336 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20338 var cls = ['bottom'];
20340 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20347 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20352 this.picker().addClass(cls.join('-'));
20356 Roo.each(cls, function(c){
20358 _this.picker().setTop(_this.inputEl().getHeight());
20362 _this.picker().setTop(0 - _this.picker().getHeight());
20367 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20371 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20378 onFocus : function()
20380 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20384 onBlur : function()
20386 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20392 this.picker().show();
20397 this.fireEvent('show', this, this.date);
20402 this.picker().hide();
20405 this.fireEvent('hide', this, this.date);
20408 setTime : function()
20411 this.setValue(this.time.format(this.format));
20413 this.fireEvent('select', this, this.date);
20418 onMousedown: function(e){
20419 e.stopPropagation();
20420 e.preventDefault();
20423 onIncrementHours: function()
20425 Roo.log('onIncrementHours');
20426 this.time = this.time.add(Date.HOUR, 1);
20431 onDecrementHours: function()
20433 Roo.log('onDecrementHours');
20434 this.time = this.time.add(Date.HOUR, -1);
20438 onIncrementMinutes: function()
20440 Roo.log('onIncrementMinutes');
20441 this.time = this.time.add(Date.MINUTE, 1);
20445 onDecrementMinutes: function()
20447 Roo.log('onDecrementMinutes');
20448 this.time = this.time.add(Date.MINUTE, -1);
20452 onTogglePeriod: function()
20454 Roo.log('onTogglePeriod');
20455 this.time = this.time.add(Date.HOUR, 12);
20462 Roo.apply(Roo.bootstrap.TimeField, {
20492 cls: 'btn btn-info ok',
20504 Roo.apply(Roo.bootstrap.TimeField, {
20508 cls: 'datepicker dropdown-menu',
20512 cls: 'datepicker-time',
20516 cls: 'table-condensed',
20518 Roo.bootstrap.TimeField.content,
20519 Roo.bootstrap.TimeField.footer
20538 * @class Roo.bootstrap.MonthField
20539 * @extends Roo.bootstrap.Input
20540 * Bootstrap MonthField class
20542 * @cfg {String} language default en
20545 * Create a new MonthField
20546 * @param {Object} config The config object
20549 Roo.bootstrap.MonthField = function(config){
20550 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20555 * Fires when this field show.
20556 * @param {Roo.bootstrap.MonthField} this
20557 * @param {Mixed} date The date value
20562 * Fires when this field hide.
20563 * @param {Roo.bootstrap.MonthField} this
20564 * @param {Mixed} date The date value
20569 * Fires when select a date.
20570 * @param {Roo.bootstrap.MonthField} this
20571 * @param {String} oldvalue The old value
20572 * @param {String} newvalue The new value
20578 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20580 onRender: function(ct, position)
20583 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20585 this.language = this.language || 'en';
20586 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20587 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20589 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20590 this.isInline = false;
20591 this.isInput = true;
20592 this.component = this.el.select('.add-on', true).first() || false;
20593 this.component = (this.component && this.component.length === 0) ? false : this.component;
20594 this.hasInput = this.component && this.inputEL().length;
20596 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20598 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20600 this.picker().on('mousedown', this.onMousedown, this);
20601 this.picker().on('click', this.onClick, this);
20603 this.picker().addClass('datepicker-dropdown');
20605 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20606 v.setStyle('width', '189px');
20613 if(this.isInline) {
20619 setValue: function(v, suppressEvent)
20621 var o = this.getValue();
20623 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20627 if(suppressEvent !== true){
20628 this.fireEvent('select', this, o, v);
20633 getValue: function()
20638 onClick: function(e)
20640 e.stopPropagation();
20641 e.preventDefault();
20643 var target = e.getTarget();
20645 if(target.nodeName.toLowerCase() === 'i'){
20646 target = Roo.get(target).dom.parentNode;
20649 var nodeName = target.nodeName;
20650 var className = target.className;
20651 var html = target.innerHTML;
20653 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20657 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20659 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20665 picker : function()
20667 return this.pickerEl;
20670 fillMonths: function()
20673 var months = this.picker().select('>.datepicker-months td', true).first();
20675 months.dom.innerHTML = '';
20681 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20684 months.createChild(month);
20693 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20694 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20697 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20698 e.removeClass('active');
20700 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20701 e.addClass('active');
20708 if(this.isInline) {
20712 this.picker().removeClass(['bottom', 'top']);
20714 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20716 * place to the top of element!
20720 this.picker().addClass('top');
20721 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20726 this.picker().addClass('bottom');
20728 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20731 onFocus : function()
20733 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20737 onBlur : function()
20739 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20741 var d = this.inputEl().getValue();
20750 this.picker().show();
20751 this.picker().select('>.datepicker-months', true).first().show();
20755 this.fireEvent('show', this, this.date);
20760 if(this.isInline) {
20763 this.picker().hide();
20764 this.fireEvent('hide', this, this.date);
20768 onMousedown: function(e)
20770 e.stopPropagation();
20771 e.preventDefault();
20776 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20780 fireKey: function(e)
20782 if (!this.picker().isVisible()){
20783 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20794 e.preventDefault();
20798 dir = e.keyCode == 37 ? -1 : 1;
20800 this.vIndex = this.vIndex + dir;
20802 if(this.vIndex < 0){
20806 if(this.vIndex > 11){
20810 if(isNaN(this.vIndex)){
20814 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20820 dir = e.keyCode == 38 ? -1 : 1;
20822 this.vIndex = this.vIndex + dir * 4;
20824 if(this.vIndex < 0){
20828 if(this.vIndex > 11){
20832 if(isNaN(this.vIndex)){
20836 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20841 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20842 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20846 e.preventDefault();
20849 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20850 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20866 this.picker().remove();
20871 Roo.apply(Roo.bootstrap.MonthField, {
20890 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20891 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20896 Roo.apply(Roo.bootstrap.MonthField, {
20900 cls: 'datepicker dropdown-menu roo-dynamic',
20904 cls: 'datepicker-months',
20908 cls: 'table-condensed',
20910 Roo.bootstrap.DateField.content
20930 * @class Roo.bootstrap.CheckBox
20931 * @extends Roo.bootstrap.Input
20932 * Bootstrap CheckBox class
20934 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20935 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20936 * @cfg {String} boxLabel The text that appears beside the checkbox
20937 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20938 * @cfg {Boolean} checked initnal the element
20939 * @cfg {Boolean} inline inline the element (default false)
20940 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20941 * @cfg {String} tooltip label tooltip
20944 * Create a new CheckBox
20945 * @param {Object} config The config object
20948 Roo.bootstrap.CheckBox = function(config){
20949 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20954 * Fires when the element is checked or unchecked.
20955 * @param {Roo.bootstrap.CheckBox} this This input
20956 * @param {Boolean} checked The new checked value
20961 * Fires when the element is click.
20962 * @param {Roo.bootstrap.CheckBox} this This input
20969 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20971 inputType: 'checkbox',
20980 getAutoCreate : function()
20982 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20988 cfg.cls = 'form-group ' + this.inputType; //input-group
20991 cfg.cls += ' ' + this.inputType + '-inline';
20997 type : this.inputType,
20998 value : this.inputValue,
20999 cls : 'roo-' + this.inputType, //'form-box',
21000 placeholder : this.placeholder || ''
21004 if(this.inputType != 'radio'){
21008 cls : 'roo-hidden-value',
21009 value : this.checked ? this.inputValue : this.valueOff
21014 if (this.weight) { // Validity check?
21015 cfg.cls += " " + this.inputType + "-" + this.weight;
21018 if (this.disabled) {
21019 input.disabled=true;
21023 input.checked = this.checked;
21028 input.name = this.name;
21030 if(this.inputType != 'radio'){
21031 hidden.name = this.name;
21032 input.name = '_hidden_' + this.name;
21037 input.cls += ' input-' + this.size;
21042 ['xs','sm','md','lg'].map(function(size){
21043 if (settings[size]) {
21044 cfg.cls += ' col-' + size + '-' + settings[size];
21048 var inputblock = input;
21050 if (this.before || this.after) {
21053 cls : 'input-group',
21058 inputblock.cn.push({
21060 cls : 'input-group-addon',
21065 inputblock.cn.push(input);
21067 if(this.inputType != 'radio'){
21068 inputblock.cn.push(hidden);
21072 inputblock.cn.push({
21074 cls : 'input-group-addon',
21081 if (align ==='left' && this.fieldLabel.length) {
21082 // Roo.log("left and has label");
21087 cls : 'control-label',
21088 html : this.fieldLabel
21098 if(this.labelWidth > 12){
21099 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21102 if(this.labelWidth < 13 && this.labelmd == 0){
21103 this.labelmd = this.labelWidth;
21106 if(this.labellg > 0){
21107 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21108 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21111 if(this.labelmd > 0){
21112 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21113 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21116 if(this.labelsm > 0){
21117 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21118 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21121 if(this.labelxs > 0){
21122 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21123 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21126 } else if ( this.fieldLabel.length) {
21127 // Roo.log(" label");
21131 tag: this.boxLabel ? 'span' : 'label',
21133 cls: 'control-label box-input-label',
21134 //cls : 'input-group-addon',
21135 html : this.fieldLabel
21144 // Roo.log(" no label && no align");
21145 cfg.cn = [ inputblock ] ;
21151 var boxLabelCfg = {
21153 //'for': id, // box label is handled by onclick - so no for...
21155 html: this.boxLabel
21159 boxLabelCfg.tooltip = this.tooltip;
21162 cfg.cn.push(boxLabelCfg);
21165 if(this.inputType != 'radio'){
21166 cfg.cn.push(hidden);
21174 * return the real input element.
21176 inputEl: function ()
21178 return this.el.select('input.roo-' + this.inputType,true).first();
21180 hiddenEl: function ()
21182 return this.el.select('input.roo-hidden-value',true).first();
21185 labelEl: function()
21187 return this.el.select('label.control-label',true).first();
21189 /* depricated... */
21193 return this.labelEl();
21196 boxLabelEl: function()
21198 return this.el.select('label.box-label',true).first();
21201 initEvents : function()
21203 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21205 this.inputEl().on('click', this.onClick, this);
21207 if (this.boxLabel) {
21208 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21211 this.startValue = this.getValue();
21214 Roo.bootstrap.CheckBox.register(this);
21218 onClick : function(e)
21220 if(this.fireEvent('click', this, e) !== false){
21221 this.setChecked(!this.checked);
21226 setChecked : function(state,suppressEvent)
21228 this.startValue = this.getValue();
21230 if(this.inputType == 'radio'){
21232 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21233 e.dom.checked = false;
21236 this.inputEl().dom.checked = true;
21238 this.inputEl().dom.value = this.inputValue;
21240 if(suppressEvent !== true){
21241 this.fireEvent('check', this, true);
21249 this.checked = state;
21251 this.inputEl().dom.checked = state;
21254 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21256 if(suppressEvent !== true){
21257 this.fireEvent('check', this, state);
21263 getValue : function()
21265 if(this.inputType == 'radio'){
21266 return this.getGroupValue();
21269 return this.hiddenEl().dom.value;
21273 getGroupValue : function()
21275 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21279 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21282 setValue : function(v,suppressEvent)
21284 if(this.inputType == 'radio'){
21285 this.setGroupValue(v, suppressEvent);
21289 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21294 setGroupValue : function(v, suppressEvent)
21296 this.startValue = this.getValue();
21298 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21299 e.dom.checked = false;
21301 if(e.dom.value == v){
21302 e.dom.checked = true;
21306 if(suppressEvent !== true){
21307 this.fireEvent('check', this, true);
21315 validate : function()
21317 if(this.getVisibilityEl().hasClass('hidden')){
21323 (this.inputType == 'radio' && this.validateRadio()) ||
21324 (this.inputType == 'checkbox' && this.validateCheckbox())
21330 this.markInvalid();
21334 validateRadio : function()
21336 if(this.getVisibilityEl().hasClass('hidden')){
21340 if(this.allowBlank){
21346 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21347 if(!e.dom.checked){
21359 validateCheckbox : function()
21362 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21363 //return (this.getValue() == this.inputValue) ? true : false;
21366 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21374 for(var i in group){
21375 if(group[i].el.isVisible(true)){
21383 for(var i in group){
21388 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21395 * Mark this field as valid
21397 markValid : function()
21401 this.fireEvent('valid', this);
21403 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21406 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21413 if(this.inputType == 'radio'){
21414 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21415 var fg = e.findParent('.form-group', false, true);
21416 if (Roo.bootstrap.version == 3) {
21417 fg.removeClass([_this.invalidClass, _this.validClass]);
21418 fg.addClass(_this.validClass);
21420 fg.removeClass(['is-valid', 'is-invalid']);
21421 fg.addClass('is-valid');
21429 var fg = this.el.findParent('.form-group', false, true);
21430 if (Roo.bootstrap.version == 3) {
21431 fg.removeClass([this.invalidClass, this.validClass]);
21432 fg.addClass(this.validClass);
21434 fg.removeClass(['is-valid', 'is-invalid']);
21435 fg.addClass('is-valid');
21440 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21446 for(var i in group){
21447 var fg = group[i].el.findParent('.form-group', false, true);
21448 if (Roo.bootstrap.version == 3) {
21449 fg.removeClass([this.invalidClass, this.validClass]);
21450 fg.addClass(this.validClass);
21452 fg.removeClass(['is-valid', 'is-invalid']);
21453 fg.addClass('is-valid');
21459 * Mark this field as invalid
21460 * @param {String} msg The validation message
21462 markInvalid : function(msg)
21464 if(this.allowBlank){
21470 this.fireEvent('invalid', this, msg);
21472 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21475 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21479 label.markInvalid();
21482 if(this.inputType == 'radio'){
21484 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21485 var fg = e.findParent('.form-group', false, true);
21486 if (Roo.bootstrap.version == 3) {
21487 fg.removeClass([_this.invalidClass, _this.validClass]);
21488 fg.addClass(_this.invalidClass);
21490 fg.removeClass(['is-invalid', 'is-valid']);
21491 fg.addClass('is-invalid');
21499 var fg = this.el.findParent('.form-group', false, true);
21500 if (Roo.bootstrap.version == 3) {
21501 fg.removeClass([_this.invalidClass, _this.validClass]);
21502 fg.addClass(_this.invalidClass);
21504 fg.removeClass(['is-invalid', 'is-valid']);
21505 fg.addClass('is-invalid');
21510 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21516 for(var i in group){
21517 var fg = group[i].el.findParent('.form-group', false, true);
21518 if (Roo.bootstrap.version == 3) {
21519 fg.removeClass([_this.invalidClass, _this.validClass]);
21520 fg.addClass(_this.invalidClass);
21522 fg.removeClass(['is-invalid', 'is-valid']);
21523 fg.addClass('is-invalid');
21529 clearInvalid : function()
21531 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21533 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21535 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21537 if (label && label.iconEl) {
21538 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21539 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21543 disable : function()
21545 if(this.inputType != 'radio'){
21546 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21553 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21554 _this.getActionEl().addClass(this.disabledClass);
21555 e.dom.disabled = true;
21559 this.disabled = true;
21560 this.fireEvent("disable", this);
21564 enable : function()
21566 if(this.inputType != 'radio'){
21567 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21574 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21575 _this.getActionEl().removeClass(this.disabledClass);
21576 e.dom.disabled = false;
21580 this.disabled = false;
21581 this.fireEvent("enable", this);
21585 setBoxLabel : function(v)
21590 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21596 Roo.apply(Roo.bootstrap.CheckBox, {
21601 * register a CheckBox Group
21602 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21604 register : function(checkbox)
21606 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21607 this.groups[checkbox.groupId] = {};
21610 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21614 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21618 * fetch a CheckBox Group based on the group ID
21619 * @param {string} the group ID
21620 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21622 get: function(groupId) {
21623 if (typeof(this.groups[groupId]) == 'undefined') {
21627 return this.groups[groupId] ;
21640 * @class Roo.bootstrap.Radio
21641 * @extends Roo.bootstrap.Component
21642 * Bootstrap Radio class
21643 * @cfg {String} boxLabel - the label associated
21644 * @cfg {String} value - the value of radio
21647 * Create a new Radio
21648 * @param {Object} config The config object
21650 Roo.bootstrap.Radio = function(config){
21651 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21655 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21661 getAutoCreate : function()
21665 cls : 'form-group radio',
21670 html : this.boxLabel
21678 initEvents : function()
21680 this.parent().register(this);
21682 this.el.on('click', this.onClick, this);
21686 onClick : function(e)
21688 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21689 this.setChecked(true);
21693 setChecked : function(state, suppressEvent)
21695 this.parent().setValue(this.value, suppressEvent);
21699 setBoxLabel : function(v)
21704 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21719 * @class Roo.bootstrap.SecurePass
21720 * @extends Roo.bootstrap.Input
21721 * Bootstrap SecurePass class
21725 * Create a new SecurePass
21726 * @param {Object} config The config object
21729 Roo.bootstrap.SecurePass = function (config) {
21730 // these go here, so the translation tool can replace them..
21732 PwdEmpty: "Please type a password, and then retype it to confirm.",
21733 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21734 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21735 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21736 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21737 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21738 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21739 TooWeak: "Your password is Too Weak."
21741 this.meterLabel = "Password strength:";
21742 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21743 this.meterClass = [
21744 "roo-password-meter-tooweak",
21745 "roo-password-meter-weak",
21746 "roo-password-meter-medium",
21747 "roo-password-meter-strong",
21748 "roo-password-meter-grey"
21753 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21756 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21758 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21760 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21761 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21762 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21763 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21764 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21765 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21766 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21776 * @cfg {String/Object} Label for the strength meter (defaults to
21777 * 'Password strength:')
21782 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21783 * ['Weak', 'Medium', 'Strong'])
21786 pwdStrengths: false,
21799 initEvents: function ()
21801 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21803 if (this.el.is('input[type=password]') && Roo.isSafari) {
21804 this.el.on('keydown', this.SafariOnKeyDown, this);
21807 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21810 onRender: function (ct, position)
21812 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21813 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21814 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21816 this.trigger.createChild({
21821 cls: 'roo-password-meter-grey col-xs-12',
21824 //width: this.meterWidth + 'px'
21828 cls: 'roo-password-meter-text'
21834 if (this.hideTrigger) {
21835 this.trigger.setDisplayed(false);
21837 this.setSize(this.width || '', this.height || '');
21840 onDestroy: function ()
21842 if (this.trigger) {
21843 this.trigger.removeAllListeners();
21844 this.trigger.remove();
21847 this.wrap.remove();
21849 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21852 checkStrength: function ()
21854 var pwd = this.inputEl().getValue();
21855 if (pwd == this._lastPwd) {
21860 if (this.ClientSideStrongPassword(pwd)) {
21862 } else if (this.ClientSideMediumPassword(pwd)) {
21864 } else if (this.ClientSideWeakPassword(pwd)) {
21870 Roo.log('strength1: ' + strength);
21872 //var pm = this.trigger.child('div/div/div').dom;
21873 var pm = this.trigger.child('div/div');
21874 pm.removeClass(this.meterClass);
21875 pm.addClass(this.meterClass[strength]);
21878 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21880 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21882 this._lastPwd = pwd;
21886 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21888 this._lastPwd = '';
21890 var pm = this.trigger.child('div/div');
21891 pm.removeClass(this.meterClass);
21892 pm.addClass('roo-password-meter-grey');
21895 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21898 this.inputEl().dom.type='password';
21901 validateValue: function (value)
21904 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21907 if (value.length == 0) {
21908 if (this.allowBlank) {
21909 this.clearInvalid();
21913 this.markInvalid(this.errors.PwdEmpty);
21914 this.errorMsg = this.errors.PwdEmpty;
21922 if ('[\x21-\x7e]*'.match(value)) {
21923 this.markInvalid(this.errors.PwdBadChar);
21924 this.errorMsg = this.errors.PwdBadChar;
21927 if (value.length < 6) {
21928 this.markInvalid(this.errors.PwdShort);
21929 this.errorMsg = this.errors.PwdShort;
21932 if (value.length > 16) {
21933 this.markInvalid(this.errors.PwdLong);
21934 this.errorMsg = this.errors.PwdLong;
21938 if (this.ClientSideStrongPassword(value)) {
21940 } else if (this.ClientSideMediumPassword(value)) {
21942 } else if (this.ClientSideWeakPassword(value)) {
21949 if (strength < 2) {
21950 //this.markInvalid(this.errors.TooWeak);
21951 this.errorMsg = this.errors.TooWeak;
21956 console.log('strength2: ' + strength);
21958 //var pm = this.trigger.child('div/div/div').dom;
21960 var pm = this.trigger.child('div/div');
21961 pm.removeClass(this.meterClass);
21962 pm.addClass(this.meterClass[strength]);
21964 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21966 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21968 this.errorMsg = '';
21972 CharacterSetChecks: function (type)
21975 this.fResult = false;
21978 isctype: function (character, type)
21981 case this.kCapitalLetter:
21982 if (character >= 'A' && character <= 'Z') {
21987 case this.kSmallLetter:
21988 if (character >= 'a' && character <= 'z') {
21994 if (character >= '0' && character <= '9') {
21999 case this.kPunctuation:
22000 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
22011 IsLongEnough: function (pwd, size)
22013 return !(pwd == null || isNaN(size) || pwd.length < size);
22016 SpansEnoughCharacterSets: function (word, nb)
22018 if (!this.IsLongEnough(word, nb))
22023 var characterSetChecks = new Array(
22024 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
22025 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
22028 for (var index = 0; index < word.length; ++index) {
22029 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22030 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
22031 characterSetChecks[nCharSet].fResult = true;
22038 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
22039 if (characterSetChecks[nCharSet].fResult) {
22044 if (nCharSets < nb) {
22050 ClientSideStrongPassword: function (pwd)
22052 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22055 ClientSideMediumPassword: function (pwd)
22057 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22060 ClientSideWeakPassword: function (pwd)
22062 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22065 })//<script type="text/javascript">
22068 * Based Ext JS Library 1.1.1
22069 * Copyright(c) 2006-2007, Ext JS, LLC.
22075 * @class Roo.HtmlEditorCore
22076 * @extends Roo.Component
22077 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22079 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22082 Roo.HtmlEditorCore = function(config){
22085 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22090 * @event initialize
22091 * Fires when the editor is fully initialized (including the iframe)
22092 * @param {Roo.HtmlEditorCore} this
22097 * Fires when the editor is first receives the focus. Any insertion must wait
22098 * until after this event.
22099 * @param {Roo.HtmlEditorCore} this
22103 * @event beforesync
22104 * Fires before the textarea is updated with content from the editor iframe. Return false
22105 * to cancel the sync.
22106 * @param {Roo.HtmlEditorCore} this
22107 * @param {String} html
22111 * @event beforepush
22112 * Fires before the iframe editor is updated with content from the textarea. Return false
22113 * to cancel the push.
22114 * @param {Roo.HtmlEditorCore} this
22115 * @param {String} html
22120 * Fires when the textarea is updated with content from the editor iframe.
22121 * @param {Roo.HtmlEditorCore} this
22122 * @param {String} html
22127 * Fires when the iframe editor is updated with content from the textarea.
22128 * @param {Roo.HtmlEditorCore} this
22129 * @param {String} html
22134 * @event editorevent
22135 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22136 * @param {Roo.HtmlEditorCore} this
22142 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22144 // defaults : white / black...
22145 this.applyBlacklists();
22152 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22156 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22162 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22167 * @cfg {Number} height (in pixels)
22171 * @cfg {Number} width (in pixels)
22176 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22179 stylesheets: false,
22184 // private properties
22185 validationEvent : false,
22187 initialized : false,
22189 sourceEditMode : false,
22190 onFocus : Roo.emptyFn,
22192 hideMode:'offsets',
22196 // blacklist + whitelisted elements..
22203 * Protected method that will not generally be called directly. It
22204 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22205 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22207 getDocMarkup : function(){
22211 // inherit styels from page...??
22212 if (this.stylesheets === false) {
22214 Roo.get(document.head).select('style').each(function(node) {
22215 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22218 Roo.get(document.head).select('link').each(function(node) {
22219 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22222 } else if (!this.stylesheets.length) {
22224 st = '<style type="text/css">' +
22225 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22228 st = '<style type="text/css">' +
22233 st += '<style type="text/css">' +
22234 'IMG { cursor: pointer } ' +
22237 var cls = 'roo-htmleditor-body';
22239 if(this.bodyCls.length){
22240 cls += ' ' + this.bodyCls;
22243 return '<html><head>' + st +
22244 //<style type="text/css">' +
22245 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22247 ' </head><body class="' + cls + '"></body></html>';
22251 onRender : function(ct, position)
22254 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22255 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22258 this.el.dom.style.border = '0 none';
22259 this.el.dom.setAttribute('tabIndex', -1);
22260 this.el.addClass('x-hidden hide');
22264 if(Roo.isIE){ // fix IE 1px bogus margin
22265 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22269 this.frameId = Roo.id();
22273 var iframe = this.owner.wrap.createChild({
22275 cls: 'form-control', // bootstrap..
22277 name: this.frameId,
22278 frameBorder : 'no',
22279 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22284 this.iframe = iframe.dom;
22286 this.assignDocWin();
22288 this.doc.designMode = 'on';
22291 this.doc.write(this.getDocMarkup());
22295 var task = { // must defer to wait for browser to be ready
22297 //console.log("run task?" + this.doc.readyState);
22298 this.assignDocWin();
22299 if(this.doc.body || this.doc.readyState == 'complete'){
22301 this.doc.designMode="on";
22305 Roo.TaskMgr.stop(task);
22306 this.initEditor.defer(10, this);
22313 Roo.TaskMgr.start(task);
22318 onResize : function(w, h)
22320 Roo.log('resize: ' +w + ',' + h );
22321 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22325 if(typeof w == 'number'){
22327 this.iframe.style.width = w + 'px';
22329 if(typeof h == 'number'){
22331 this.iframe.style.height = h + 'px';
22333 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22340 * Toggles the editor between standard and source edit mode.
22341 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22343 toggleSourceEdit : function(sourceEditMode){
22345 this.sourceEditMode = sourceEditMode === true;
22347 if(this.sourceEditMode){
22349 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22352 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22353 //this.iframe.className = '';
22356 //this.setSize(this.owner.wrap.getSize());
22357 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22364 * Protected method that will not generally be called directly. If you need/want
22365 * custom HTML cleanup, this is the method you should override.
22366 * @param {String} html The HTML to be cleaned
22367 * return {String} The cleaned HTML
22369 cleanHtml : function(html){
22370 html = String(html);
22371 if(html.length > 5){
22372 if(Roo.isSafari){ // strip safari nonsense
22373 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22376 if(html == ' '){
22383 * HTML Editor -> Textarea
22384 * Protected method that will not generally be called directly. Syncs the contents
22385 * of the editor iframe with the textarea.
22387 syncValue : function(){
22388 if(this.initialized){
22389 var bd = (this.doc.body || this.doc.documentElement);
22390 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22391 var html = bd.innerHTML;
22393 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22394 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22396 html = '<div style="'+m[0]+'">' + html + '</div>';
22399 html = this.cleanHtml(html);
22400 // fix up the special chars.. normaly like back quotes in word...
22401 // however we do not want to do this with chinese..
22402 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22403 var cc = b.charCodeAt();
22405 (cc >= 0x4E00 && cc < 0xA000 ) ||
22406 (cc >= 0x3400 && cc < 0x4E00 ) ||
22407 (cc >= 0xf900 && cc < 0xfb00 )
22413 if(this.owner.fireEvent('beforesync', this, html) !== false){
22414 this.el.dom.value = html;
22415 this.owner.fireEvent('sync', this, html);
22421 * Protected method that will not generally be called directly. Pushes the value of the textarea
22422 * into the iframe editor.
22424 pushValue : function(){
22425 if(this.initialized){
22426 var v = this.el.dom.value.trim();
22428 // if(v.length < 1){
22432 if(this.owner.fireEvent('beforepush', this, v) !== false){
22433 var d = (this.doc.body || this.doc.documentElement);
22435 this.cleanUpPaste();
22436 this.el.dom.value = d.innerHTML;
22437 this.owner.fireEvent('push', this, v);
22443 deferFocus : function(){
22444 this.focus.defer(10, this);
22448 focus : function(){
22449 if(this.win && !this.sourceEditMode){
22456 assignDocWin: function()
22458 var iframe = this.iframe;
22461 this.doc = iframe.contentWindow.document;
22462 this.win = iframe.contentWindow;
22464 // if (!Roo.get(this.frameId)) {
22467 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22468 // this.win = Roo.get(this.frameId).dom.contentWindow;
22470 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22474 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22475 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22480 initEditor : function(){
22481 //console.log("INIT EDITOR");
22482 this.assignDocWin();
22486 this.doc.designMode="on";
22488 this.doc.write(this.getDocMarkup());
22491 var dbody = (this.doc.body || this.doc.documentElement);
22492 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22493 // this copies styles from the containing element into thsi one..
22494 // not sure why we need all of this..
22495 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22497 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22498 //ss['background-attachment'] = 'fixed'; // w3c
22499 dbody.bgProperties = 'fixed'; // ie
22500 //Roo.DomHelper.applyStyles(dbody, ss);
22501 Roo.EventManager.on(this.doc, {
22502 //'mousedown': this.onEditorEvent,
22503 'mouseup': this.onEditorEvent,
22504 'dblclick': this.onEditorEvent,
22505 'click': this.onEditorEvent,
22506 'keyup': this.onEditorEvent,
22511 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22513 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22514 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22516 this.initialized = true;
22518 this.owner.fireEvent('initialize', this);
22523 onDestroy : function(){
22529 //for (var i =0; i < this.toolbars.length;i++) {
22530 // // fixme - ask toolbars for heights?
22531 // this.toolbars[i].onDestroy();
22534 //this.wrap.dom.innerHTML = '';
22535 //this.wrap.remove();
22540 onFirstFocus : function(){
22542 this.assignDocWin();
22545 this.activated = true;
22548 if(Roo.isGecko){ // prevent silly gecko errors
22550 var s = this.win.getSelection();
22551 if(!s.focusNode || s.focusNode.nodeType != 3){
22552 var r = s.getRangeAt(0);
22553 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22558 this.execCmd('useCSS', true);
22559 this.execCmd('styleWithCSS', false);
22562 this.owner.fireEvent('activate', this);
22566 adjustFont: function(btn){
22567 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22568 //if(Roo.isSafari){ // safari
22571 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22572 if(Roo.isSafari){ // safari
22573 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22574 v = (v < 10) ? 10 : v;
22575 v = (v > 48) ? 48 : v;
22576 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22581 v = Math.max(1, v+adjust);
22583 this.execCmd('FontSize', v );
22586 onEditorEvent : function(e)
22588 this.owner.fireEvent('editorevent', this, e);
22589 // this.updateToolbar();
22590 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22593 insertTag : function(tg)
22595 // could be a bit smarter... -> wrap the current selected tRoo..
22596 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22598 range = this.createRange(this.getSelection());
22599 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22600 wrappingNode.appendChild(range.extractContents());
22601 range.insertNode(wrappingNode);
22608 this.execCmd("formatblock", tg);
22612 insertText : function(txt)
22616 var range = this.createRange();
22617 range.deleteContents();
22618 //alert(Sender.getAttribute('label'));
22620 range.insertNode(this.doc.createTextNode(txt));
22626 * Executes a Midas editor command on the editor document and performs necessary focus and
22627 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22628 * @param {String} cmd The Midas command
22629 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22631 relayCmd : function(cmd, value){
22633 this.execCmd(cmd, value);
22634 this.owner.fireEvent('editorevent', this);
22635 //this.updateToolbar();
22636 this.owner.deferFocus();
22640 * Executes a Midas editor command directly on the editor document.
22641 * For visual commands, you should use {@link #relayCmd} instead.
22642 * <b>This should only be called after the editor is initialized.</b>
22643 * @param {String} cmd The Midas command
22644 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22646 execCmd : function(cmd, value){
22647 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22654 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22656 * @param {String} text | dom node..
22658 insertAtCursor : function(text)
22661 if(!this.activated){
22667 var r = this.doc.selection.createRange();
22678 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22682 // from jquery ui (MIT licenced)
22684 var win = this.win;
22686 if (win.getSelection && win.getSelection().getRangeAt) {
22687 range = win.getSelection().getRangeAt(0);
22688 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22689 range.insertNode(node);
22690 } else if (win.document.selection && win.document.selection.createRange) {
22691 // no firefox support
22692 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22693 win.document.selection.createRange().pasteHTML(txt);
22695 // no firefox support
22696 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22697 this.execCmd('InsertHTML', txt);
22706 mozKeyPress : function(e){
22708 var c = e.getCharCode(), cmd;
22711 c = String.fromCharCode(c).toLowerCase();
22725 this.cleanUpPaste.defer(100, this);
22733 e.preventDefault();
22741 fixKeys : function(){ // load time branching for fastest keydown performance
22743 return function(e){
22744 var k = e.getKey(), r;
22747 r = this.doc.selection.createRange();
22750 r.pasteHTML('    ');
22757 r = this.doc.selection.createRange();
22759 var target = r.parentElement();
22760 if(!target || target.tagName.toLowerCase() != 'li'){
22762 r.pasteHTML('<br />');
22768 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22769 this.cleanUpPaste.defer(100, this);
22775 }else if(Roo.isOpera){
22776 return function(e){
22777 var k = e.getKey();
22781 this.execCmd('InsertHTML','    ');
22784 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22785 this.cleanUpPaste.defer(100, this);
22790 }else if(Roo.isSafari){
22791 return function(e){
22792 var k = e.getKey();
22796 this.execCmd('InsertText','\t');
22800 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22801 this.cleanUpPaste.defer(100, this);
22809 getAllAncestors: function()
22811 var p = this.getSelectedNode();
22814 a.push(p); // push blank onto stack..
22815 p = this.getParentElement();
22819 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22823 a.push(this.doc.body);
22827 lastSelNode : false,
22830 getSelection : function()
22832 this.assignDocWin();
22833 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22836 getSelectedNode: function()
22838 // this may only work on Gecko!!!
22840 // should we cache this!!!!
22845 var range = this.createRange(this.getSelection()).cloneRange();
22848 var parent = range.parentElement();
22850 var testRange = range.duplicate();
22851 testRange.moveToElementText(parent);
22852 if (testRange.inRange(range)) {
22855 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22858 parent = parent.parentElement;
22863 // is ancestor a text element.
22864 var ac = range.commonAncestorContainer;
22865 if (ac.nodeType == 3) {
22866 ac = ac.parentNode;
22869 var ar = ac.childNodes;
22872 var other_nodes = [];
22873 var has_other_nodes = false;
22874 for (var i=0;i<ar.length;i++) {
22875 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22878 // fullly contained node.
22880 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22885 // probably selected..
22886 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22887 other_nodes.push(ar[i]);
22891 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22896 has_other_nodes = true;
22898 if (!nodes.length && other_nodes.length) {
22899 nodes= other_nodes;
22901 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22907 createRange: function(sel)
22909 // this has strange effects when using with
22910 // top toolbar - not sure if it's a great idea.
22911 //this.editor.contentWindow.focus();
22912 if (typeof sel != "undefined") {
22914 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22916 return this.doc.createRange();
22919 return this.doc.createRange();
22922 getParentElement: function()
22925 this.assignDocWin();
22926 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22928 var range = this.createRange(sel);
22931 var p = range.commonAncestorContainer;
22932 while (p.nodeType == 3) { // text node
22943 * Range intersection.. the hard stuff...
22947 * [ -- selected range --- ]
22951 * if end is before start or hits it. fail.
22952 * if start is after end or hits it fail.
22954 * if either hits (but other is outside. - then it's not
22960 // @see http://www.thismuchiknow.co.uk/?p=64.
22961 rangeIntersectsNode : function(range, node)
22963 var nodeRange = node.ownerDocument.createRange();
22965 nodeRange.selectNode(node);
22967 nodeRange.selectNodeContents(node);
22970 var rangeStartRange = range.cloneRange();
22971 rangeStartRange.collapse(true);
22973 var rangeEndRange = range.cloneRange();
22974 rangeEndRange.collapse(false);
22976 var nodeStartRange = nodeRange.cloneRange();
22977 nodeStartRange.collapse(true);
22979 var nodeEndRange = nodeRange.cloneRange();
22980 nodeEndRange.collapse(false);
22982 return rangeStartRange.compareBoundaryPoints(
22983 Range.START_TO_START, nodeEndRange) == -1 &&
22984 rangeEndRange.compareBoundaryPoints(
22985 Range.START_TO_START, nodeStartRange) == 1;
22989 rangeCompareNode : function(range, node)
22991 var nodeRange = node.ownerDocument.createRange();
22993 nodeRange.selectNode(node);
22995 nodeRange.selectNodeContents(node);
22999 range.collapse(true);
23001 nodeRange.collapse(true);
23003 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
23004 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
23006 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
23008 var nodeIsBefore = ss == 1;
23009 var nodeIsAfter = ee == -1;
23011 if (nodeIsBefore && nodeIsAfter) {
23014 if (!nodeIsBefore && nodeIsAfter) {
23015 return 1; //right trailed.
23018 if (nodeIsBefore && !nodeIsAfter) {
23019 return 2; // left trailed.
23025 // private? - in a new class?
23026 cleanUpPaste : function()
23028 // cleans up the whole document..
23029 Roo.log('cleanuppaste');
23031 this.cleanUpChildren(this.doc.body);
23032 var clean = this.cleanWordChars(this.doc.body.innerHTML);
23033 if (clean != this.doc.body.innerHTML) {
23034 this.doc.body.innerHTML = clean;
23039 cleanWordChars : function(input) {// change the chars to hex code
23040 var he = Roo.HtmlEditorCore;
23042 var output = input;
23043 Roo.each(he.swapCodes, function(sw) {
23044 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
23046 output = output.replace(swapper, sw[1]);
23053 cleanUpChildren : function (n)
23055 if (!n.childNodes.length) {
23058 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23059 this.cleanUpChild(n.childNodes[i]);
23066 cleanUpChild : function (node)
23069 //console.log(node);
23070 if (node.nodeName == "#text") {
23071 // clean up silly Windows -- stuff?
23074 if (node.nodeName == "#comment") {
23075 node.parentNode.removeChild(node);
23076 // clean up silly Windows -- stuff?
23079 var lcname = node.tagName.toLowerCase();
23080 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23081 // whitelist of tags..
23083 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23085 node.parentNode.removeChild(node);
23090 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23092 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23093 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23095 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23096 // remove_keep_children = true;
23099 if (remove_keep_children) {
23100 this.cleanUpChildren(node);
23101 // inserts everything just before this node...
23102 while (node.childNodes.length) {
23103 var cn = node.childNodes[0];
23104 node.removeChild(cn);
23105 node.parentNode.insertBefore(cn, node);
23107 node.parentNode.removeChild(node);
23111 if (!node.attributes || !node.attributes.length) {
23112 this.cleanUpChildren(node);
23116 function cleanAttr(n,v)
23119 if (v.match(/^\./) || v.match(/^\//)) {
23122 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23125 if (v.match(/^#/)) {
23128 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23129 node.removeAttribute(n);
23133 var cwhite = this.cwhite;
23134 var cblack = this.cblack;
23136 function cleanStyle(n,v)
23138 if (v.match(/expression/)) { //XSS?? should we even bother..
23139 node.removeAttribute(n);
23143 var parts = v.split(/;/);
23146 Roo.each(parts, function(p) {
23147 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23151 var l = p.split(':').shift().replace(/\s+/g,'');
23152 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23154 if ( cwhite.length && cblack.indexOf(l) > -1) {
23155 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23156 //node.removeAttribute(n);
23160 // only allow 'c whitelisted system attributes'
23161 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23162 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23163 //node.removeAttribute(n);
23173 if (clean.length) {
23174 node.setAttribute(n, clean.join(';'));
23176 node.removeAttribute(n);
23182 for (var i = node.attributes.length-1; i > -1 ; i--) {
23183 var a = node.attributes[i];
23186 if (a.name.toLowerCase().substr(0,2)=='on') {
23187 node.removeAttribute(a.name);
23190 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23191 node.removeAttribute(a.name);
23194 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23195 cleanAttr(a.name,a.value); // fixme..
23198 if (a.name == 'style') {
23199 cleanStyle(a.name,a.value);
23202 /// clean up MS crap..
23203 // tecnically this should be a list of valid class'es..
23206 if (a.name == 'class') {
23207 if (a.value.match(/^Mso/)) {
23208 node.className = '';
23211 if (a.value.match(/^body$/)) {
23212 node.className = '';
23223 this.cleanUpChildren(node);
23229 * Clean up MS wordisms...
23231 cleanWord : function(node)
23236 this.cleanWord(this.doc.body);
23239 if (node.nodeName == "#text") {
23240 // clean up silly Windows -- stuff?
23243 if (node.nodeName == "#comment") {
23244 node.parentNode.removeChild(node);
23245 // clean up silly Windows -- stuff?
23249 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23250 node.parentNode.removeChild(node);
23254 // remove - but keep children..
23255 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23256 while (node.childNodes.length) {
23257 var cn = node.childNodes[0];
23258 node.removeChild(cn);
23259 node.parentNode.insertBefore(cn, node);
23261 node.parentNode.removeChild(node);
23262 this.iterateChildren(node, this.cleanWord);
23266 if (node.className.length) {
23268 var cn = node.className.split(/\W+/);
23270 Roo.each(cn, function(cls) {
23271 if (cls.match(/Mso[a-zA-Z]+/)) {
23276 node.className = cna.length ? cna.join(' ') : '';
23278 node.removeAttribute("class");
23282 if (node.hasAttribute("lang")) {
23283 node.removeAttribute("lang");
23286 if (node.hasAttribute("style")) {
23288 var styles = node.getAttribute("style").split(";");
23290 Roo.each(styles, function(s) {
23291 if (!s.match(/:/)) {
23294 var kv = s.split(":");
23295 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23298 // what ever is left... we allow.
23301 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23302 if (!nstyle.length) {
23303 node.removeAttribute('style');
23306 this.iterateChildren(node, this.cleanWord);
23312 * iterateChildren of a Node, calling fn each time, using this as the scole..
23313 * @param {DomNode} node node to iterate children of.
23314 * @param {Function} fn method of this class to call on each item.
23316 iterateChildren : function(node, fn)
23318 if (!node.childNodes.length) {
23321 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23322 fn.call(this, node.childNodes[i])
23328 * cleanTableWidths.
23330 * Quite often pasting from word etc.. results in tables with column and widths.
23331 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23334 cleanTableWidths : function(node)
23339 this.cleanTableWidths(this.doc.body);
23344 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23347 Roo.log(node.tagName);
23348 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23349 this.iterateChildren(node, this.cleanTableWidths);
23352 if (node.hasAttribute('width')) {
23353 node.removeAttribute('width');
23357 if (node.hasAttribute("style")) {
23360 var styles = node.getAttribute("style").split(";");
23362 Roo.each(styles, function(s) {
23363 if (!s.match(/:/)) {
23366 var kv = s.split(":");
23367 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23370 // what ever is left... we allow.
23373 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23374 if (!nstyle.length) {
23375 node.removeAttribute('style');
23379 this.iterateChildren(node, this.cleanTableWidths);
23387 domToHTML : function(currentElement, depth, nopadtext) {
23389 depth = depth || 0;
23390 nopadtext = nopadtext || false;
23392 if (!currentElement) {
23393 return this.domToHTML(this.doc.body);
23396 //Roo.log(currentElement);
23398 var allText = false;
23399 var nodeName = currentElement.nodeName;
23400 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23402 if (nodeName == '#text') {
23404 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23409 if (nodeName != 'BODY') {
23412 // Prints the node tagName, such as <A>, <IMG>, etc
23415 for(i = 0; i < currentElement.attributes.length;i++) {
23417 var aname = currentElement.attributes.item(i).name;
23418 if (!currentElement.attributes.item(i).value.length) {
23421 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23424 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23433 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23436 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23441 // Traverse the tree
23443 var currentElementChild = currentElement.childNodes.item(i);
23444 var allText = true;
23445 var innerHTML = '';
23447 while (currentElementChild) {
23448 // Formatting code (indent the tree so it looks nice on the screen)
23449 var nopad = nopadtext;
23450 if (lastnode == 'SPAN') {
23454 if (currentElementChild.nodeName == '#text') {
23455 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23456 toadd = nopadtext ? toadd : toadd.trim();
23457 if (!nopad && toadd.length > 80) {
23458 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23460 innerHTML += toadd;
23463 currentElementChild = currentElement.childNodes.item(i);
23469 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23471 // Recursively traverse the tree structure of the child node
23472 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23473 lastnode = currentElementChild.nodeName;
23475 currentElementChild=currentElement.childNodes.item(i);
23481 // The remaining code is mostly for formatting the tree
23482 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23487 ret+= "</"+tagName+">";
23493 applyBlacklists : function()
23495 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23496 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23500 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23501 if (b.indexOf(tag) > -1) {
23504 this.white.push(tag);
23508 Roo.each(w, function(tag) {
23509 if (b.indexOf(tag) > -1) {
23512 if (this.white.indexOf(tag) > -1) {
23515 this.white.push(tag);
23520 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23521 if (w.indexOf(tag) > -1) {
23524 this.black.push(tag);
23528 Roo.each(b, function(tag) {
23529 if (w.indexOf(tag) > -1) {
23532 if (this.black.indexOf(tag) > -1) {
23535 this.black.push(tag);
23540 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23541 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23545 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23546 if (b.indexOf(tag) > -1) {
23549 this.cwhite.push(tag);
23553 Roo.each(w, function(tag) {
23554 if (b.indexOf(tag) > -1) {
23557 if (this.cwhite.indexOf(tag) > -1) {
23560 this.cwhite.push(tag);
23565 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23566 if (w.indexOf(tag) > -1) {
23569 this.cblack.push(tag);
23573 Roo.each(b, function(tag) {
23574 if (w.indexOf(tag) > -1) {
23577 if (this.cblack.indexOf(tag) > -1) {
23580 this.cblack.push(tag);
23585 setStylesheets : function(stylesheets)
23587 if(typeof(stylesheets) == 'string'){
23588 Roo.get(this.iframe.contentDocument.head).createChild({
23590 rel : 'stylesheet',
23599 Roo.each(stylesheets, function(s) {
23604 Roo.get(_this.iframe.contentDocument.head).createChild({
23606 rel : 'stylesheet',
23615 removeStylesheets : function()
23619 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23624 setStyle : function(style)
23626 Roo.get(this.iframe.contentDocument.head).createChild({
23635 // hide stuff that is not compatible
23649 * @event specialkey
23653 * @cfg {String} fieldClass @hide
23656 * @cfg {String} focusClass @hide
23659 * @cfg {String} autoCreate @hide
23662 * @cfg {String} inputType @hide
23665 * @cfg {String} invalidClass @hide
23668 * @cfg {String} invalidText @hide
23671 * @cfg {String} msgFx @hide
23674 * @cfg {String} validateOnBlur @hide
23678 Roo.HtmlEditorCore.white = [
23679 'area', 'br', 'img', 'input', 'hr', 'wbr',
23681 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23682 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23683 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23684 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23685 'table', 'ul', 'xmp',
23687 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23690 'dir', 'menu', 'ol', 'ul', 'dl',
23696 Roo.HtmlEditorCore.black = [
23697 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23699 'base', 'basefont', 'bgsound', 'blink', 'body',
23700 'frame', 'frameset', 'head', 'html', 'ilayer',
23701 'iframe', 'layer', 'link', 'meta', 'object',
23702 'script', 'style' ,'title', 'xml' // clean later..
23704 Roo.HtmlEditorCore.clean = [
23705 'script', 'style', 'title', 'xml'
23707 Roo.HtmlEditorCore.remove = [
23712 Roo.HtmlEditorCore.ablack = [
23716 Roo.HtmlEditorCore.aclean = [
23717 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23721 Roo.HtmlEditorCore.pwhite= [
23722 'http', 'https', 'mailto'
23725 // white listed style attributes.
23726 Roo.HtmlEditorCore.cwhite= [
23727 // 'text-align', /// default is to allow most things..
23733 // black listed style attributes.
23734 Roo.HtmlEditorCore.cblack= [
23735 // 'font-size' -- this can be set by the project
23739 Roo.HtmlEditorCore.swapCodes =[
23758 * @class Roo.bootstrap.HtmlEditor
23759 * @extends Roo.bootstrap.TextArea
23760 * Bootstrap HtmlEditor class
23763 * Create a new HtmlEditor
23764 * @param {Object} config The config object
23767 Roo.bootstrap.HtmlEditor = function(config){
23768 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23769 if (!this.toolbars) {
23770 this.toolbars = [];
23773 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23776 * @event initialize
23777 * Fires when the editor is fully initialized (including the iframe)
23778 * @param {HtmlEditor} this
23783 * Fires when the editor is first receives the focus. Any insertion must wait
23784 * until after this event.
23785 * @param {HtmlEditor} this
23789 * @event beforesync
23790 * Fires before the textarea is updated with content from the editor iframe. Return false
23791 * to cancel the sync.
23792 * @param {HtmlEditor} this
23793 * @param {String} html
23797 * @event beforepush
23798 * Fires before the iframe editor is updated with content from the textarea. Return false
23799 * to cancel the push.
23800 * @param {HtmlEditor} this
23801 * @param {String} html
23806 * Fires when the textarea is updated with content from the editor iframe.
23807 * @param {HtmlEditor} this
23808 * @param {String} html
23813 * Fires when the iframe editor is updated with content from the textarea.
23814 * @param {HtmlEditor} this
23815 * @param {String} html
23819 * @event editmodechange
23820 * Fires when the editor switches edit modes
23821 * @param {HtmlEditor} this
23822 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23824 editmodechange: true,
23826 * @event editorevent
23827 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23828 * @param {HtmlEditor} this
23832 * @event firstfocus
23833 * Fires when on first focus - needed by toolbars..
23834 * @param {HtmlEditor} this
23839 * Auto save the htmlEditor value as a file into Events
23840 * @param {HtmlEditor} this
23844 * @event savedpreview
23845 * preview the saved version of htmlEditor
23846 * @param {HtmlEditor} this
23853 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23857 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23862 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23867 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23872 * @cfg {Number} height (in pixels)
23876 * @cfg {Number} width (in pixels)
23881 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23884 stylesheets: false,
23889 // private properties
23890 validationEvent : false,
23892 initialized : false,
23895 onFocus : Roo.emptyFn,
23897 hideMode:'offsets',
23899 tbContainer : false,
23903 toolbarContainer :function() {
23904 return this.wrap.select('.x-html-editor-tb',true).first();
23908 * Protected method that will not generally be called directly. It
23909 * is called when the editor creates its toolbar. Override this method if you need to
23910 * add custom toolbar buttons.
23911 * @param {HtmlEditor} editor
23913 createToolbar : function(){
23914 Roo.log('renewing');
23915 Roo.log("create toolbars");
23917 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23918 this.toolbars[0].render(this.toolbarContainer());
23922 // if (!editor.toolbars || !editor.toolbars.length) {
23923 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23926 // for (var i =0 ; i < editor.toolbars.length;i++) {
23927 // editor.toolbars[i] = Roo.factory(
23928 // typeof(editor.toolbars[i]) == 'string' ?
23929 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23930 // Roo.bootstrap.HtmlEditor);
23931 // editor.toolbars[i].init(editor);
23937 onRender : function(ct, position)
23939 // Roo.log("Call onRender: " + this.xtype);
23941 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23943 this.wrap = this.inputEl().wrap({
23944 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23947 this.editorcore.onRender(ct, position);
23949 if (this.resizable) {
23950 this.resizeEl = new Roo.Resizable(this.wrap, {
23954 minHeight : this.height,
23955 height: this.height,
23956 handles : this.resizable,
23959 resize : function(r, w, h) {
23960 _t.onResize(w,h); // -something
23966 this.createToolbar(this);
23969 if(!this.width && this.resizable){
23970 this.setSize(this.wrap.getSize());
23972 if (this.resizeEl) {
23973 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23974 // should trigger onReize..
23980 onResize : function(w, h)
23982 Roo.log('resize: ' +w + ',' + h );
23983 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23987 if(this.inputEl() ){
23988 if(typeof w == 'number'){
23989 var aw = w - this.wrap.getFrameWidth('lr');
23990 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23993 if(typeof h == 'number'){
23994 var tbh = -11; // fixme it needs to tool bar size!
23995 for (var i =0; i < this.toolbars.length;i++) {
23996 // fixme - ask toolbars for heights?
23997 tbh += this.toolbars[i].el.getHeight();
23998 //if (this.toolbars[i].footer) {
23999 // tbh += this.toolbars[i].footer.el.getHeight();
24007 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24008 ah -= 5; // knock a few pixes off for look..
24009 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
24013 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
24014 this.editorcore.onResize(ew,eh);
24019 * Toggles the editor between standard and source edit mode.
24020 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24022 toggleSourceEdit : function(sourceEditMode)
24024 this.editorcore.toggleSourceEdit(sourceEditMode);
24026 if(this.editorcore.sourceEditMode){
24027 Roo.log('editor - showing textarea');
24030 // Roo.log(this.syncValue());
24032 this.inputEl().removeClass(['hide', 'x-hidden']);
24033 this.inputEl().dom.removeAttribute('tabIndex');
24034 this.inputEl().focus();
24036 Roo.log('editor - hiding textarea');
24038 // Roo.log(this.pushValue());
24041 this.inputEl().addClass(['hide', 'x-hidden']);
24042 this.inputEl().dom.setAttribute('tabIndex', -1);
24043 //this.deferFocus();
24046 if(this.resizable){
24047 this.setSize(this.wrap.getSize());
24050 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24053 // private (for BoxComponent)
24054 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24056 // private (for BoxComponent)
24057 getResizeEl : function(){
24061 // private (for BoxComponent)
24062 getPositionEl : function(){
24067 initEvents : function(){
24068 this.originalValue = this.getValue();
24072 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24075 // markInvalid : Roo.emptyFn,
24077 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24080 // clearInvalid : Roo.emptyFn,
24082 setValue : function(v){
24083 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24084 this.editorcore.pushValue();
24089 deferFocus : function(){
24090 this.focus.defer(10, this);
24094 focus : function(){
24095 this.editorcore.focus();
24101 onDestroy : function(){
24107 for (var i =0; i < this.toolbars.length;i++) {
24108 // fixme - ask toolbars for heights?
24109 this.toolbars[i].onDestroy();
24112 this.wrap.dom.innerHTML = '';
24113 this.wrap.remove();
24118 onFirstFocus : function(){
24119 //Roo.log("onFirstFocus");
24120 this.editorcore.onFirstFocus();
24121 for (var i =0; i < this.toolbars.length;i++) {
24122 this.toolbars[i].onFirstFocus();
24128 syncValue : function()
24130 this.editorcore.syncValue();
24133 pushValue : function()
24135 this.editorcore.pushValue();
24139 // hide stuff that is not compatible
24153 * @event specialkey
24157 * @cfg {String} fieldClass @hide
24160 * @cfg {String} focusClass @hide
24163 * @cfg {String} autoCreate @hide
24166 * @cfg {String} inputType @hide
24170 * @cfg {String} invalidText @hide
24173 * @cfg {String} msgFx @hide
24176 * @cfg {String} validateOnBlur @hide
24185 Roo.namespace('Roo.bootstrap.htmleditor');
24187 * @class Roo.bootstrap.HtmlEditorToolbar1
24193 new Roo.bootstrap.HtmlEditor({
24196 new Roo.bootstrap.HtmlEditorToolbar1({
24197 disable : { fonts: 1 , format: 1, ..., ... , ...],
24203 * @cfg {Object} disable List of elements to disable..
24204 * @cfg {Array} btns List of additional buttons.
24208 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24211 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24214 Roo.apply(this, config);
24216 // default disabled, based on 'good practice'..
24217 this.disable = this.disable || {};
24218 Roo.applyIf(this.disable, {
24221 specialElements : true
24223 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24225 this.editor = config.editor;
24226 this.editorcore = config.editor.editorcore;
24228 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24230 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24231 // dont call parent... till later.
24233 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24238 editorcore : false,
24243 "h1","h2","h3","h4","h5","h6",
24245 "abbr", "acronym", "address", "cite", "samp", "var",
24249 onRender : function(ct, position)
24251 // Roo.log("Call onRender: " + this.xtype);
24253 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24255 this.el.dom.style.marginBottom = '0';
24257 var editorcore = this.editorcore;
24258 var editor= this.editor;
24261 var btn = function(id,cmd , toggle, handler, html){
24263 var event = toggle ? 'toggle' : 'click';
24268 xns: Roo.bootstrap,
24272 enableToggle:toggle !== false,
24274 pressed : toggle ? false : null,
24277 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24278 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24284 // var cb_box = function...
24289 xns: Roo.bootstrap,
24294 xns: Roo.bootstrap,
24298 Roo.each(this.formats, function(f) {
24299 style.menu.items.push({
24301 xns: Roo.bootstrap,
24302 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24307 editorcore.insertTag(this.tagname);
24314 children.push(style);
24316 btn('bold',false,true);
24317 btn('italic',false,true);
24318 btn('align-left', 'justifyleft',true);
24319 btn('align-center', 'justifycenter',true);
24320 btn('align-right' , 'justifyright',true);
24321 btn('link', false, false, function(btn) {
24322 //Roo.log("create link?");
24323 var url = prompt(this.createLinkText, this.defaultLinkValue);
24324 if(url && url != 'http:/'+'/'){
24325 this.editorcore.relayCmd('createlink', url);
24328 btn('list','insertunorderedlist',true);
24329 btn('pencil', false,true, function(btn){
24331 this.toggleSourceEdit(btn.pressed);
24334 if (this.editor.btns.length > 0) {
24335 for (var i = 0; i<this.editor.btns.length; i++) {
24336 children.push(this.editor.btns[i]);
24344 xns: Roo.bootstrap,
24349 xns: Roo.bootstrap,
24354 cog.menu.items.push({
24356 xns: Roo.bootstrap,
24357 html : Clean styles,
24362 editorcore.insertTag(this.tagname);
24371 this.xtype = 'NavSimplebar';
24373 for(var i=0;i< children.length;i++) {
24375 this.buttons.add(this.addxtypeChild(children[i]));
24379 editor.on('editorevent', this.updateToolbar, this);
24381 onBtnClick : function(id)
24383 this.editorcore.relayCmd(id);
24384 this.editorcore.focus();
24388 * Protected method that will not generally be called directly. It triggers
24389 * a toolbar update by reading the markup state of the current selection in the editor.
24391 updateToolbar: function(){
24393 if(!this.editorcore.activated){
24394 this.editor.onFirstFocus(); // is this neeed?
24398 var btns = this.buttons;
24399 var doc = this.editorcore.doc;
24400 btns.get('bold').setActive(doc.queryCommandState('bold'));
24401 btns.get('italic').setActive(doc.queryCommandState('italic'));
24402 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24404 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24405 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24406 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24408 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24409 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24412 var ans = this.editorcore.getAllAncestors();
24413 if (this.formatCombo) {
24416 var store = this.formatCombo.store;
24417 this.formatCombo.setValue("");
24418 for (var i =0; i < ans.length;i++) {
24419 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24421 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24429 // hides menus... - so this cant be on a menu...
24430 Roo.bootstrap.MenuMgr.hideAll();
24432 Roo.bootstrap.MenuMgr.hideAll();
24433 //this.editorsyncValue();
24435 onFirstFocus: function() {
24436 this.buttons.each(function(item){
24440 toggleSourceEdit : function(sourceEditMode){
24443 if(sourceEditMode){
24444 Roo.log("disabling buttons");
24445 this.buttons.each( function(item){
24446 if(item.cmd != 'pencil'){
24452 Roo.log("enabling buttons");
24453 if(this.editorcore.initialized){
24454 this.buttons.each( function(item){
24460 Roo.log("calling toggole on editor");
24461 // tell the editor that it's been pressed..
24462 this.editor.toggleSourceEdit(sourceEditMode);
24472 * @class Roo.bootstrap.Table.AbstractSelectionModel
24473 * @extends Roo.util.Observable
24474 * Abstract base class for grid SelectionModels. It provides the interface that should be
24475 * implemented by descendant classes. This class should not be directly instantiated.
24478 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24479 this.locked = false;
24480 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24484 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24485 /** @ignore Called by the grid automatically. Do not call directly. */
24486 init : function(grid){
24492 * Locks the selections.
24495 this.locked = true;
24499 * Unlocks the selections.
24501 unlock : function(){
24502 this.locked = false;
24506 * Returns true if the selections are locked.
24507 * @return {Boolean}
24509 isLocked : function(){
24510 return this.locked;
24514 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24515 * @class Roo.bootstrap.Table.RowSelectionModel
24516 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24517 * It supports multiple selections and keyboard selection/navigation.
24519 * @param {Object} config
24522 Roo.bootstrap.Table.RowSelectionModel = function(config){
24523 Roo.apply(this, config);
24524 this.selections = new Roo.util.MixedCollection(false, function(o){
24529 this.lastActive = false;
24533 * @event selectionchange
24534 * Fires when the selection changes
24535 * @param {SelectionModel} this
24537 "selectionchange" : true,
24539 * @event afterselectionchange
24540 * Fires after the selection changes (eg. by key press or clicking)
24541 * @param {SelectionModel} this
24543 "afterselectionchange" : true,
24545 * @event beforerowselect
24546 * Fires when a row is selected being selected, return false to cancel.
24547 * @param {SelectionModel} this
24548 * @param {Number} rowIndex The selected index
24549 * @param {Boolean} keepExisting False if other selections will be cleared
24551 "beforerowselect" : true,
24554 * Fires when a row is selected.
24555 * @param {SelectionModel} this
24556 * @param {Number} rowIndex The selected index
24557 * @param {Roo.data.Record} r The record
24559 "rowselect" : true,
24561 * @event rowdeselect
24562 * Fires when a row is deselected.
24563 * @param {SelectionModel} this
24564 * @param {Number} rowIndex The selected index
24566 "rowdeselect" : true
24568 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24569 this.locked = false;
24572 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24574 * @cfg {Boolean} singleSelect
24575 * True to allow selection of only one row at a time (defaults to false)
24577 singleSelect : false,
24580 initEvents : function()
24583 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24584 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24585 //}else{ // allow click to work like normal
24586 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24588 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24589 this.grid.on("rowclick", this.handleMouseDown, this);
24591 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24592 "up" : function(e){
24594 this.selectPrevious(e.shiftKey);
24595 }else if(this.last !== false && this.lastActive !== false){
24596 var last = this.last;
24597 this.selectRange(this.last, this.lastActive-1);
24598 this.grid.getView().focusRow(this.lastActive);
24599 if(last !== false){
24603 this.selectFirstRow();
24605 this.fireEvent("afterselectionchange", this);
24607 "down" : function(e){
24609 this.selectNext(e.shiftKey);
24610 }else if(this.last !== false && this.lastActive !== false){
24611 var last = this.last;
24612 this.selectRange(this.last, this.lastActive+1);
24613 this.grid.getView().focusRow(this.lastActive);
24614 if(last !== false){
24618 this.selectFirstRow();
24620 this.fireEvent("afterselectionchange", this);
24624 this.grid.store.on('load', function(){
24625 this.selections.clear();
24628 var view = this.grid.view;
24629 view.on("refresh", this.onRefresh, this);
24630 view.on("rowupdated", this.onRowUpdated, this);
24631 view.on("rowremoved", this.onRemove, this);
24636 onRefresh : function()
24638 var ds = this.grid.store, i, v = this.grid.view;
24639 var s = this.selections;
24640 s.each(function(r){
24641 if((i = ds.indexOfId(r.id)) != -1){
24650 onRemove : function(v, index, r){
24651 this.selections.remove(r);
24655 onRowUpdated : function(v, index, r){
24656 if(this.isSelected(r)){
24657 v.onRowSelect(index);
24663 * @param {Array} records The records to select
24664 * @param {Boolean} keepExisting (optional) True to keep existing selections
24666 selectRecords : function(records, keepExisting)
24669 this.clearSelections();
24671 var ds = this.grid.store;
24672 for(var i = 0, len = records.length; i < len; i++){
24673 this.selectRow(ds.indexOf(records[i]), true);
24678 * Gets the number of selected rows.
24681 getCount : function(){
24682 return this.selections.length;
24686 * Selects the first row in the grid.
24688 selectFirstRow : function(){
24693 * Select the last row.
24694 * @param {Boolean} keepExisting (optional) True to keep existing selections
24696 selectLastRow : function(keepExisting){
24697 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24698 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24702 * Selects the row immediately following the last selected row.
24703 * @param {Boolean} keepExisting (optional) True to keep existing selections
24705 selectNext : function(keepExisting)
24707 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24708 this.selectRow(this.last+1, keepExisting);
24709 this.grid.getView().focusRow(this.last);
24714 * Selects the row that precedes the last selected row.
24715 * @param {Boolean} keepExisting (optional) True to keep existing selections
24717 selectPrevious : function(keepExisting){
24719 this.selectRow(this.last-1, keepExisting);
24720 this.grid.getView().focusRow(this.last);
24725 * Returns the selected records
24726 * @return {Array} Array of selected records
24728 getSelections : function(){
24729 return [].concat(this.selections.items);
24733 * Returns the first selected record.
24736 getSelected : function(){
24737 return this.selections.itemAt(0);
24742 * Clears all selections.
24744 clearSelections : function(fast)
24750 var ds = this.grid.store;
24751 var s = this.selections;
24752 s.each(function(r){
24753 this.deselectRow(ds.indexOfId(r.id));
24757 this.selections.clear();
24764 * Selects all rows.
24766 selectAll : function(){
24770 this.selections.clear();
24771 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24772 this.selectRow(i, true);
24777 * Returns True if there is a selection.
24778 * @return {Boolean}
24780 hasSelection : function(){
24781 return this.selections.length > 0;
24785 * Returns True if the specified row is selected.
24786 * @param {Number/Record} record The record or index of the record to check
24787 * @return {Boolean}
24789 isSelected : function(index){
24790 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24791 return (r && this.selections.key(r.id) ? true : false);
24795 * Returns True if the specified record id is selected.
24796 * @param {String} id The id of record to check
24797 * @return {Boolean}
24799 isIdSelected : function(id){
24800 return (this.selections.key(id) ? true : false);
24805 handleMouseDBClick : function(e, t){
24809 handleMouseDown : function(e, t)
24811 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24812 if(this.isLocked() || rowIndex < 0 ){
24815 if(e.shiftKey && this.last !== false){
24816 var last = this.last;
24817 this.selectRange(last, rowIndex, e.ctrlKey);
24818 this.last = last; // reset the last
24822 var isSelected = this.isSelected(rowIndex);
24823 //Roo.log("select row:" + rowIndex);
24825 this.deselectRow(rowIndex);
24827 this.selectRow(rowIndex, true);
24831 if(e.button !== 0 && isSelected){
24832 alert('rowIndex 2: ' + rowIndex);
24833 view.focusRow(rowIndex);
24834 }else if(e.ctrlKey && isSelected){
24835 this.deselectRow(rowIndex);
24836 }else if(!isSelected){
24837 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24838 view.focusRow(rowIndex);
24842 this.fireEvent("afterselectionchange", this);
24845 handleDragableRowClick : function(grid, rowIndex, e)
24847 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24848 this.selectRow(rowIndex, false);
24849 grid.view.focusRow(rowIndex);
24850 this.fireEvent("afterselectionchange", this);
24855 * Selects multiple rows.
24856 * @param {Array} rows Array of the indexes of the row to select
24857 * @param {Boolean} keepExisting (optional) True to keep existing selections
24859 selectRows : function(rows, keepExisting){
24861 this.clearSelections();
24863 for(var i = 0, len = rows.length; i < len; i++){
24864 this.selectRow(rows[i], true);
24869 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24870 * @param {Number} startRow The index of the first row in the range
24871 * @param {Number} endRow The index of the last row in the range
24872 * @param {Boolean} keepExisting (optional) True to retain existing selections
24874 selectRange : function(startRow, endRow, keepExisting){
24879 this.clearSelections();
24881 if(startRow <= endRow){
24882 for(var i = startRow; i <= endRow; i++){
24883 this.selectRow(i, true);
24886 for(var i = startRow; i >= endRow; i--){
24887 this.selectRow(i, true);
24893 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24894 * @param {Number} startRow The index of the first row in the range
24895 * @param {Number} endRow The index of the last row in the range
24897 deselectRange : function(startRow, endRow, preventViewNotify){
24901 for(var i = startRow; i <= endRow; i++){
24902 this.deselectRow(i, preventViewNotify);
24908 * @param {Number} row The index of the row to select
24909 * @param {Boolean} keepExisting (optional) True to keep existing selections
24911 selectRow : function(index, keepExisting, preventViewNotify)
24913 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24916 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24917 if(!keepExisting || this.singleSelect){
24918 this.clearSelections();
24921 var r = this.grid.store.getAt(index);
24922 //console.log('selectRow - record id :' + r.id);
24924 this.selections.add(r);
24925 this.last = this.lastActive = index;
24926 if(!preventViewNotify){
24927 var proxy = new Roo.Element(
24928 this.grid.getRowDom(index)
24930 proxy.addClass('bg-info info');
24932 this.fireEvent("rowselect", this, index, r);
24933 this.fireEvent("selectionchange", this);
24939 * @param {Number} row The index of the row to deselect
24941 deselectRow : function(index, preventViewNotify)
24946 if(this.last == index){
24949 if(this.lastActive == index){
24950 this.lastActive = false;
24953 var r = this.grid.store.getAt(index);
24958 this.selections.remove(r);
24959 //.console.log('deselectRow - record id :' + r.id);
24960 if(!preventViewNotify){
24962 var proxy = new Roo.Element(
24963 this.grid.getRowDom(index)
24965 proxy.removeClass('bg-info info');
24967 this.fireEvent("rowdeselect", this, index);
24968 this.fireEvent("selectionchange", this);
24972 restoreLast : function(){
24974 this.last = this._last;
24979 acceptsNav : function(row, col, cm){
24980 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24984 onEditorKey : function(field, e){
24985 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24990 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24992 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24994 }else if(k == e.ENTER && !e.ctrlKey){
24998 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
25000 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
25002 }else if(k == e.ESC){
25006 g.startEditing(newCell[0], newCell[1]);
25012 * Ext JS Library 1.1.1
25013 * Copyright(c) 2006-2007, Ext JS, LLC.
25015 * Originally Released Under LGPL - original licence link has changed is not relivant.
25018 * <script type="text/javascript">
25022 * @class Roo.bootstrap.PagingToolbar
25023 * @extends Roo.bootstrap.NavSimplebar
25024 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
25026 * Create a new PagingToolbar
25027 * @param {Object} config The config object
25028 * @param {Roo.data.Store} store
25030 Roo.bootstrap.PagingToolbar = function(config)
25032 // old args format still supported... - xtype is prefered..
25033 // created from xtype...
25035 this.ds = config.dataSource;
25037 if (config.store && !this.ds) {
25038 this.store= Roo.factory(config.store, Roo.data);
25039 this.ds = this.store;
25040 this.ds.xmodule = this.xmodule || false;
25043 this.toolbarItems = [];
25044 if (config.items) {
25045 this.toolbarItems = config.items;
25048 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25053 this.bind(this.ds);
25056 if (Roo.bootstrap.version == 4) {
25057 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25059 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25064 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25066 * @cfg {Roo.data.Store} dataSource
25067 * The underlying data store providing the paged data
25070 * @cfg {String/HTMLElement/Element} container
25071 * container The id or element that will contain the toolbar
25074 * @cfg {Boolean} displayInfo
25075 * True to display the displayMsg (defaults to false)
25078 * @cfg {Number} pageSize
25079 * The number of records to display per page (defaults to 20)
25083 * @cfg {String} displayMsg
25084 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25086 displayMsg : 'Displaying {0} - {1} of {2}',
25088 * @cfg {String} emptyMsg
25089 * The message to display when no records are found (defaults to "No data to display")
25091 emptyMsg : 'No data to display',
25093 * Customizable piece of the default paging text (defaults to "Page")
25096 beforePageText : "Page",
25098 * Customizable piece of the default paging text (defaults to "of %0")
25101 afterPageText : "of {0}",
25103 * Customizable piece of the default paging text (defaults to "First Page")
25106 firstText : "First Page",
25108 * Customizable piece of the default paging text (defaults to "Previous Page")
25111 prevText : "Previous Page",
25113 * Customizable piece of the default paging text (defaults to "Next Page")
25116 nextText : "Next Page",
25118 * Customizable piece of the default paging text (defaults to "Last Page")
25121 lastText : "Last Page",
25123 * Customizable piece of the default paging text (defaults to "Refresh")
25126 refreshText : "Refresh",
25130 onRender : function(ct, position)
25132 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25133 this.navgroup.parentId = this.id;
25134 this.navgroup.onRender(this.el, null);
25135 // add the buttons to the navgroup
25137 if(this.displayInfo){
25138 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25139 this.displayEl = this.el.select('.x-paging-info', true).first();
25140 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25141 // this.displayEl = navel.el.select('span',true).first();
25147 Roo.each(_this.buttons, function(e){ // this might need to use render????
25148 Roo.factory(e).render(_this.el);
25152 Roo.each(_this.toolbarItems, function(e) {
25153 _this.navgroup.addItem(e);
25157 this.first = this.navgroup.addItem({
25158 tooltip: this.firstText,
25159 cls: "prev btn-outline-secondary",
25160 html : ' <i class="fa fa-step-backward"></i>',
25162 preventDefault: true,
25163 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25166 this.prev = this.navgroup.addItem({
25167 tooltip: this.prevText,
25168 cls: "prev btn-outline-secondary",
25169 html : ' <i class="fa fa-backward"></i>',
25171 preventDefault: true,
25172 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25174 //this.addSeparator();
25177 var field = this.navgroup.addItem( {
25179 cls : 'x-paging-position btn-outline-secondary',
25181 html : this.beforePageText +
25182 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25183 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25186 this.field = field.el.select('input', true).first();
25187 this.field.on("keydown", this.onPagingKeydown, this);
25188 this.field.on("focus", function(){this.dom.select();});
25191 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25192 //this.field.setHeight(18);
25193 //this.addSeparator();
25194 this.next = this.navgroup.addItem({
25195 tooltip: this.nextText,
25196 cls: "next btn-outline-secondary",
25197 html : ' <i class="fa fa-forward"></i>',
25199 preventDefault: true,
25200 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25202 this.last = this.navgroup.addItem({
25203 tooltip: this.lastText,
25204 html : ' <i class="fa fa-step-forward"></i>',
25205 cls: "next btn-outline-secondary",
25207 preventDefault: true,
25208 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25210 //this.addSeparator();
25211 this.loading = this.navgroup.addItem({
25212 tooltip: this.refreshText,
25213 cls: "btn-outline-secondary",
25214 html : ' <i class="fa fa-refresh"></i>',
25215 preventDefault: true,
25216 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25222 updateInfo : function(){
25223 if(this.displayEl){
25224 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25225 var msg = count == 0 ?
25229 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25231 this.displayEl.update(msg);
25236 onLoad : function(ds, r, o)
25238 this.cursor = o.params.start ? o.params.start : 0;
25240 var d = this.getPageData(),
25245 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25246 this.field.dom.value = ap;
25247 this.first.setDisabled(ap == 1);
25248 this.prev.setDisabled(ap == 1);
25249 this.next.setDisabled(ap == ps);
25250 this.last.setDisabled(ap == ps);
25251 this.loading.enable();
25256 getPageData : function(){
25257 var total = this.ds.getTotalCount();
25260 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25261 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25266 onLoadError : function(){
25267 this.loading.enable();
25271 onPagingKeydown : function(e){
25272 var k = e.getKey();
25273 var d = this.getPageData();
25275 var v = this.field.dom.value, pageNum;
25276 if(!v || isNaN(pageNum = parseInt(v, 10))){
25277 this.field.dom.value = d.activePage;
25280 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25281 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25284 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))
25286 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25287 this.field.dom.value = pageNum;
25288 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25291 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25293 var v = this.field.dom.value, pageNum;
25294 var increment = (e.shiftKey) ? 10 : 1;
25295 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25298 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25299 this.field.dom.value = d.activePage;
25302 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25304 this.field.dom.value = parseInt(v, 10) + increment;
25305 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25306 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25313 beforeLoad : function(){
25315 this.loading.disable();
25320 onClick : function(which){
25329 ds.load({params:{start: 0, limit: this.pageSize}});
25332 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25335 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25338 var total = ds.getTotalCount();
25339 var extra = total % this.pageSize;
25340 var lastStart = extra ? (total - extra) : total-this.pageSize;
25341 ds.load({params:{start: lastStart, limit: this.pageSize}});
25344 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25350 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25351 * @param {Roo.data.Store} store The data store to unbind
25353 unbind : function(ds){
25354 ds.un("beforeload", this.beforeLoad, this);
25355 ds.un("load", this.onLoad, this);
25356 ds.un("loadexception", this.onLoadError, this);
25357 ds.un("remove", this.updateInfo, this);
25358 ds.un("add", this.updateInfo, this);
25359 this.ds = undefined;
25363 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25364 * @param {Roo.data.Store} store The data store to bind
25366 bind : function(ds){
25367 ds.on("beforeload", this.beforeLoad, this);
25368 ds.on("load", this.onLoad, this);
25369 ds.on("loadexception", this.onLoadError, this);
25370 ds.on("remove", this.updateInfo, this);
25371 ds.on("add", this.updateInfo, this);
25382 * @class Roo.bootstrap.MessageBar
25383 * @extends Roo.bootstrap.Component
25384 * Bootstrap MessageBar class
25385 * @cfg {String} html contents of the MessageBar
25386 * @cfg {String} weight (info | success | warning | danger) default info
25387 * @cfg {String} beforeClass insert the bar before the given class
25388 * @cfg {Boolean} closable (true | false) default false
25389 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25392 * Create a new Element
25393 * @param {Object} config The config object
25396 Roo.bootstrap.MessageBar = function(config){
25397 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25400 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25406 beforeClass: 'bootstrap-sticky-wrap',
25408 getAutoCreate : function(){
25412 cls: 'alert alert-dismissable alert-' + this.weight,
25417 html: this.html || ''
25423 cfg.cls += ' alert-messages-fixed';
25437 onRender : function(ct, position)
25439 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25442 var cfg = Roo.apply({}, this.getAutoCreate());
25446 cfg.cls += ' ' + this.cls;
25449 cfg.style = this.style;
25451 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25453 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25456 this.el.select('>button.close').on('click', this.hide, this);
25462 if (!this.rendered) {
25468 this.fireEvent('show', this);
25474 if (!this.rendered) {
25480 this.fireEvent('hide', this);
25483 update : function()
25485 // var e = this.el.dom.firstChild;
25487 // if(this.closable){
25488 // e = e.nextSibling;
25491 // e.data = this.html || '';
25493 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25509 * @class Roo.bootstrap.Graph
25510 * @extends Roo.bootstrap.Component
25511 * Bootstrap Graph class
25515 @cfg {String} graphtype bar | vbar | pie
25516 @cfg {number} g_x coodinator | centre x (pie)
25517 @cfg {number} g_y coodinator | centre y (pie)
25518 @cfg {number} g_r radius (pie)
25519 @cfg {number} g_height height of the chart (respected by all elements in the set)
25520 @cfg {number} g_width width of the chart (respected by all elements in the set)
25521 @cfg {Object} title The title of the chart
25524 -opts (object) options for the chart
25526 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25527 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25529 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.
25530 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25532 o stretch (boolean)
25534 -opts (object) options for the pie
25537 o startAngle (number)
25538 o endAngle (number)
25542 * Create a new Input
25543 * @param {Object} config The config object
25546 Roo.bootstrap.Graph = function(config){
25547 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25553 * The img click event for the img.
25554 * @param {Roo.EventObject} e
25560 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25571 //g_colors: this.colors,
25578 getAutoCreate : function(){
25589 onRender : function(ct,position){
25592 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25594 if (typeof(Raphael) == 'undefined') {
25595 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25599 this.raphael = Raphael(this.el.dom);
25601 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25602 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25603 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25604 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25606 r.text(160, 10, "Single Series Chart").attr(txtattr);
25607 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25608 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25609 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25611 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25612 r.barchart(330, 10, 300, 220, data1);
25613 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25614 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25617 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25618 // r.barchart(30, 30, 560, 250, xdata, {
25619 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25620 // axis : "0 0 1 1",
25621 // axisxlabels : xdata
25622 // //yvalues : cols,
25625 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25627 // this.load(null,xdata,{
25628 // axis : "0 0 1 1",
25629 // axisxlabels : xdata
25634 load : function(graphtype,xdata,opts)
25636 this.raphael.clear();
25638 graphtype = this.graphtype;
25643 var r = this.raphael,
25644 fin = function () {
25645 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25647 fout = function () {
25648 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25650 pfin = function() {
25651 this.sector.stop();
25652 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25655 this.label[0].stop();
25656 this.label[0].attr({ r: 7.5 });
25657 this.label[1].attr({ "font-weight": 800 });
25660 pfout = function() {
25661 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25664 this.label[0].animate({ r: 5 }, 500, "bounce");
25665 this.label[1].attr({ "font-weight": 400 });
25671 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25674 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25677 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25678 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25680 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25687 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25692 setTitle: function(o)
25697 initEvents: function() {
25700 this.el.on('click', this.onClick, this);
25704 onClick : function(e)
25706 Roo.log('img onclick');
25707 this.fireEvent('click', this, e);
25719 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25722 * @class Roo.bootstrap.dash.NumberBox
25723 * @extends Roo.bootstrap.Component
25724 * Bootstrap NumberBox class
25725 * @cfg {String} headline Box headline
25726 * @cfg {String} content Box content
25727 * @cfg {String} icon Box icon
25728 * @cfg {String} footer Footer text
25729 * @cfg {String} fhref Footer href
25732 * Create a new NumberBox
25733 * @param {Object} config The config object
25737 Roo.bootstrap.dash.NumberBox = function(config){
25738 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25742 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25751 getAutoCreate : function(){
25755 cls : 'small-box ',
25763 cls : 'roo-headline',
25764 html : this.headline
25768 cls : 'roo-content',
25769 html : this.content
25783 cls : 'ion ' + this.icon
25792 cls : 'small-box-footer',
25793 href : this.fhref || '#',
25797 cfg.cn.push(footer);
25804 onRender : function(ct,position){
25805 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25812 setHeadline: function (value)
25814 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25817 setFooter: function (value, href)
25819 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25822 this.el.select('a.small-box-footer',true).first().attr('href', href);
25827 setContent: function (value)
25829 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25832 initEvents: function()
25846 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25849 * @class Roo.bootstrap.dash.TabBox
25850 * @extends Roo.bootstrap.Component
25851 * Bootstrap TabBox class
25852 * @cfg {String} title Title of the TabBox
25853 * @cfg {String} icon Icon of the TabBox
25854 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25855 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25858 * Create a new TabBox
25859 * @param {Object} config The config object
25863 Roo.bootstrap.dash.TabBox = function(config){
25864 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25869 * When a pane is added
25870 * @param {Roo.bootstrap.dash.TabPane} pane
25874 * @event activatepane
25875 * When a pane is activated
25876 * @param {Roo.bootstrap.dash.TabPane} pane
25878 "activatepane" : true
25886 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25891 tabScrollable : false,
25893 getChildContainer : function()
25895 return this.el.select('.tab-content', true).first();
25898 getAutoCreate : function(){
25902 cls: 'pull-left header',
25910 cls: 'fa ' + this.icon
25916 cls: 'nav nav-tabs pull-right',
25922 if(this.tabScrollable){
25929 cls: 'nav nav-tabs pull-right',
25940 cls: 'nav-tabs-custom',
25945 cls: 'tab-content no-padding',
25953 initEvents : function()
25955 //Roo.log('add add pane handler');
25956 this.on('addpane', this.onAddPane, this);
25959 * Updates the box title
25960 * @param {String} html to set the title to.
25962 setTitle : function(value)
25964 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25966 onAddPane : function(pane)
25968 this.panes.push(pane);
25969 //Roo.log('addpane');
25971 // tabs are rendere left to right..
25972 if(!this.showtabs){
25976 var ctr = this.el.select('.nav-tabs', true).first();
25979 var existing = ctr.select('.nav-tab',true);
25980 var qty = existing.getCount();;
25983 var tab = ctr.createChild({
25985 cls : 'nav-tab' + (qty ? '' : ' active'),
25993 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25996 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25998 pane.el.addClass('active');
26003 onTabClick : function(ev,un,ob,pane)
26005 //Roo.log('tab - prev default');
26006 ev.preventDefault();
26009 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
26010 pane.tab.addClass('active');
26011 //Roo.log(pane.title);
26012 this.getChildContainer().select('.tab-pane',true).removeClass('active');
26013 // technically we should have a deactivate event.. but maybe add later.
26014 // and it should not de-activate the selected tab...
26015 this.fireEvent('activatepane', pane);
26016 pane.el.addClass('active');
26017 pane.fireEvent('activate');
26022 getActivePane : function()
26025 Roo.each(this.panes, function(p) {
26026 if(p.el.hasClass('active')){
26047 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26049 * @class Roo.bootstrap.TabPane
26050 * @extends Roo.bootstrap.Component
26051 * Bootstrap TabPane class
26052 * @cfg {Boolean} active (false | true) Default false
26053 * @cfg {String} title title of panel
26057 * Create a new TabPane
26058 * @param {Object} config The config object
26061 Roo.bootstrap.dash.TabPane = function(config){
26062 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26068 * When a pane is activated
26069 * @param {Roo.bootstrap.dash.TabPane} pane
26076 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26081 // the tabBox that this is attached to.
26084 getAutoCreate : function()
26092 cfg.cls += ' active';
26097 initEvents : function()
26099 //Roo.log('trigger add pane handler');
26100 this.parent().fireEvent('addpane', this)
26104 * Updates the tab title
26105 * @param {String} html to set the title to.
26107 setTitle: function(str)
26113 this.tab.select('a', true).first().dom.innerHTML = str;
26130 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26133 * @class Roo.bootstrap.menu.Menu
26134 * @extends Roo.bootstrap.Component
26135 * Bootstrap Menu class - container for Menu
26136 * @cfg {String} html Text of the menu
26137 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26138 * @cfg {String} icon Font awesome icon
26139 * @cfg {String} pos Menu align to (top | bottom) default bottom
26143 * Create a new Menu
26144 * @param {Object} config The config object
26148 Roo.bootstrap.menu.Menu = function(config){
26149 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26153 * @event beforeshow
26154 * Fires before this menu is displayed
26155 * @param {Roo.bootstrap.menu.Menu} this
26159 * @event beforehide
26160 * Fires before this menu is hidden
26161 * @param {Roo.bootstrap.menu.Menu} this
26166 * Fires after this menu is displayed
26167 * @param {Roo.bootstrap.menu.Menu} this
26172 * Fires after this menu is hidden
26173 * @param {Roo.bootstrap.menu.Menu} this
26178 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26179 * @param {Roo.bootstrap.menu.Menu} this
26180 * @param {Roo.EventObject} e
26187 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26191 weight : 'default',
26196 getChildContainer : function() {
26197 if(this.isSubMenu){
26201 return this.el.select('ul.dropdown-menu', true).first();
26204 getAutoCreate : function()
26209 cls : 'roo-menu-text',
26217 cls : 'fa ' + this.icon
26228 cls : 'dropdown-button btn btn-' + this.weight,
26233 cls : 'dropdown-toggle btn btn-' + this.weight,
26243 cls : 'dropdown-menu'
26249 if(this.pos == 'top'){
26250 cfg.cls += ' dropup';
26253 if(this.isSubMenu){
26256 cls : 'dropdown-menu'
26263 onRender : function(ct, position)
26265 this.isSubMenu = ct.hasClass('dropdown-submenu');
26267 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26270 initEvents : function()
26272 if(this.isSubMenu){
26276 this.hidden = true;
26278 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26279 this.triggerEl.on('click', this.onTriggerPress, this);
26281 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26282 this.buttonEl.on('click', this.onClick, this);
26288 if(this.isSubMenu){
26292 return this.el.select('ul.dropdown-menu', true).first();
26295 onClick : function(e)
26297 this.fireEvent("click", this, e);
26300 onTriggerPress : function(e)
26302 if (this.isVisible()) {
26309 isVisible : function(){
26310 return !this.hidden;
26315 this.fireEvent("beforeshow", this);
26317 this.hidden = false;
26318 this.el.addClass('open');
26320 Roo.get(document).on("mouseup", this.onMouseUp, this);
26322 this.fireEvent("show", this);
26329 this.fireEvent("beforehide", this);
26331 this.hidden = true;
26332 this.el.removeClass('open');
26334 Roo.get(document).un("mouseup", this.onMouseUp);
26336 this.fireEvent("hide", this);
26339 onMouseUp : function()
26353 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26356 * @class Roo.bootstrap.menu.Item
26357 * @extends Roo.bootstrap.Component
26358 * Bootstrap MenuItem class
26359 * @cfg {Boolean} submenu (true | false) default false
26360 * @cfg {String} html text of the item
26361 * @cfg {String} href the link
26362 * @cfg {Boolean} disable (true | false) default false
26363 * @cfg {Boolean} preventDefault (true | false) default true
26364 * @cfg {String} icon Font awesome icon
26365 * @cfg {String} pos Submenu align to (left | right) default right
26369 * Create a new Item
26370 * @param {Object} config The config object
26374 Roo.bootstrap.menu.Item = function(config){
26375 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26379 * Fires when the mouse is hovering over this menu
26380 * @param {Roo.bootstrap.menu.Item} this
26381 * @param {Roo.EventObject} e
26386 * Fires when the mouse exits this menu
26387 * @param {Roo.bootstrap.menu.Item} this
26388 * @param {Roo.EventObject} e
26394 * The raw click event for the entire grid.
26395 * @param {Roo.EventObject} e
26401 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26406 preventDefault: true,
26411 getAutoCreate : function()
26416 cls : 'roo-menu-item-text',
26424 cls : 'fa ' + this.icon
26433 href : this.href || '#',
26440 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26444 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26446 if(this.pos == 'left'){
26447 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26454 initEvents : function()
26456 this.el.on('mouseover', this.onMouseOver, this);
26457 this.el.on('mouseout', this.onMouseOut, this);
26459 this.el.select('a', true).first().on('click', this.onClick, this);
26463 onClick : function(e)
26465 if(this.preventDefault){
26466 e.preventDefault();
26469 this.fireEvent("click", this, e);
26472 onMouseOver : function(e)
26474 if(this.submenu && this.pos == 'left'){
26475 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26478 this.fireEvent("mouseover", this, e);
26481 onMouseOut : function(e)
26483 this.fireEvent("mouseout", this, e);
26495 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26498 * @class Roo.bootstrap.menu.Separator
26499 * @extends Roo.bootstrap.Component
26500 * Bootstrap Separator class
26503 * Create a new Separator
26504 * @param {Object} config The config object
26508 Roo.bootstrap.menu.Separator = function(config){
26509 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26512 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26514 getAutoCreate : function(){
26535 * @class Roo.bootstrap.Tooltip
26536 * Bootstrap Tooltip class
26537 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26538 * to determine which dom element triggers the tooltip.
26540 * It needs to add support for additional attributes like tooltip-position
26543 * Create a new Toolti
26544 * @param {Object} config The config object
26547 Roo.bootstrap.Tooltip = function(config){
26548 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26550 this.alignment = Roo.bootstrap.Tooltip.alignment;
26552 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26553 this.alignment = config.alignment;
26558 Roo.apply(Roo.bootstrap.Tooltip, {
26560 * @function init initialize tooltip monitoring.
26564 currentTip : false,
26565 currentRegion : false,
26571 Roo.get(document).on('mouseover', this.enter ,this);
26572 Roo.get(document).on('mouseout', this.leave, this);
26575 this.currentTip = new Roo.bootstrap.Tooltip();
26578 enter : function(ev)
26580 var dom = ev.getTarget();
26582 //Roo.log(['enter',dom]);
26583 var el = Roo.fly(dom);
26584 if (this.currentEl) {
26586 //Roo.log(this.currentEl);
26587 //Roo.log(this.currentEl.contains(dom));
26588 if (this.currentEl == el) {
26591 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26597 if (this.currentTip.el) {
26598 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26602 if(!el || el.dom == document){
26608 // you can not look for children, as if el is the body.. then everythign is the child..
26609 if (!el.attr('tooltip')) { //
26610 if (!el.select("[tooltip]").elements.length) {
26613 // is the mouse over this child...?
26614 bindEl = el.select("[tooltip]").first();
26615 var xy = ev.getXY();
26616 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26617 //Roo.log("not in region.");
26620 //Roo.log("child element over..");
26623 this.currentEl = bindEl;
26624 this.currentTip.bind(bindEl);
26625 this.currentRegion = Roo.lib.Region.getRegion(dom);
26626 this.currentTip.enter();
26629 leave : function(ev)
26631 var dom = ev.getTarget();
26632 //Roo.log(['leave',dom]);
26633 if (!this.currentEl) {
26638 if (dom != this.currentEl.dom) {
26641 var xy = ev.getXY();
26642 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26645 // only activate leave if mouse cursor is outside... bounding box..
26650 if (this.currentTip) {
26651 this.currentTip.leave();
26653 //Roo.log('clear currentEl');
26654 this.currentEl = false;
26659 'left' : ['r-l', [-2,0], 'right'],
26660 'right' : ['l-r', [2,0], 'left'],
26661 'bottom' : ['t-b', [0,2], 'top'],
26662 'top' : [ 'b-t', [0,-2], 'bottom']
26668 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26673 delay : null, // can be { show : 300 , hide: 500}
26677 hoverState : null, //???
26679 placement : 'bottom',
26683 getAutoCreate : function(){
26690 cls : 'tooltip-arrow'
26693 cls : 'tooltip-inner'
26700 bind : function(el)
26706 enter : function () {
26708 if (this.timeout != null) {
26709 clearTimeout(this.timeout);
26712 this.hoverState = 'in';
26713 //Roo.log("enter - show");
26714 if (!this.delay || !this.delay.show) {
26719 this.timeout = setTimeout(function () {
26720 if (_t.hoverState == 'in') {
26723 }, this.delay.show);
26727 clearTimeout(this.timeout);
26729 this.hoverState = 'out';
26730 if (!this.delay || !this.delay.hide) {
26736 this.timeout = setTimeout(function () {
26737 //Roo.log("leave - timeout");
26739 if (_t.hoverState == 'out') {
26741 Roo.bootstrap.Tooltip.currentEl = false;
26746 show : function (msg)
26749 this.render(document.body);
26752 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26754 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26756 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26758 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26760 var placement = typeof this.placement == 'function' ?
26761 this.placement.call(this, this.el, on_el) :
26764 var autoToken = /\s?auto?\s?/i;
26765 var autoPlace = autoToken.test(placement);
26767 placement = placement.replace(autoToken, '') || 'top';
26771 //this.el.setXY([0,0]);
26773 //this.el.dom.style.display='block';
26775 //this.el.appendTo(on_el);
26777 var p = this.getPosition();
26778 var box = this.el.getBox();
26784 var align = this.alignment[placement];
26786 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26788 if(placement == 'top' || placement == 'bottom'){
26790 placement = 'right';
26793 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26794 placement = 'left';
26797 var scroll = Roo.select('body', true).first().getScroll();
26799 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26803 align = this.alignment[placement];
26806 this.el.alignTo(this.bindEl, align[0],align[1]);
26807 //var arrow = this.el.select('.arrow',true).first();
26808 //arrow.set(align[2],
26810 this.el.addClass(placement);
26812 this.el.addClass('in fade');
26814 this.hoverState = null;
26816 if (this.el.hasClass('fade')) {
26827 //this.el.setXY([0,0]);
26828 this.el.removeClass('in');
26844 * @class Roo.bootstrap.LocationPicker
26845 * @extends Roo.bootstrap.Component
26846 * Bootstrap LocationPicker class
26847 * @cfg {Number} latitude Position when init default 0
26848 * @cfg {Number} longitude Position when init default 0
26849 * @cfg {Number} zoom default 15
26850 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26851 * @cfg {Boolean} mapTypeControl default false
26852 * @cfg {Boolean} disableDoubleClickZoom default false
26853 * @cfg {Boolean} scrollwheel default true
26854 * @cfg {Boolean} streetViewControl default false
26855 * @cfg {Number} radius default 0
26856 * @cfg {String} locationName
26857 * @cfg {Boolean} draggable default true
26858 * @cfg {Boolean} enableAutocomplete default false
26859 * @cfg {Boolean} enableReverseGeocode default true
26860 * @cfg {String} markerTitle
26863 * Create a new LocationPicker
26864 * @param {Object} config The config object
26868 Roo.bootstrap.LocationPicker = function(config){
26870 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26875 * Fires when the picker initialized.
26876 * @param {Roo.bootstrap.LocationPicker} this
26877 * @param {Google Location} location
26881 * @event positionchanged
26882 * Fires when the picker position changed.
26883 * @param {Roo.bootstrap.LocationPicker} this
26884 * @param {Google Location} location
26886 positionchanged : true,
26889 * Fires when the map resize.
26890 * @param {Roo.bootstrap.LocationPicker} this
26895 * Fires when the map show.
26896 * @param {Roo.bootstrap.LocationPicker} this
26901 * Fires when the map hide.
26902 * @param {Roo.bootstrap.LocationPicker} this
26907 * Fires when click the map.
26908 * @param {Roo.bootstrap.LocationPicker} this
26909 * @param {Map event} e
26913 * @event mapRightClick
26914 * Fires when right click the map.
26915 * @param {Roo.bootstrap.LocationPicker} this
26916 * @param {Map event} e
26918 mapRightClick : true,
26920 * @event markerClick
26921 * Fires when click the marker.
26922 * @param {Roo.bootstrap.LocationPicker} this
26923 * @param {Map event} e
26925 markerClick : true,
26927 * @event markerRightClick
26928 * Fires when right click the marker.
26929 * @param {Roo.bootstrap.LocationPicker} this
26930 * @param {Map event} e
26932 markerRightClick : true,
26934 * @event OverlayViewDraw
26935 * Fires when OverlayView Draw
26936 * @param {Roo.bootstrap.LocationPicker} this
26938 OverlayViewDraw : true,
26940 * @event OverlayViewOnAdd
26941 * Fires when OverlayView Draw
26942 * @param {Roo.bootstrap.LocationPicker} this
26944 OverlayViewOnAdd : true,
26946 * @event OverlayViewOnRemove
26947 * Fires when OverlayView Draw
26948 * @param {Roo.bootstrap.LocationPicker} this
26950 OverlayViewOnRemove : true,
26952 * @event OverlayViewShow
26953 * Fires when OverlayView Draw
26954 * @param {Roo.bootstrap.LocationPicker} this
26955 * @param {Pixel} cpx
26957 OverlayViewShow : true,
26959 * @event OverlayViewHide
26960 * Fires when OverlayView Draw
26961 * @param {Roo.bootstrap.LocationPicker} this
26963 OverlayViewHide : true,
26965 * @event loadexception
26966 * Fires when load google lib failed.
26967 * @param {Roo.bootstrap.LocationPicker} this
26969 loadexception : true
26974 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26976 gMapContext: false,
26982 mapTypeControl: false,
26983 disableDoubleClickZoom: false,
26985 streetViewControl: false,
26989 enableAutocomplete: false,
26990 enableReverseGeocode: true,
26993 getAutoCreate: function()
26998 cls: 'roo-location-picker'
27004 initEvents: function(ct, position)
27006 if(!this.el.getWidth() || this.isApplied()){
27010 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27015 initial: function()
27017 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
27018 this.fireEvent('loadexception', this);
27022 if(!this.mapTypeId){
27023 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
27026 this.gMapContext = this.GMapContext();
27028 this.initOverlayView();
27030 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
27034 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
27035 _this.setPosition(_this.gMapContext.marker.position);
27038 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
27039 _this.fireEvent('mapClick', this, event);
27043 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
27044 _this.fireEvent('mapRightClick', this, event);
27048 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
27049 _this.fireEvent('markerClick', this, event);
27053 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27054 _this.fireEvent('markerRightClick', this, event);
27058 this.setPosition(this.gMapContext.location);
27060 this.fireEvent('initial', this, this.gMapContext.location);
27063 initOverlayView: function()
27067 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27071 _this.fireEvent('OverlayViewDraw', _this);
27076 _this.fireEvent('OverlayViewOnAdd', _this);
27079 onRemove: function()
27081 _this.fireEvent('OverlayViewOnRemove', _this);
27084 show: function(cpx)
27086 _this.fireEvent('OverlayViewShow', _this, cpx);
27091 _this.fireEvent('OverlayViewHide', _this);
27097 fromLatLngToContainerPixel: function(event)
27099 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27102 isApplied: function()
27104 return this.getGmapContext() == false ? false : true;
27107 getGmapContext: function()
27109 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27112 GMapContext: function()
27114 var position = new google.maps.LatLng(this.latitude, this.longitude);
27116 var _map = new google.maps.Map(this.el.dom, {
27119 mapTypeId: this.mapTypeId,
27120 mapTypeControl: this.mapTypeControl,
27121 disableDoubleClickZoom: this.disableDoubleClickZoom,
27122 scrollwheel: this.scrollwheel,
27123 streetViewControl: this.streetViewControl,
27124 locationName: this.locationName,
27125 draggable: this.draggable,
27126 enableAutocomplete: this.enableAutocomplete,
27127 enableReverseGeocode: this.enableReverseGeocode
27130 var _marker = new google.maps.Marker({
27131 position: position,
27133 title: this.markerTitle,
27134 draggable: this.draggable
27141 location: position,
27142 radius: this.radius,
27143 locationName: this.locationName,
27144 addressComponents: {
27145 formatted_address: null,
27146 addressLine1: null,
27147 addressLine2: null,
27149 streetNumber: null,
27153 stateOrProvince: null
27156 domContainer: this.el.dom,
27157 geodecoder: new google.maps.Geocoder()
27161 drawCircle: function(center, radius, options)
27163 if (this.gMapContext.circle != null) {
27164 this.gMapContext.circle.setMap(null);
27168 options = Roo.apply({}, options, {
27169 strokeColor: "#0000FF",
27170 strokeOpacity: .35,
27172 fillColor: "#0000FF",
27176 options.map = this.gMapContext.map;
27177 options.radius = radius;
27178 options.center = center;
27179 this.gMapContext.circle = new google.maps.Circle(options);
27180 return this.gMapContext.circle;
27186 setPosition: function(location)
27188 this.gMapContext.location = location;
27189 this.gMapContext.marker.setPosition(location);
27190 this.gMapContext.map.panTo(location);
27191 this.drawCircle(location, this.gMapContext.radius, {});
27195 if (this.gMapContext.settings.enableReverseGeocode) {
27196 this.gMapContext.geodecoder.geocode({
27197 latLng: this.gMapContext.location
27198 }, function(results, status) {
27200 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27201 _this.gMapContext.locationName = results[0].formatted_address;
27202 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27204 _this.fireEvent('positionchanged', this, location);
27211 this.fireEvent('positionchanged', this, location);
27216 google.maps.event.trigger(this.gMapContext.map, "resize");
27218 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27220 this.fireEvent('resize', this);
27223 setPositionByLatLng: function(latitude, longitude)
27225 this.setPosition(new google.maps.LatLng(latitude, longitude));
27228 getCurrentPosition: function()
27231 latitude: this.gMapContext.location.lat(),
27232 longitude: this.gMapContext.location.lng()
27236 getAddressName: function()
27238 return this.gMapContext.locationName;
27241 getAddressComponents: function()
27243 return this.gMapContext.addressComponents;
27246 address_component_from_google_geocode: function(address_components)
27250 for (var i = 0; i < address_components.length; i++) {
27251 var component = address_components[i];
27252 if (component.types.indexOf("postal_code") >= 0) {
27253 result.postalCode = component.short_name;
27254 } else if (component.types.indexOf("street_number") >= 0) {
27255 result.streetNumber = component.short_name;
27256 } else if (component.types.indexOf("route") >= 0) {
27257 result.streetName = component.short_name;
27258 } else if (component.types.indexOf("neighborhood") >= 0) {
27259 result.city = component.short_name;
27260 } else if (component.types.indexOf("locality") >= 0) {
27261 result.city = component.short_name;
27262 } else if (component.types.indexOf("sublocality") >= 0) {
27263 result.district = component.short_name;
27264 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27265 result.stateOrProvince = component.short_name;
27266 } else if (component.types.indexOf("country") >= 0) {
27267 result.country = component.short_name;
27271 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27272 result.addressLine2 = "";
27276 setZoomLevel: function(zoom)
27278 this.gMapContext.map.setZoom(zoom);
27291 this.fireEvent('show', this);
27302 this.fireEvent('hide', this);
27307 Roo.apply(Roo.bootstrap.LocationPicker, {
27309 OverlayView : function(map, options)
27311 options = options || {};
27318 * @class Roo.bootstrap.Alert
27319 * @extends Roo.bootstrap.Component
27320 * Bootstrap Alert class - shows an alert area box
27322 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27323 Enter a valid email address
27326 * @cfg {String} title The title of alert
27327 * @cfg {String} html The content of alert
27328 * @cfg {String} weight ( success | info | warning | danger )
27329 * @cfg {String} faicon font-awesomeicon
27332 * Create a new alert
27333 * @param {Object} config The config object
27337 Roo.bootstrap.Alert = function(config){
27338 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27342 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27349 getAutoCreate : function()
27358 cls : 'roo-alert-icon'
27363 cls : 'roo-alert-title',
27368 cls : 'roo-alert-text',
27375 cfg.cn[0].cls += ' fa ' + this.faicon;
27379 cfg.cls += ' alert-' + this.weight;
27385 initEvents: function()
27387 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27390 setTitle : function(str)
27392 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27395 setText : function(str)
27397 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27400 setWeight : function(weight)
27403 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27406 this.weight = weight;
27408 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27411 setIcon : function(icon)
27414 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27417 this.faicon = icon;
27419 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27440 * @class Roo.bootstrap.UploadCropbox
27441 * @extends Roo.bootstrap.Component
27442 * Bootstrap UploadCropbox class
27443 * @cfg {String} emptyText show when image has been loaded
27444 * @cfg {String} rotateNotify show when image too small to rotate
27445 * @cfg {Number} errorTimeout default 3000
27446 * @cfg {Number} minWidth default 300
27447 * @cfg {Number} minHeight default 300
27448 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27449 * @cfg {Boolean} isDocument (true|false) default false
27450 * @cfg {String} url action url
27451 * @cfg {String} paramName default 'imageUpload'
27452 * @cfg {String} method default POST
27453 * @cfg {Boolean} loadMask (true|false) default true
27454 * @cfg {Boolean} loadingText default 'Loading...'
27457 * Create a new UploadCropbox
27458 * @param {Object} config The config object
27461 Roo.bootstrap.UploadCropbox = function(config){
27462 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27466 * @event beforeselectfile
27467 * Fire before select file
27468 * @param {Roo.bootstrap.UploadCropbox} this
27470 "beforeselectfile" : true,
27473 * Fire after initEvent
27474 * @param {Roo.bootstrap.UploadCropbox} this
27479 * Fire after initEvent
27480 * @param {Roo.bootstrap.UploadCropbox} this
27481 * @param {String} data
27486 * Fire when preparing the file data
27487 * @param {Roo.bootstrap.UploadCropbox} this
27488 * @param {Object} file
27493 * Fire when get exception
27494 * @param {Roo.bootstrap.UploadCropbox} this
27495 * @param {XMLHttpRequest} xhr
27497 "exception" : true,
27499 * @event beforeloadcanvas
27500 * Fire before load the canvas
27501 * @param {Roo.bootstrap.UploadCropbox} this
27502 * @param {String} src
27504 "beforeloadcanvas" : true,
27507 * Fire when trash image
27508 * @param {Roo.bootstrap.UploadCropbox} this
27513 * Fire when download the image
27514 * @param {Roo.bootstrap.UploadCropbox} this
27518 * @event footerbuttonclick
27519 * Fire when footerbuttonclick
27520 * @param {Roo.bootstrap.UploadCropbox} this
27521 * @param {String} type
27523 "footerbuttonclick" : true,
27527 * @param {Roo.bootstrap.UploadCropbox} this
27532 * Fire when rotate the image
27533 * @param {Roo.bootstrap.UploadCropbox} this
27534 * @param {String} pos
27539 * Fire when inspect the file
27540 * @param {Roo.bootstrap.UploadCropbox} this
27541 * @param {Object} file
27546 * Fire when xhr upload the file
27547 * @param {Roo.bootstrap.UploadCropbox} this
27548 * @param {Object} data
27553 * Fire when arrange the file data
27554 * @param {Roo.bootstrap.UploadCropbox} this
27555 * @param {Object} formData
27560 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27563 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27565 emptyText : 'Click to upload image',
27566 rotateNotify : 'Image is too small to rotate',
27567 errorTimeout : 3000,
27581 cropType : 'image/jpeg',
27583 canvasLoaded : false,
27584 isDocument : false,
27586 paramName : 'imageUpload',
27588 loadingText : 'Loading...',
27591 getAutoCreate : function()
27595 cls : 'roo-upload-cropbox',
27599 cls : 'roo-upload-cropbox-selector',
27604 cls : 'roo-upload-cropbox-body',
27605 style : 'cursor:pointer',
27609 cls : 'roo-upload-cropbox-preview'
27613 cls : 'roo-upload-cropbox-thumb'
27617 cls : 'roo-upload-cropbox-empty-notify',
27618 html : this.emptyText
27622 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27623 html : this.rotateNotify
27629 cls : 'roo-upload-cropbox-footer',
27632 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27642 onRender : function(ct, position)
27644 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27646 if (this.buttons.length) {
27648 Roo.each(this.buttons, function(bb) {
27650 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27652 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27658 this.maskEl = this.el;
27662 initEvents : function()
27664 this.urlAPI = (window.createObjectURL && window) ||
27665 (window.URL && URL.revokeObjectURL && URL) ||
27666 (window.webkitURL && webkitURL);
27668 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27669 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27671 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27672 this.selectorEl.hide();
27674 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27675 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27677 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27678 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27679 this.thumbEl.hide();
27681 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27682 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27684 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27685 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27686 this.errorEl.hide();
27688 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27689 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27690 this.footerEl.hide();
27692 this.setThumbBoxSize();
27698 this.fireEvent('initial', this);
27705 window.addEventListener("resize", function() { _this.resize(); } );
27707 this.bodyEl.on('click', this.beforeSelectFile, this);
27710 this.bodyEl.on('touchstart', this.onTouchStart, this);
27711 this.bodyEl.on('touchmove', this.onTouchMove, this);
27712 this.bodyEl.on('touchend', this.onTouchEnd, this);
27716 this.bodyEl.on('mousedown', this.onMouseDown, this);
27717 this.bodyEl.on('mousemove', this.onMouseMove, this);
27718 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27719 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27720 Roo.get(document).on('mouseup', this.onMouseUp, this);
27723 this.selectorEl.on('change', this.onFileSelected, this);
27729 this.baseScale = 1;
27731 this.baseRotate = 1;
27732 this.dragable = false;
27733 this.pinching = false;
27736 this.cropData = false;
27737 this.notifyEl.dom.innerHTML = this.emptyText;
27739 this.selectorEl.dom.value = '';
27743 resize : function()
27745 if(this.fireEvent('resize', this) != false){
27746 this.setThumbBoxPosition();
27747 this.setCanvasPosition();
27751 onFooterButtonClick : function(e, el, o, type)
27754 case 'rotate-left' :
27755 this.onRotateLeft(e);
27757 case 'rotate-right' :
27758 this.onRotateRight(e);
27761 this.beforeSelectFile(e);
27776 this.fireEvent('footerbuttonclick', this, type);
27779 beforeSelectFile : function(e)
27781 e.preventDefault();
27783 if(this.fireEvent('beforeselectfile', this) != false){
27784 this.selectorEl.dom.click();
27788 onFileSelected : function(e)
27790 e.preventDefault();
27792 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27796 var file = this.selectorEl.dom.files[0];
27798 if(this.fireEvent('inspect', this, file) != false){
27799 this.prepare(file);
27804 trash : function(e)
27806 this.fireEvent('trash', this);
27809 download : function(e)
27811 this.fireEvent('download', this);
27814 loadCanvas : function(src)
27816 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27820 this.imageEl = document.createElement('img');
27824 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27826 this.imageEl.src = src;
27830 onLoadCanvas : function()
27832 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27833 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27835 this.bodyEl.un('click', this.beforeSelectFile, this);
27837 this.notifyEl.hide();
27838 this.thumbEl.show();
27839 this.footerEl.show();
27841 this.baseRotateLevel();
27843 if(this.isDocument){
27844 this.setThumbBoxSize();
27847 this.setThumbBoxPosition();
27849 this.baseScaleLevel();
27855 this.canvasLoaded = true;
27858 this.maskEl.unmask();
27863 setCanvasPosition : function()
27865 if(!this.canvasEl){
27869 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27870 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27872 this.previewEl.setLeft(pw);
27873 this.previewEl.setTop(ph);
27877 onMouseDown : function(e)
27881 this.dragable = true;
27882 this.pinching = false;
27884 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27885 this.dragable = false;
27889 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27890 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27894 onMouseMove : function(e)
27898 if(!this.canvasLoaded){
27902 if (!this.dragable){
27906 var minX = Math.ceil(this.thumbEl.getLeft(true));
27907 var minY = Math.ceil(this.thumbEl.getTop(true));
27909 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27910 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27912 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27913 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27915 x = x - this.mouseX;
27916 y = y - this.mouseY;
27918 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27919 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27921 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27922 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27924 this.previewEl.setLeft(bgX);
27925 this.previewEl.setTop(bgY);
27927 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27928 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27931 onMouseUp : function(e)
27935 this.dragable = false;
27938 onMouseWheel : function(e)
27942 this.startScale = this.scale;
27944 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27946 if(!this.zoomable()){
27947 this.scale = this.startScale;
27956 zoomable : function()
27958 var minScale = this.thumbEl.getWidth() / this.minWidth;
27960 if(this.minWidth < this.minHeight){
27961 minScale = this.thumbEl.getHeight() / this.minHeight;
27964 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27965 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27969 (this.rotate == 0 || this.rotate == 180) &&
27971 width > this.imageEl.OriginWidth ||
27972 height > this.imageEl.OriginHeight ||
27973 (width < this.minWidth && height < this.minHeight)
27981 (this.rotate == 90 || this.rotate == 270) &&
27983 width > this.imageEl.OriginWidth ||
27984 height > this.imageEl.OriginHeight ||
27985 (width < this.minHeight && height < this.minWidth)
27992 !this.isDocument &&
27993 (this.rotate == 0 || this.rotate == 180) &&
27995 width < this.minWidth ||
27996 width > this.imageEl.OriginWidth ||
27997 height < this.minHeight ||
27998 height > this.imageEl.OriginHeight
28005 !this.isDocument &&
28006 (this.rotate == 90 || this.rotate == 270) &&
28008 width < this.minHeight ||
28009 width > this.imageEl.OriginWidth ||
28010 height < this.minWidth ||
28011 height > this.imageEl.OriginHeight
28021 onRotateLeft : function(e)
28023 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28025 var minScale = this.thumbEl.getWidth() / this.minWidth;
28027 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28028 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28030 this.startScale = this.scale;
28032 while (this.getScaleLevel() < minScale){
28034 this.scale = this.scale + 1;
28036 if(!this.zoomable()){
28041 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28042 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28047 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28054 this.scale = this.startScale;
28056 this.onRotateFail();
28061 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28063 if(this.isDocument){
28064 this.setThumbBoxSize();
28065 this.setThumbBoxPosition();
28066 this.setCanvasPosition();
28071 this.fireEvent('rotate', this, 'left');
28075 onRotateRight : function(e)
28077 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28079 var minScale = this.thumbEl.getWidth() / this.minWidth;
28081 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28082 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28084 this.startScale = this.scale;
28086 while (this.getScaleLevel() < minScale){
28088 this.scale = this.scale + 1;
28090 if(!this.zoomable()){
28095 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28096 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28101 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28108 this.scale = this.startScale;
28110 this.onRotateFail();
28115 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28117 if(this.isDocument){
28118 this.setThumbBoxSize();
28119 this.setThumbBoxPosition();
28120 this.setCanvasPosition();
28125 this.fireEvent('rotate', this, 'right');
28128 onRotateFail : function()
28130 this.errorEl.show(true);
28134 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28139 this.previewEl.dom.innerHTML = '';
28141 var canvasEl = document.createElement("canvas");
28143 var contextEl = canvasEl.getContext("2d");
28145 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28146 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28147 var center = this.imageEl.OriginWidth / 2;
28149 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28150 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28151 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28152 center = this.imageEl.OriginHeight / 2;
28155 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28157 contextEl.translate(center, center);
28158 contextEl.rotate(this.rotate * Math.PI / 180);
28160 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28162 this.canvasEl = document.createElement("canvas");
28164 this.contextEl = this.canvasEl.getContext("2d");
28166 switch (this.rotate) {
28169 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28170 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28172 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28177 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28178 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28180 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28181 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);
28185 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28190 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28191 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28193 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28194 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);
28198 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);
28203 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28204 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28206 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28207 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28211 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);
28218 this.previewEl.appendChild(this.canvasEl);
28220 this.setCanvasPosition();
28225 if(!this.canvasLoaded){
28229 var imageCanvas = document.createElement("canvas");
28231 var imageContext = imageCanvas.getContext("2d");
28233 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28234 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28236 var center = imageCanvas.width / 2;
28238 imageContext.translate(center, center);
28240 imageContext.rotate(this.rotate * Math.PI / 180);
28242 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28244 var canvas = document.createElement("canvas");
28246 var context = canvas.getContext("2d");
28248 canvas.width = this.minWidth;
28249 canvas.height = this.minHeight;
28251 switch (this.rotate) {
28254 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28255 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28257 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28258 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28260 var targetWidth = this.minWidth - 2 * x;
28261 var targetHeight = this.minHeight - 2 * y;
28265 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28266 scale = targetWidth / width;
28269 if(x > 0 && y == 0){
28270 scale = targetHeight / height;
28273 if(x > 0 && y > 0){
28274 scale = targetWidth / width;
28276 if(width < height){
28277 scale = targetHeight / height;
28281 context.scale(scale, scale);
28283 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28284 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28286 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28287 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28289 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28294 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28295 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28297 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28298 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28300 var targetWidth = this.minWidth - 2 * x;
28301 var targetHeight = this.minHeight - 2 * y;
28305 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28306 scale = targetWidth / width;
28309 if(x > 0 && y == 0){
28310 scale = targetHeight / height;
28313 if(x > 0 && y > 0){
28314 scale = targetWidth / width;
28316 if(width < height){
28317 scale = targetHeight / height;
28321 context.scale(scale, scale);
28323 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28324 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28326 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28327 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28329 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28331 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28336 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28337 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28339 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28340 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28342 var targetWidth = this.minWidth - 2 * x;
28343 var targetHeight = this.minHeight - 2 * y;
28347 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28348 scale = targetWidth / width;
28351 if(x > 0 && y == 0){
28352 scale = targetHeight / height;
28355 if(x > 0 && y > 0){
28356 scale = targetWidth / width;
28358 if(width < height){
28359 scale = targetHeight / height;
28363 context.scale(scale, scale);
28365 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28366 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28368 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28369 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28371 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28372 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28374 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28379 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28380 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28382 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28383 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28385 var targetWidth = this.minWidth - 2 * x;
28386 var targetHeight = this.minHeight - 2 * y;
28390 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28391 scale = targetWidth / width;
28394 if(x > 0 && y == 0){
28395 scale = targetHeight / height;
28398 if(x > 0 && y > 0){
28399 scale = targetWidth / width;
28401 if(width < height){
28402 scale = targetHeight / height;
28406 context.scale(scale, scale);
28408 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28409 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28411 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28412 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28414 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28416 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28423 this.cropData = canvas.toDataURL(this.cropType);
28425 if(this.fireEvent('crop', this, this.cropData) !== false){
28426 this.process(this.file, this.cropData);
28433 setThumbBoxSize : function()
28437 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28438 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28439 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28441 this.minWidth = width;
28442 this.minHeight = height;
28444 if(this.rotate == 90 || this.rotate == 270){
28445 this.minWidth = height;
28446 this.minHeight = width;
28451 width = Math.ceil(this.minWidth * height / this.minHeight);
28453 if(this.minWidth > this.minHeight){
28455 height = Math.ceil(this.minHeight * width / this.minWidth);
28458 this.thumbEl.setStyle({
28459 width : width + 'px',
28460 height : height + 'px'
28467 setThumbBoxPosition : function()
28469 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28470 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28472 this.thumbEl.setLeft(x);
28473 this.thumbEl.setTop(y);
28477 baseRotateLevel : function()
28479 this.baseRotate = 1;
28482 typeof(this.exif) != 'undefined' &&
28483 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28484 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28486 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28489 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28493 baseScaleLevel : function()
28497 if(this.isDocument){
28499 if(this.baseRotate == 6 || this.baseRotate == 8){
28501 height = this.thumbEl.getHeight();
28502 this.baseScale = height / this.imageEl.OriginWidth;
28504 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28505 width = this.thumbEl.getWidth();
28506 this.baseScale = width / this.imageEl.OriginHeight;
28512 height = this.thumbEl.getHeight();
28513 this.baseScale = height / this.imageEl.OriginHeight;
28515 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28516 width = this.thumbEl.getWidth();
28517 this.baseScale = width / this.imageEl.OriginWidth;
28523 if(this.baseRotate == 6 || this.baseRotate == 8){
28525 width = this.thumbEl.getHeight();
28526 this.baseScale = width / this.imageEl.OriginHeight;
28528 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28529 height = this.thumbEl.getWidth();
28530 this.baseScale = height / this.imageEl.OriginHeight;
28533 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28534 height = this.thumbEl.getWidth();
28535 this.baseScale = height / this.imageEl.OriginHeight;
28537 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28538 width = this.thumbEl.getHeight();
28539 this.baseScale = width / this.imageEl.OriginWidth;
28546 width = this.thumbEl.getWidth();
28547 this.baseScale = width / this.imageEl.OriginWidth;
28549 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28550 height = this.thumbEl.getHeight();
28551 this.baseScale = height / this.imageEl.OriginHeight;
28554 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28556 height = this.thumbEl.getHeight();
28557 this.baseScale = height / this.imageEl.OriginHeight;
28559 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28560 width = this.thumbEl.getWidth();
28561 this.baseScale = width / this.imageEl.OriginWidth;
28569 getScaleLevel : function()
28571 return this.baseScale * Math.pow(1.1, this.scale);
28574 onTouchStart : function(e)
28576 if(!this.canvasLoaded){
28577 this.beforeSelectFile(e);
28581 var touches = e.browserEvent.touches;
28587 if(touches.length == 1){
28588 this.onMouseDown(e);
28592 if(touches.length != 2){
28598 for(var i = 0, finger; finger = touches[i]; i++){
28599 coords.push(finger.pageX, finger.pageY);
28602 var x = Math.pow(coords[0] - coords[2], 2);
28603 var y = Math.pow(coords[1] - coords[3], 2);
28605 this.startDistance = Math.sqrt(x + y);
28607 this.startScale = this.scale;
28609 this.pinching = true;
28610 this.dragable = false;
28614 onTouchMove : function(e)
28616 if(!this.pinching && !this.dragable){
28620 var touches = e.browserEvent.touches;
28627 this.onMouseMove(e);
28633 for(var i = 0, finger; finger = touches[i]; i++){
28634 coords.push(finger.pageX, finger.pageY);
28637 var x = Math.pow(coords[0] - coords[2], 2);
28638 var y = Math.pow(coords[1] - coords[3], 2);
28640 this.endDistance = Math.sqrt(x + y);
28642 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28644 if(!this.zoomable()){
28645 this.scale = this.startScale;
28653 onTouchEnd : function(e)
28655 this.pinching = false;
28656 this.dragable = false;
28660 process : function(file, crop)
28663 this.maskEl.mask(this.loadingText);
28666 this.xhr = new XMLHttpRequest();
28668 file.xhr = this.xhr;
28670 this.xhr.open(this.method, this.url, true);
28673 "Accept": "application/json",
28674 "Cache-Control": "no-cache",
28675 "X-Requested-With": "XMLHttpRequest"
28678 for (var headerName in headers) {
28679 var headerValue = headers[headerName];
28681 this.xhr.setRequestHeader(headerName, headerValue);
28687 this.xhr.onload = function()
28689 _this.xhrOnLoad(_this.xhr);
28692 this.xhr.onerror = function()
28694 _this.xhrOnError(_this.xhr);
28697 var formData = new FormData();
28699 formData.append('returnHTML', 'NO');
28702 formData.append('crop', crop);
28705 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28706 formData.append(this.paramName, file, file.name);
28709 if(typeof(file.filename) != 'undefined'){
28710 formData.append('filename', file.filename);
28713 if(typeof(file.mimetype) != 'undefined'){
28714 formData.append('mimetype', file.mimetype);
28717 if(this.fireEvent('arrange', this, formData) != false){
28718 this.xhr.send(formData);
28722 xhrOnLoad : function(xhr)
28725 this.maskEl.unmask();
28728 if (xhr.readyState !== 4) {
28729 this.fireEvent('exception', this, xhr);
28733 var response = Roo.decode(xhr.responseText);
28735 if(!response.success){
28736 this.fireEvent('exception', this, xhr);
28740 var response = Roo.decode(xhr.responseText);
28742 this.fireEvent('upload', this, response);
28746 xhrOnError : function()
28749 this.maskEl.unmask();
28752 Roo.log('xhr on error');
28754 var response = Roo.decode(xhr.responseText);
28760 prepare : function(file)
28763 this.maskEl.mask(this.loadingText);
28769 if(typeof(file) === 'string'){
28770 this.loadCanvas(file);
28774 if(!file || !this.urlAPI){
28779 this.cropType = file.type;
28783 if(this.fireEvent('prepare', this, this.file) != false){
28785 var reader = new FileReader();
28787 reader.onload = function (e) {
28788 if (e.target.error) {
28789 Roo.log(e.target.error);
28793 var buffer = e.target.result,
28794 dataView = new DataView(buffer),
28796 maxOffset = dataView.byteLength - 4,
28800 if (dataView.getUint16(0) === 0xffd8) {
28801 while (offset < maxOffset) {
28802 markerBytes = dataView.getUint16(offset);
28804 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28805 markerLength = dataView.getUint16(offset + 2) + 2;
28806 if (offset + markerLength > dataView.byteLength) {
28807 Roo.log('Invalid meta data: Invalid segment size.');
28811 if(markerBytes == 0xffe1){
28812 _this.parseExifData(
28819 offset += markerLength;
28829 var url = _this.urlAPI.createObjectURL(_this.file);
28831 _this.loadCanvas(url);
28836 reader.readAsArrayBuffer(this.file);
28842 parseExifData : function(dataView, offset, length)
28844 var tiffOffset = offset + 10,
28848 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28849 // No Exif data, might be XMP data instead
28853 // Check for the ASCII code for "Exif" (0x45786966):
28854 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28855 // No Exif data, might be XMP data instead
28858 if (tiffOffset + 8 > dataView.byteLength) {
28859 Roo.log('Invalid Exif data: Invalid segment size.');
28862 // Check for the two null bytes:
28863 if (dataView.getUint16(offset + 8) !== 0x0000) {
28864 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28867 // Check the byte alignment:
28868 switch (dataView.getUint16(tiffOffset)) {
28870 littleEndian = true;
28873 littleEndian = false;
28876 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28879 // Check for the TIFF tag marker (0x002A):
28880 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28881 Roo.log('Invalid Exif data: Missing TIFF marker.');
28884 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28885 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28887 this.parseExifTags(
28890 tiffOffset + dirOffset,
28895 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28900 if (dirOffset + 6 > dataView.byteLength) {
28901 Roo.log('Invalid Exif data: Invalid directory offset.');
28904 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28905 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28906 if (dirEndOffset + 4 > dataView.byteLength) {
28907 Roo.log('Invalid Exif data: Invalid directory size.');
28910 for (i = 0; i < tagsNumber; i += 1) {
28914 dirOffset + 2 + 12 * i, // tag offset
28918 // Return the offset to the next directory:
28919 return dataView.getUint32(dirEndOffset, littleEndian);
28922 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28924 var tag = dataView.getUint16(offset, littleEndian);
28926 this.exif[tag] = this.getExifValue(
28930 dataView.getUint16(offset + 2, littleEndian), // tag type
28931 dataView.getUint32(offset + 4, littleEndian), // tag length
28936 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28938 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28947 Roo.log('Invalid Exif data: Invalid tag type.');
28951 tagSize = tagType.size * length;
28952 // Determine if the value is contained in the dataOffset bytes,
28953 // or if the value at the dataOffset is a pointer to the actual data:
28954 dataOffset = tagSize > 4 ?
28955 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28956 if (dataOffset + tagSize > dataView.byteLength) {
28957 Roo.log('Invalid Exif data: Invalid data offset.');
28960 if (length === 1) {
28961 return tagType.getValue(dataView, dataOffset, littleEndian);
28964 for (i = 0; i < length; i += 1) {
28965 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28968 if (tagType.ascii) {
28970 // Concatenate the chars:
28971 for (i = 0; i < values.length; i += 1) {
28973 // Ignore the terminating NULL byte(s):
28974 if (c === '\u0000') {
28986 Roo.apply(Roo.bootstrap.UploadCropbox, {
28988 'Orientation': 0x0112
28992 1: 0, //'top-left',
28994 3: 180, //'bottom-right',
28995 // 4: 'bottom-left',
28997 6: 90, //'right-top',
28998 // 7: 'right-bottom',
28999 8: 270 //'left-bottom'
29003 // byte, 8-bit unsigned int:
29005 getValue: function (dataView, dataOffset) {
29006 return dataView.getUint8(dataOffset);
29010 // ascii, 8-bit byte:
29012 getValue: function (dataView, dataOffset) {
29013 return String.fromCharCode(dataView.getUint8(dataOffset));
29018 // short, 16 bit int:
29020 getValue: function (dataView, dataOffset, littleEndian) {
29021 return dataView.getUint16(dataOffset, littleEndian);
29025 // long, 32 bit int:
29027 getValue: function (dataView, dataOffset, littleEndian) {
29028 return dataView.getUint32(dataOffset, littleEndian);
29032 // rational = two long values, first is numerator, second is denominator:
29034 getValue: function (dataView, dataOffset, littleEndian) {
29035 return dataView.getUint32(dataOffset, littleEndian) /
29036 dataView.getUint32(dataOffset + 4, littleEndian);
29040 // slong, 32 bit signed int:
29042 getValue: function (dataView, dataOffset, littleEndian) {
29043 return dataView.getInt32(dataOffset, littleEndian);
29047 // srational, two slongs, first is numerator, second is denominator:
29049 getValue: function (dataView, dataOffset, littleEndian) {
29050 return dataView.getInt32(dataOffset, littleEndian) /
29051 dataView.getInt32(dataOffset + 4, littleEndian);
29061 cls : 'btn-group roo-upload-cropbox-rotate-left',
29062 action : 'rotate-left',
29066 cls : 'btn btn-default',
29067 html : '<i class="fa fa-undo"></i>'
29073 cls : 'btn-group roo-upload-cropbox-picture',
29074 action : 'picture',
29078 cls : 'btn btn-default',
29079 html : '<i class="fa fa-picture-o"></i>'
29085 cls : 'btn-group roo-upload-cropbox-rotate-right',
29086 action : 'rotate-right',
29090 cls : 'btn btn-default',
29091 html : '<i class="fa fa-repeat"></i>'
29099 cls : 'btn-group roo-upload-cropbox-rotate-left',
29100 action : 'rotate-left',
29104 cls : 'btn btn-default',
29105 html : '<i class="fa fa-undo"></i>'
29111 cls : 'btn-group roo-upload-cropbox-download',
29112 action : 'download',
29116 cls : 'btn btn-default',
29117 html : '<i class="fa fa-download"></i>'
29123 cls : 'btn-group roo-upload-cropbox-crop',
29128 cls : 'btn btn-default',
29129 html : '<i class="fa fa-crop"></i>'
29135 cls : 'btn-group roo-upload-cropbox-trash',
29140 cls : 'btn btn-default',
29141 html : '<i class="fa fa-trash"></i>'
29147 cls : 'btn-group roo-upload-cropbox-rotate-right',
29148 action : 'rotate-right',
29152 cls : 'btn btn-default',
29153 html : '<i class="fa fa-repeat"></i>'
29161 cls : 'btn-group roo-upload-cropbox-rotate-left',
29162 action : 'rotate-left',
29166 cls : 'btn btn-default',
29167 html : '<i class="fa fa-undo"></i>'
29173 cls : 'btn-group roo-upload-cropbox-rotate-right',
29174 action : 'rotate-right',
29178 cls : 'btn btn-default',
29179 html : '<i class="fa fa-repeat"></i>'
29192 * @class Roo.bootstrap.DocumentManager
29193 * @extends Roo.bootstrap.Component
29194 * Bootstrap DocumentManager class
29195 * @cfg {String} paramName default 'imageUpload'
29196 * @cfg {String} toolTipName default 'filename'
29197 * @cfg {String} method default POST
29198 * @cfg {String} url action url
29199 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29200 * @cfg {Boolean} multiple multiple upload default true
29201 * @cfg {Number} thumbSize default 300
29202 * @cfg {String} fieldLabel
29203 * @cfg {Number} labelWidth default 4
29204 * @cfg {String} labelAlign (left|top) default left
29205 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29206 * @cfg {Number} labellg set the width of label (1-12)
29207 * @cfg {Number} labelmd set the width of label (1-12)
29208 * @cfg {Number} labelsm set the width of label (1-12)
29209 * @cfg {Number} labelxs set the width of label (1-12)
29212 * Create a new DocumentManager
29213 * @param {Object} config The config object
29216 Roo.bootstrap.DocumentManager = function(config){
29217 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29220 this.delegates = [];
29225 * Fire when initial the DocumentManager
29226 * @param {Roo.bootstrap.DocumentManager} this
29231 * inspect selected file
29232 * @param {Roo.bootstrap.DocumentManager} this
29233 * @param {File} file
29238 * Fire when xhr load exception
29239 * @param {Roo.bootstrap.DocumentManager} this
29240 * @param {XMLHttpRequest} xhr
29242 "exception" : true,
29244 * @event afterupload
29245 * Fire when xhr load exception
29246 * @param {Roo.bootstrap.DocumentManager} this
29247 * @param {XMLHttpRequest} xhr
29249 "afterupload" : true,
29252 * prepare the form data
29253 * @param {Roo.bootstrap.DocumentManager} this
29254 * @param {Object} formData
29259 * Fire when remove the file
29260 * @param {Roo.bootstrap.DocumentManager} this
29261 * @param {Object} file
29266 * Fire after refresh the file
29267 * @param {Roo.bootstrap.DocumentManager} this
29272 * Fire after click the image
29273 * @param {Roo.bootstrap.DocumentManager} this
29274 * @param {Object} file
29279 * Fire when upload a image and editable set to true
29280 * @param {Roo.bootstrap.DocumentManager} this
29281 * @param {Object} file
29285 * @event beforeselectfile
29286 * Fire before select file
29287 * @param {Roo.bootstrap.DocumentManager} this
29289 "beforeselectfile" : true,
29292 * Fire before process file
29293 * @param {Roo.bootstrap.DocumentManager} this
29294 * @param {Object} file
29298 * @event previewrendered
29299 * Fire when preview rendered
29300 * @param {Roo.bootstrap.DocumentManager} this
29301 * @param {Object} file
29303 "previewrendered" : true,
29306 "previewResize" : true
29311 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29320 paramName : 'imageUpload',
29321 toolTipName : 'filename',
29324 labelAlign : 'left',
29334 getAutoCreate : function()
29336 var managerWidget = {
29338 cls : 'roo-document-manager',
29342 cls : 'roo-document-manager-selector',
29347 cls : 'roo-document-manager-uploader',
29351 cls : 'roo-document-manager-upload-btn',
29352 html : '<i class="fa fa-plus"></i>'
29363 cls : 'column col-md-12',
29368 if(this.fieldLabel.length){
29373 cls : 'column col-md-12',
29374 html : this.fieldLabel
29378 cls : 'column col-md-12',
29383 if(this.labelAlign == 'left'){
29388 html : this.fieldLabel
29397 if(this.labelWidth > 12){
29398 content[0].style = "width: " + this.labelWidth + 'px';
29401 if(this.labelWidth < 13 && this.labelmd == 0){
29402 this.labelmd = this.labelWidth;
29405 if(this.labellg > 0){
29406 content[0].cls += ' col-lg-' + this.labellg;
29407 content[1].cls += ' col-lg-' + (12 - this.labellg);
29410 if(this.labelmd > 0){
29411 content[0].cls += ' col-md-' + this.labelmd;
29412 content[1].cls += ' col-md-' + (12 - this.labelmd);
29415 if(this.labelsm > 0){
29416 content[0].cls += ' col-sm-' + this.labelsm;
29417 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29420 if(this.labelxs > 0){
29421 content[0].cls += ' col-xs-' + this.labelxs;
29422 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29430 cls : 'row clearfix',
29438 initEvents : function()
29440 this.managerEl = this.el.select('.roo-document-manager', true).first();
29441 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29443 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29444 this.selectorEl.hide();
29447 this.selectorEl.attr('multiple', 'multiple');
29450 this.selectorEl.on('change', this.onFileSelected, this);
29452 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29453 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29455 this.uploader.on('click', this.onUploaderClick, this);
29457 this.renderProgressDialog();
29461 window.addEventListener("resize", function() { _this.refresh(); } );
29463 this.fireEvent('initial', this);
29466 renderProgressDialog : function()
29470 this.progressDialog = new Roo.bootstrap.Modal({
29471 cls : 'roo-document-manager-progress-dialog',
29472 allow_close : false,
29483 btnclick : function() {
29484 _this.uploadCancel();
29490 this.progressDialog.render(Roo.get(document.body));
29492 this.progress = new Roo.bootstrap.Progress({
29493 cls : 'roo-document-manager-progress',
29498 this.progress.render(this.progressDialog.getChildContainer());
29500 this.progressBar = new Roo.bootstrap.ProgressBar({
29501 cls : 'roo-document-manager-progress-bar',
29504 aria_valuemax : 12,
29508 this.progressBar.render(this.progress.getChildContainer());
29511 onUploaderClick : function(e)
29513 e.preventDefault();
29515 if(this.fireEvent('beforeselectfile', this) != false){
29516 this.selectorEl.dom.click();
29521 onFileSelected : function(e)
29523 e.preventDefault();
29525 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29529 Roo.each(this.selectorEl.dom.files, function(file){
29530 if(this.fireEvent('inspect', this, file) != false){
29531 this.files.push(file);
29541 this.selectorEl.dom.value = '';
29543 if(!this.files || !this.files.length){
29547 if(this.boxes > 0 && this.files.length > this.boxes){
29548 this.files = this.files.slice(0, this.boxes);
29551 this.uploader.show();
29553 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29554 this.uploader.hide();
29563 Roo.each(this.files, function(file){
29565 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29566 var f = this.renderPreview(file);
29571 if(file.type.indexOf('image') != -1){
29572 this.delegates.push(
29574 _this.process(file);
29575 }).createDelegate(this)
29583 _this.process(file);
29584 }).createDelegate(this)
29589 this.files = files;
29591 this.delegates = this.delegates.concat(docs);
29593 if(!this.delegates.length){
29598 this.progressBar.aria_valuemax = this.delegates.length;
29605 arrange : function()
29607 if(!this.delegates.length){
29608 this.progressDialog.hide();
29613 var delegate = this.delegates.shift();
29615 this.progressDialog.show();
29617 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29619 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29624 refresh : function()
29626 this.uploader.show();
29628 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29629 this.uploader.hide();
29632 Roo.isTouch ? this.closable(false) : this.closable(true);
29634 this.fireEvent('refresh', this);
29637 onRemove : function(e, el, o)
29639 e.preventDefault();
29641 this.fireEvent('remove', this, o);
29645 remove : function(o)
29649 Roo.each(this.files, function(file){
29650 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29659 this.files = files;
29666 Roo.each(this.files, function(file){
29671 file.target.remove();
29680 onClick : function(e, el, o)
29682 e.preventDefault();
29684 this.fireEvent('click', this, o);
29688 closable : function(closable)
29690 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29692 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29704 xhrOnLoad : function(xhr)
29706 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29710 if (xhr.readyState !== 4) {
29712 this.fireEvent('exception', this, xhr);
29716 var response = Roo.decode(xhr.responseText);
29718 if(!response.success){
29720 this.fireEvent('exception', this, xhr);
29724 var file = this.renderPreview(response.data);
29726 this.files.push(file);
29730 this.fireEvent('afterupload', this, xhr);
29734 xhrOnError : function(xhr)
29736 Roo.log('xhr on error');
29738 var response = Roo.decode(xhr.responseText);
29745 process : function(file)
29747 if(this.fireEvent('process', this, file) !== false){
29748 if(this.editable && file.type.indexOf('image') != -1){
29749 this.fireEvent('edit', this, file);
29753 this.uploadStart(file, false);
29760 uploadStart : function(file, crop)
29762 this.xhr = new XMLHttpRequest();
29764 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29769 file.xhr = this.xhr;
29771 this.managerEl.createChild({
29773 cls : 'roo-document-manager-loading',
29777 tooltip : file.name,
29778 cls : 'roo-document-manager-thumb',
29779 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29785 this.xhr.open(this.method, this.url, true);
29788 "Accept": "application/json",
29789 "Cache-Control": "no-cache",
29790 "X-Requested-With": "XMLHttpRequest"
29793 for (var headerName in headers) {
29794 var headerValue = headers[headerName];
29796 this.xhr.setRequestHeader(headerName, headerValue);
29802 this.xhr.onload = function()
29804 _this.xhrOnLoad(_this.xhr);
29807 this.xhr.onerror = function()
29809 _this.xhrOnError(_this.xhr);
29812 var formData = new FormData();
29814 formData.append('returnHTML', 'NO');
29817 formData.append('crop', crop);
29820 formData.append(this.paramName, file, file.name);
29827 if(this.fireEvent('prepare', this, formData, options) != false){
29829 if(options.manually){
29833 this.xhr.send(formData);
29837 this.uploadCancel();
29840 uploadCancel : function()
29846 this.delegates = [];
29848 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29855 renderPreview : function(file)
29857 if(typeof(file.target) != 'undefined' && file.target){
29861 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29863 var previewEl = this.managerEl.createChild({
29865 cls : 'roo-document-manager-preview',
29869 tooltip : file[this.toolTipName],
29870 cls : 'roo-document-manager-thumb',
29871 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29876 html : '<i class="fa fa-times-circle"></i>'
29881 var close = previewEl.select('button.close', true).first();
29883 close.on('click', this.onRemove, this, file);
29885 file.target = previewEl;
29887 var image = previewEl.select('img', true).first();
29891 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29893 image.on('click', this.onClick, this, file);
29895 this.fireEvent('previewrendered', this, file);
29901 onPreviewLoad : function(file, image)
29903 if(typeof(file.target) == 'undefined' || !file.target){
29907 var width = image.dom.naturalWidth || image.dom.width;
29908 var height = image.dom.naturalHeight || image.dom.height;
29910 if(!this.previewResize) {
29914 if(width > height){
29915 file.target.addClass('wide');
29919 file.target.addClass('tall');
29924 uploadFromSource : function(file, crop)
29926 this.xhr = new XMLHttpRequest();
29928 this.managerEl.createChild({
29930 cls : 'roo-document-manager-loading',
29934 tooltip : file.name,
29935 cls : 'roo-document-manager-thumb',
29936 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29942 this.xhr.open(this.method, this.url, true);
29945 "Accept": "application/json",
29946 "Cache-Control": "no-cache",
29947 "X-Requested-With": "XMLHttpRequest"
29950 for (var headerName in headers) {
29951 var headerValue = headers[headerName];
29953 this.xhr.setRequestHeader(headerName, headerValue);
29959 this.xhr.onload = function()
29961 _this.xhrOnLoad(_this.xhr);
29964 this.xhr.onerror = function()
29966 _this.xhrOnError(_this.xhr);
29969 var formData = new FormData();
29971 formData.append('returnHTML', 'NO');
29973 formData.append('crop', crop);
29975 if(typeof(file.filename) != 'undefined'){
29976 formData.append('filename', file.filename);
29979 if(typeof(file.mimetype) != 'undefined'){
29980 formData.append('mimetype', file.mimetype);
29985 if(this.fireEvent('prepare', this, formData) != false){
29986 this.xhr.send(formData);
29996 * @class Roo.bootstrap.DocumentViewer
29997 * @extends Roo.bootstrap.Component
29998 * Bootstrap DocumentViewer class
29999 * @cfg {Boolean} showDownload (true|false) show download button (default true)
30000 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
30003 * Create a new DocumentViewer
30004 * @param {Object} config The config object
30007 Roo.bootstrap.DocumentViewer = function(config){
30008 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
30013 * Fire after initEvent
30014 * @param {Roo.bootstrap.DocumentViewer} this
30020 * @param {Roo.bootstrap.DocumentViewer} this
30025 * Fire after download button
30026 * @param {Roo.bootstrap.DocumentViewer} this
30031 * Fire after trash button
30032 * @param {Roo.bootstrap.DocumentViewer} this
30039 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
30041 showDownload : true,
30045 getAutoCreate : function()
30049 cls : 'roo-document-viewer',
30053 cls : 'roo-document-viewer-body',
30057 cls : 'roo-document-viewer-thumb',
30061 cls : 'roo-document-viewer-image'
30069 cls : 'roo-document-viewer-footer',
30072 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30076 cls : 'btn-group roo-document-viewer-download',
30080 cls : 'btn btn-default',
30081 html : '<i class="fa fa-download"></i>'
30087 cls : 'btn-group roo-document-viewer-trash',
30091 cls : 'btn btn-default',
30092 html : '<i class="fa fa-trash"></i>'
30105 initEvents : function()
30107 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30108 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30110 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30111 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30113 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30114 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30116 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30117 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30119 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30120 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30122 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30123 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30125 this.bodyEl.on('click', this.onClick, this);
30126 this.downloadBtn.on('click', this.onDownload, this);
30127 this.trashBtn.on('click', this.onTrash, this);
30129 this.downloadBtn.hide();
30130 this.trashBtn.hide();
30132 if(this.showDownload){
30133 this.downloadBtn.show();
30136 if(this.showTrash){
30137 this.trashBtn.show();
30140 if(!this.showDownload && !this.showTrash) {
30141 this.footerEl.hide();
30146 initial : function()
30148 this.fireEvent('initial', this);
30152 onClick : function(e)
30154 e.preventDefault();
30156 this.fireEvent('click', this);
30159 onDownload : function(e)
30161 e.preventDefault();
30163 this.fireEvent('download', this);
30166 onTrash : function(e)
30168 e.preventDefault();
30170 this.fireEvent('trash', this);
30182 * @class Roo.bootstrap.NavProgressBar
30183 * @extends Roo.bootstrap.Component
30184 * Bootstrap NavProgressBar class
30187 * Create a new nav progress bar
30188 * @param {Object} config The config object
30191 Roo.bootstrap.NavProgressBar = function(config){
30192 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30194 this.bullets = this.bullets || [];
30196 // Roo.bootstrap.NavProgressBar.register(this);
30200 * Fires when the active item changes
30201 * @param {Roo.bootstrap.NavProgressBar} this
30202 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30203 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30210 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30215 getAutoCreate : function()
30217 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30221 cls : 'roo-navigation-bar-group',
30225 cls : 'roo-navigation-top-bar'
30229 cls : 'roo-navigation-bullets-bar',
30233 cls : 'roo-navigation-bar'
30240 cls : 'roo-navigation-bottom-bar'
30250 initEvents: function()
30255 onRender : function(ct, position)
30257 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30259 if(this.bullets.length){
30260 Roo.each(this.bullets, function(b){
30269 addItem : function(cfg)
30271 var item = new Roo.bootstrap.NavProgressItem(cfg);
30273 item.parentId = this.id;
30274 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30277 var top = new Roo.bootstrap.Element({
30279 cls : 'roo-navigation-bar-text'
30282 var bottom = new Roo.bootstrap.Element({
30284 cls : 'roo-navigation-bar-text'
30287 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30288 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30290 var topText = new Roo.bootstrap.Element({
30292 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30295 var bottomText = new Roo.bootstrap.Element({
30297 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30300 topText.onRender(top.el, null);
30301 bottomText.onRender(bottom.el, null);
30304 item.bottomEl = bottom;
30307 this.barItems.push(item);
30312 getActive : function()
30314 var active = false;
30316 Roo.each(this.barItems, function(v){
30318 if (!v.isActive()) {
30330 setActiveItem : function(item)
30334 Roo.each(this.barItems, function(v){
30335 if (v.rid == item.rid) {
30339 if (v.isActive()) {
30340 v.setActive(false);
30345 item.setActive(true);
30347 this.fireEvent('changed', this, item, prev);
30350 getBarItem: function(rid)
30354 Roo.each(this.barItems, function(e) {
30355 if (e.rid != rid) {
30366 indexOfItem : function(item)
30370 Roo.each(this.barItems, function(v, i){
30372 if (v.rid != item.rid) {
30383 setActiveNext : function()
30385 var i = this.indexOfItem(this.getActive());
30387 if (i > this.barItems.length) {
30391 this.setActiveItem(this.barItems[i+1]);
30394 setActivePrev : function()
30396 var i = this.indexOfItem(this.getActive());
30402 this.setActiveItem(this.barItems[i-1]);
30405 format : function()
30407 if(!this.barItems.length){
30411 var width = 100 / this.barItems.length;
30413 Roo.each(this.barItems, function(i){
30414 i.el.setStyle('width', width + '%');
30415 i.topEl.el.setStyle('width', width + '%');
30416 i.bottomEl.el.setStyle('width', width + '%');
30425 * Nav Progress Item
30430 * @class Roo.bootstrap.NavProgressItem
30431 * @extends Roo.bootstrap.Component
30432 * Bootstrap NavProgressItem class
30433 * @cfg {String} rid the reference id
30434 * @cfg {Boolean} active (true|false) Is item active default false
30435 * @cfg {Boolean} disabled (true|false) Is item active default false
30436 * @cfg {String} html
30437 * @cfg {String} position (top|bottom) text position default bottom
30438 * @cfg {String} icon show icon instead of number
30441 * Create a new NavProgressItem
30442 * @param {Object} config The config object
30444 Roo.bootstrap.NavProgressItem = function(config){
30445 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30450 * The raw click event for the entire grid.
30451 * @param {Roo.bootstrap.NavProgressItem} this
30452 * @param {Roo.EventObject} e
30459 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30465 position : 'bottom',
30468 getAutoCreate : function()
30470 var iconCls = 'roo-navigation-bar-item-icon';
30472 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30476 cls: 'roo-navigation-bar-item',
30486 cfg.cls += ' active';
30489 cfg.cls += ' disabled';
30495 disable : function()
30497 this.setDisabled(true);
30500 enable : function()
30502 this.setDisabled(false);
30505 initEvents: function()
30507 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30509 this.iconEl.on('click', this.onClick, this);
30512 onClick : function(e)
30514 e.preventDefault();
30520 if(this.fireEvent('click', this, e) === false){
30524 this.parent().setActiveItem(this);
30527 isActive: function ()
30529 return this.active;
30532 setActive : function(state)
30534 if(this.active == state){
30538 this.active = state;
30541 this.el.addClass('active');
30545 this.el.removeClass('active');
30550 setDisabled : function(state)
30552 if(this.disabled == state){
30556 this.disabled = state;
30559 this.el.addClass('disabled');
30563 this.el.removeClass('disabled');
30566 tooltipEl : function()
30568 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30581 * @class Roo.bootstrap.FieldLabel
30582 * @extends Roo.bootstrap.Component
30583 * Bootstrap FieldLabel class
30584 * @cfg {String} html contents of the element
30585 * @cfg {String} tag tag of the element default label
30586 * @cfg {String} cls class of the element
30587 * @cfg {String} target label target
30588 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30589 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30590 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30591 * @cfg {String} iconTooltip default "This field is required"
30592 * @cfg {String} indicatorpos (left|right) default left
30595 * Create a new FieldLabel
30596 * @param {Object} config The config object
30599 Roo.bootstrap.FieldLabel = function(config){
30600 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30605 * Fires after the field has been marked as invalid.
30606 * @param {Roo.form.FieldLabel} this
30607 * @param {String} msg The validation message
30612 * Fires after the field has been validated with no errors.
30613 * @param {Roo.form.FieldLabel} this
30619 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30626 invalidClass : 'has-warning',
30627 validClass : 'has-success',
30628 iconTooltip : 'This field is required',
30629 indicatorpos : 'left',
30631 getAutoCreate : function(){
30634 if (!this.allowBlank) {
30640 cls : 'roo-bootstrap-field-label ' + this.cls,
30645 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30646 tooltip : this.iconTooltip
30655 if(this.indicatorpos == 'right'){
30658 cls : 'roo-bootstrap-field-label ' + this.cls,
30667 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30668 tooltip : this.iconTooltip
30677 initEvents: function()
30679 Roo.bootstrap.Element.superclass.initEvents.call(this);
30681 this.indicator = this.indicatorEl();
30683 if(this.indicator){
30684 this.indicator.removeClass('visible');
30685 this.indicator.addClass('invisible');
30688 Roo.bootstrap.FieldLabel.register(this);
30691 indicatorEl : function()
30693 var indicator = this.el.select('i.roo-required-indicator',true).first();
30704 * Mark this field as valid
30706 markValid : function()
30708 if(this.indicator){
30709 this.indicator.removeClass('visible');
30710 this.indicator.addClass('invisible');
30712 if (Roo.bootstrap.version == 3) {
30713 this.el.removeClass(this.invalidClass);
30714 this.el.addClass(this.validClass);
30716 this.el.removeClass('is-invalid');
30717 this.el.addClass('is-valid');
30721 this.fireEvent('valid', this);
30725 * Mark this field as invalid
30726 * @param {String} msg The validation message
30728 markInvalid : function(msg)
30730 if(this.indicator){
30731 this.indicator.removeClass('invisible');
30732 this.indicator.addClass('visible');
30734 if (Roo.bootstrap.version == 3) {
30735 this.el.removeClass(this.validClass);
30736 this.el.addClass(this.invalidClass);
30738 this.el.removeClass('is-valid');
30739 this.el.addClass('is-invalid');
30743 this.fireEvent('invalid', this, msg);
30749 Roo.apply(Roo.bootstrap.FieldLabel, {
30754 * register a FieldLabel Group
30755 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30757 register : function(label)
30759 if(this.groups.hasOwnProperty(label.target)){
30763 this.groups[label.target] = label;
30767 * fetch a FieldLabel Group based on the target
30768 * @param {string} target
30769 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30771 get: function(target) {
30772 if (typeof(this.groups[target]) == 'undefined') {
30776 return this.groups[target] ;
30785 * page DateSplitField.
30791 * @class Roo.bootstrap.DateSplitField
30792 * @extends Roo.bootstrap.Component
30793 * Bootstrap DateSplitField class
30794 * @cfg {string} fieldLabel - the label associated
30795 * @cfg {Number} labelWidth set the width of label (0-12)
30796 * @cfg {String} labelAlign (top|left)
30797 * @cfg {Boolean} dayAllowBlank (true|false) default false
30798 * @cfg {Boolean} monthAllowBlank (true|false) default false
30799 * @cfg {Boolean} yearAllowBlank (true|false) default false
30800 * @cfg {string} dayPlaceholder
30801 * @cfg {string} monthPlaceholder
30802 * @cfg {string} yearPlaceholder
30803 * @cfg {string} dayFormat default 'd'
30804 * @cfg {string} monthFormat default 'm'
30805 * @cfg {string} yearFormat default 'Y'
30806 * @cfg {Number} labellg set the width of label (1-12)
30807 * @cfg {Number} labelmd set the width of label (1-12)
30808 * @cfg {Number} labelsm set the width of label (1-12)
30809 * @cfg {Number} labelxs set the width of label (1-12)
30813 * Create a new DateSplitField
30814 * @param {Object} config The config object
30817 Roo.bootstrap.DateSplitField = function(config){
30818 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30824 * getting the data of years
30825 * @param {Roo.bootstrap.DateSplitField} this
30826 * @param {Object} years
30831 * getting the data of days
30832 * @param {Roo.bootstrap.DateSplitField} this
30833 * @param {Object} days
30838 * Fires after the field has been marked as invalid.
30839 * @param {Roo.form.Field} this
30840 * @param {String} msg The validation message
30845 * Fires after the field has been validated with no errors.
30846 * @param {Roo.form.Field} this
30852 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30855 labelAlign : 'top',
30857 dayAllowBlank : false,
30858 monthAllowBlank : false,
30859 yearAllowBlank : false,
30860 dayPlaceholder : '',
30861 monthPlaceholder : '',
30862 yearPlaceholder : '',
30866 isFormField : true,
30872 getAutoCreate : function()
30876 cls : 'row roo-date-split-field-group',
30881 cls : 'form-hidden-field roo-date-split-field-group-value',
30887 var labelCls = 'col-md-12';
30888 var contentCls = 'col-md-4';
30890 if(this.fieldLabel){
30894 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30898 html : this.fieldLabel
30903 if(this.labelAlign == 'left'){
30905 if(this.labelWidth > 12){
30906 label.style = "width: " + this.labelWidth + 'px';
30909 if(this.labelWidth < 13 && this.labelmd == 0){
30910 this.labelmd = this.labelWidth;
30913 if(this.labellg > 0){
30914 labelCls = ' col-lg-' + this.labellg;
30915 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30918 if(this.labelmd > 0){
30919 labelCls = ' col-md-' + this.labelmd;
30920 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30923 if(this.labelsm > 0){
30924 labelCls = ' col-sm-' + this.labelsm;
30925 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30928 if(this.labelxs > 0){
30929 labelCls = ' col-xs-' + this.labelxs;
30930 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30934 label.cls += ' ' + labelCls;
30936 cfg.cn.push(label);
30939 Roo.each(['day', 'month', 'year'], function(t){
30942 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30949 inputEl: function ()
30951 return this.el.select('.roo-date-split-field-group-value', true).first();
30954 onRender : function(ct, position)
30958 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30960 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30962 this.dayField = new Roo.bootstrap.ComboBox({
30963 allowBlank : this.dayAllowBlank,
30964 alwaysQuery : true,
30965 displayField : 'value',
30968 forceSelection : true,
30970 placeholder : this.dayPlaceholder,
30971 selectOnFocus : true,
30972 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30973 triggerAction : 'all',
30975 valueField : 'value',
30976 store : new Roo.data.SimpleStore({
30977 data : (function() {
30979 _this.fireEvent('days', _this, days);
30982 fields : [ 'value' ]
30985 select : function (_self, record, index)
30987 _this.setValue(_this.getValue());
30992 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30994 this.monthField = new Roo.bootstrap.MonthField({
30995 after : '<i class=\"fa fa-calendar\"></i>',
30996 allowBlank : this.monthAllowBlank,
30997 placeholder : this.monthPlaceholder,
31000 render : function (_self)
31002 this.el.select('span.input-group-addon', true).first().on('click', function(e){
31003 e.preventDefault();
31007 select : function (_self, oldvalue, newvalue)
31009 _this.setValue(_this.getValue());
31014 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
31016 this.yearField = new Roo.bootstrap.ComboBox({
31017 allowBlank : this.yearAllowBlank,
31018 alwaysQuery : true,
31019 displayField : 'value',
31022 forceSelection : true,
31024 placeholder : this.yearPlaceholder,
31025 selectOnFocus : true,
31026 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
31027 triggerAction : 'all',
31029 valueField : 'value',
31030 store : new Roo.data.SimpleStore({
31031 data : (function() {
31033 _this.fireEvent('years', _this, years);
31036 fields : [ 'value' ]
31039 select : function (_self, record, index)
31041 _this.setValue(_this.getValue());
31046 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
31049 setValue : function(v, format)
31051 this.inputEl.dom.value = v;
31053 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31055 var d = Date.parseDate(v, f);
31062 this.setDay(d.format(this.dayFormat));
31063 this.setMonth(d.format(this.monthFormat));
31064 this.setYear(d.format(this.yearFormat));
31071 setDay : function(v)
31073 this.dayField.setValue(v);
31074 this.inputEl.dom.value = this.getValue();
31079 setMonth : function(v)
31081 this.monthField.setValue(v, true);
31082 this.inputEl.dom.value = this.getValue();
31087 setYear : function(v)
31089 this.yearField.setValue(v);
31090 this.inputEl.dom.value = this.getValue();
31095 getDay : function()
31097 return this.dayField.getValue();
31100 getMonth : function()
31102 return this.monthField.getValue();
31105 getYear : function()
31107 return this.yearField.getValue();
31110 getValue : function()
31112 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31114 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31124 this.inputEl.dom.value = '';
31129 validate : function()
31131 var d = this.dayField.validate();
31132 var m = this.monthField.validate();
31133 var y = this.yearField.validate();
31138 (!this.dayAllowBlank && !d) ||
31139 (!this.monthAllowBlank && !m) ||
31140 (!this.yearAllowBlank && !y)
31145 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31154 this.markInvalid();
31159 markValid : function()
31162 var label = this.el.select('label', true).first();
31163 var icon = this.el.select('i.fa-star', true).first();
31169 this.fireEvent('valid', this);
31173 * Mark this field as invalid
31174 * @param {String} msg The validation message
31176 markInvalid : function(msg)
31179 var label = this.el.select('label', true).first();
31180 var icon = this.el.select('i.fa-star', true).first();
31182 if(label && !icon){
31183 this.el.select('.roo-date-split-field-label', true).createChild({
31185 cls : 'text-danger fa fa-lg fa-star',
31186 tooltip : 'This field is required',
31187 style : 'margin-right:5px;'
31191 this.fireEvent('invalid', this, msg);
31194 clearInvalid : function()
31196 var label = this.el.select('label', true).first();
31197 var icon = this.el.select('i.fa-star', true).first();
31203 this.fireEvent('valid', this);
31206 getName: function()
31216 * http://masonry.desandro.com
31218 * The idea is to render all the bricks based on vertical width...
31220 * The original code extends 'outlayer' - we might need to use that....
31226 * @class Roo.bootstrap.LayoutMasonry
31227 * @extends Roo.bootstrap.Component
31228 * Bootstrap Layout Masonry class
31231 * Create a new Element
31232 * @param {Object} config The config object
31235 Roo.bootstrap.LayoutMasonry = function(config){
31237 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31241 Roo.bootstrap.LayoutMasonry.register(this);
31247 * Fire after layout the items
31248 * @param {Roo.bootstrap.LayoutMasonry} this
31249 * @param {Roo.EventObject} e
31256 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31259 * @cfg {Boolean} isLayoutInstant = no animation?
31261 isLayoutInstant : false, // needed?
31264 * @cfg {Number} boxWidth width of the columns
31269 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31274 * @cfg {Number} padWidth padding below box..
31279 * @cfg {Number} gutter gutter width..
31284 * @cfg {Number} maxCols maximum number of columns
31290 * @cfg {Boolean} isAutoInitial defalut true
31292 isAutoInitial : true,
31297 * @cfg {Boolean} isHorizontal defalut false
31299 isHorizontal : false,
31301 currentSize : null,
31307 bricks: null, //CompositeElement
31311 _isLayoutInited : false,
31313 // isAlternative : false, // only use for vertical layout...
31316 * @cfg {Number} alternativePadWidth padding below box..
31318 alternativePadWidth : 50,
31320 selectedBrick : [],
31322 getAutoCreate : function(){
31324 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31328 cls: 'blog-masonary-wrapper ' + this.cls,
31330 cls : 'mas-boxes masonary'
31337 getChildContainer: function( )
31339 if (this.boxesEl) {
31340 return this.boxesEl;
31343 this.boxesEl = this.el.select('.mas-boxes').first();
31345 return this.boxesEl;
31349 initEvents : function()
31353 if(this.isAutoInitial){
31354 Roo.log('hook children rendered');
31355 this.on('childrenrendered', function() {
31356 Roo.log('children rendered');
31362 initial : function()
31364 this.selectedBrick = [];
31366 this.currentSize = this.el.getBox(true);
31368 Roo.EventManager.onWindowResize(this.resize, this);
31370 if(!this.isAutoInitial){
31378 //this.layout.defer(500,this);
31382 resize : function()
31384 var cs = this.el.getBox(true);
31387 this.currentSize.width == cs.width &&
31388 this.currentSize.x == cs.x &&
31389 this.currentSize.height == cs.height &&
31390 this.currentSize.y == cs.y
31392 Roo.log("no change in with or X or Y");
31396 this.currentSize = cs;
31402 layout : function()
31404 this._resetLayout();
31406 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31408 this.layoutItems( isInstant );
31410 this._isLayoutInited = true;
31412 this.fireEvent('layout', this);
31416 _resetLayout : function()
31418 if(this.isHorizontal){
31419 this.horizontalMeasureColumns();
31423 this.verticalMeasureColumns();
31427 verticalMeasureColumns : function()
31429 this.getContainerWidth();
31431 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31432 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31436 var boxWidth = this.boxWidth + this.padWidth;
31438 if(this.containerWidth < this.boxWidth){
31439 boxWidth = this.containerWidth
31442 var containerWidth = this.containerWidth;
31444 var cols = Math.floor(containerWidth / boxWidth);
31446 this.cols = Math.max( cols, 1 );
31448 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31450 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31452 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31454 this.colWidth = boxWidth + avail - this.padWidth;
31456 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31457 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31460 horizontalMeasureColumns : function()
31462 this.getContainerWidth();
31464 var boxWidth = this.boxWidth;
31466 if(this.containerWidth < boxWidth){
31467 boxWidth = this.containerWidth;
31470 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31472 this.el.setHeight(boxWidth);
31476 getContainerWidth : function()
31478 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31481 layoutItems : function( isInstant )
31483 Roo.log(this.bricks);
31485 var items = Roo.apply([], this.bricks);
31487 if(this.isHorizontal){
31488 this._horizontalLayoutItems( items , isInstant );
31492 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31493 // this._verticalAlternativeLayoutItems( items , isInstant );
31497 this._verticalLayoutItems( items , isInstant );
31501 _verticalLayoutItems : function ( items , isInstant)
31503 if ( !items || !items.length ) {
31508 ['xs', 'xs', 'xs', 'tall'],
31509 ['xs', 'xs', 'tall'],
31510 ['xs', 'xs', 'sm'],
31511 ['xs', 'xs', 'xs'],
31517 ['sm', 'xs', 'xs'],
31521 ['tall', 'xs', 'xs', 'xs'],
31522 ['tall', 'xs', 'xs'],
31534 Roo.each(items, function(item, k){
31536 switch (item.size) {
31537 // these layouts take up a full box,
31548 boxes.push([item]);
31571 var filterPattern = function(box, length)
31579 var pattern = box.slice(0, length);
31583 Roo.each(pattern, function(i){
31584 format.push(i.size);
31587 Roo.each(standard, function(s){
31589 if(String(s) != String(format)){
31598 if(!match && length == 1){
31603 filterPattern(box, length - 1);
31607 queue.push(pattern);
31609 box = box.slice(length, box.length);
31611 filterPattern(box, 4);
31617 Roo.each(boxes, function(box, k){
31623 if(box.length == 1){
31628 filterPattern(box, 4);
31632 this._processVerticalLayoutQueue( queue, isInstant );
31636 // _verticalAlternativeLayoutItems : function( items , isInstant )
31638 // if ( !items || !items.length ) {
31642 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31646 _horizontalLayoutItems : function ( items , isInstant)
31648 if ( !items || !items.length || items.length < 3) {
31654 var eItems = items.slice(0, 3);
31656 items = items.slice(3, items.length);
31659 ['xs', 'xs', 'xs', 'wide'],
31660 ['xs', 'xs', 'wide'],
31661 ['xs', 'xs', 'sm'],
31662 ['xs', 'xs', 'xs'],
31668 ['sm', 'xs', 'xs'],
31672 ['wide', 'xs', 'xs', 'xs'],
31673 ['wide', 'xs', 'xs'],
31686 Roo.each(items, function(item, k){
31688 switch (item.size) {
31699 boxes.push([item]);
31723 var filterPattern = function(box, length)
31731 var pattern = box.slice(0, length);
31735 Roo.each(pattern, function(i){
31736 format.push(i.size);
31739 Roo.each(standard, function(s){
31741 if(String(s) != String(format)){
31750 if(!match && length == 1){
31755 filterPattern(box, length - 1);
31759 queue.push(pattern);
31761 box = box.slice(length, box.length);
31763 filterPattern(box, 4);
31769 Roo.each(boxes, function(box, k){
31775 if(box.length == 1){
31780 filterPattern(box, 4);
31787 var pos = this.el.getBox(true);
31791 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31793 var hit_end = false;
31795 Roo.each(queue, function(box){
31799 Roo.each(box, function(b){
31801 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31811 Roo.each(box, function(b){
31813 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31816 mx = Math.max(mx, b.x);
31820 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31824 Roo.each(box, function(b){
31826 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31840 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31843 /** Sets position of item in DOM
31844 * @param {Element} item
31845 * @param {Number} x - horizontal position
31846 * @param {Number} y - vertical position
31847 * @param {Boolean} isInstant - disables transitions
31849 _processVerticalLayoutQueue : function( queue, isInstant )
31851 var pos = this.el.getBox(true);
31856 for (var i = 0; i < this.cols; i++){
31860 Roo.each(queue, function(box, k){
31862 var col = k % this.cols;
31864 Roo.each(box, function(b,kk){
31866 b.el.position('absolute');
31868 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31869 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31871 if(b.size == 'md-left' || b.size == 'md-right'){
31872 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31873 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31876 b.el.setWidth(width);
31877 b.el.setHeight(height);
31879 b.el.select('iframe',true).setSize(width,height);
31883 for (var i = 0; i < this.cols; i++){
31885 if(maxY[i] < maxY[col]){
31890 col = Math.min(col, i);
31894 x = pos.x + col * (this.colWidth + this.padWidth);
31898 var positions = [];
31900 switch (box.length){
31902 positions = this.getVerticalOneBoxColPositions(x, y, box);
31905 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31908 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31911 positions = this.getVerticalFourBoxColPositions(x, y, box);
31917 Roo.each(box, function(b,kk){
31919 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31921 var sz = b.el.getSize();
31923 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31931 for (var i = 0; i < this.cols; i++){
31932 mY = Math.max(mY, maxY[i]);
31935 this.el.setHeight(mY - pos.y);
31939 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31941 // var pos = this.el.getBox(true);
31944 // var maxX = pos.right;
31946 // var maxHeight = 0;
31948 // Roo.each(items, function(item, k){
31952 // item.el.position('absolute');
31954 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31956 // item.el.setWidth(width);
31958 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31960 // item.el.setHeight(height);
31963 // item.el.setXY([x, y], isInstant ? false : true);
31965 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31968 // y = y + height + this.alternativePadWidth;
31970 // maxHeight = maxHeight + height + this.alternativePadWidth;
31974 // this.el.setHeight(maxHeight);
31978 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31980 var pos = this.el.getBox(true);
31985 var maxX = pos.right;
31987 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31989 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31991 Roo.each(queue, function(box, k){
31993 Roo.each(box, function(b, kk){
31995 b.el.position('absolute');
31997 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31998 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32000 if(b.size == 'md-left' || b.size == 'md-right'){
32001 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
32002 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
32005 b.el.setWidth(width);
32006 b.el.setHeight(height);
32014 var positions = [];
32016 switch (box.length){
32018 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
32021 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
32024 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
32027 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
32033 Roo.each(box, function(b,kk){
32035 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
32037 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
32045 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
32047 Roo.each(eItems, function(b,k){
32049 b.size = (k == 0) ? 'sm' : 'xs';
32050 b.x = (k == 0) ? 2 : 1;
32051 b.y = (k == 0) ? 2 : 1;
32053 b.el.position('absolute');
32055 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32057 b.el.setWidth(width);
32059 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32061 b.el.setHeight(height);
32065 var positions = [];
32068 x : maxX - this.unitWidth * 2 - this.gutter,
32073 x : maxX - this.unitWidth,
32074 y : minY + (this.unitWidth + this.gutter) * 2
32078 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32082 Roo.each(eItems, function(b,k){
32084 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32090 getVerticalOneBoxColPositions : function(x, y, box)
32094 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32096 if(box[0].size == 'md-left'){
32100 if(box[0].size == 'md-right'){
32105 x : x + (this.unitWidth + this.gutter) * rand,
32112 getVerticalTwoBoxColPositions : function(x, y, box)
32116 if(box[0].size == 'xs'){
32120 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32124 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32138 x : x + (this.unitWidth + this.gutter) * 2,
32139 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32146 getVerticalThreeBoxColPositions : function(x, y, box)
32150 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32158 x : x + (this.unitWidth + this.gutter) * 1,
32163 x : x + (this.unitWidth + this.gutter) * 2,
32171 if(box[0].size == 'xs' && box[1].size == 'xs'){
32180 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32184 x : x + (this.unitWidth + this.gutter) * 1,
32198 x : x + (this.unitWidth + this.gutter) * 2,
32203 x : x + (this.unitWidth + this.gutter) * 2,
32204 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32211 getVerticalFourBoxColPositions : function(x, y, box)
32215 if(box[0].size == 'xs'){
32224 y : y + (this.unitHeight + this.gutter) * 1
32229 y : y + (this.unitHeight + this.gutter) * 2
32233 x : x + (this.unitWidth + this.gutter) * 1,
32247 x : x + (this.unitWidth + this.gutter) * 2,
32252 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32253 y : y + (this.unitHeight + this.gutter) * 1
32257 x : x + (this.unitWidth + this.gutter) * 2,
32258 y : y + (this.unitWidth + this.gutter) * 2
32265 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32269 if(box[0].size == 'md-left'){
32271 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32278 if(box[0].size == 'md-right'){
32280 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32281 y : minY + (this.unitWidth + this.gutter) * 1
32287 var rand = Math.floor(Math.random() * (4 - box[0].y));
32290 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32291 y : minY + (this.unitWidth + this.gutter) * rand
32298 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32302 if(box[0].size == 'xs'){
32305 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32310 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32311 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32319 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32324 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32325 y : minY + (this.unitWidth + this.gutter) * 2
32332 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32336 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32339 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32344 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32345 y : minY + (this.unitWidth + this.gutter) * 1
32349 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32350 y : minY + (this.unitWidth + this.gutter) * 2
32357 if(box[0].size == 'xs' && box[1].size == 'xs'){
32360 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32365 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32370 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32371 y : minY + (this.unitWidth + this.gutter) * 1
32379 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32384 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32385 y : minY + (this.unitWidth + this.gutter) * 2
32389 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32390 y : minY + (this.unitWidth + this.gutter) * 2
32397 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32401 if(box[0].size == 'xs'){
32404 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32409 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32414 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),
32419 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32420 y : minY + (this.unitWidth + this.gutter) * 1
32428 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32433 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32434 y : minY + (this.unitWidth + this.gutter) * 2
32438 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32439 y : minY + (this.unitWidth + this.gutter) * 2
32443 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),
32444 y : minY + (this.unitWidth + this.gutter) * 2
32452 * remove a Masonry Brick
32453 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32455 removeBrick : function(brick_id)
32461 for (var i = 0; i<this.bricks.length; i++) {
32462 if (this.bricks[i].id == brick_id) {
32463 this.bricks.splice(i,1);
32464 this.el.dom.removeChild(Roo.get(brick_id).dom);
32471 * adds a Masonry Brick
32472 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32474 addBrick : function(cfg)
32476 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32477 //this.register(cn);
32478 cn.parentId = this.id;
32479 cn.render(this.el);
32484 * register a Masonry Brick
32485 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32488 register : function(brick)
32490 this.bricks.push(brick);
32491 brick.masonryId = this.id;
32495 * clear all the Masonry Brick
32497 clearAll : function()
32500 //this.getChildContainer().dom.innerHTML = "";
32501 this.el.dom.innerHTML = '';
32504 getSelected : function()
32506 if (!this.selectedBrick) {
32510 return this.selectedBrick;
32514 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32518 * register a Masonry Layout
32519 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32522 register : function(layout)
32524 this.groups[layout.id] = layout;
32527 * fetch a Masonry Layout based on the masonry layout ID
32528 * @param {string} the masonry layout to add
32529 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32532 get: function(layout_id) {
32533 if (typeof(this.groups[layout_id]) == 'undefined') {
32536 return this.groups[layout_id] ;
32548 * http://masonry.desandro.com
32550 * The idea is to render all the bricks based on vertical width...
32552 * The original code extends 'outlayer' - we might need to use that....
32558 * @class Roo.bootstrap.LayoutMasonryAuto
32559 * @extends Roo.bootstrap.Component
32560 * Bootstrap Layout Masonry class
32563 * Create a new Element
32564 * @param {Object} config The config object
32567 Roo.bootstrap.LayoutMasonryAuto = function(config){
32568 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32571 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32574 * @cfg {Boolean} isFitWidth - resize the width..
32576 isFitWidth : false, // options..
32578 * @cfg {Boolean} isOriginLeft = left align?
32580 isOriginLeft : true,
32582 * @cfg {Boolean} isOriginTop = top align?
32584 isOriginTop : false,
32586 * @cfg {Boolean} isLayoutInstant = no animation?
32588 isLayoutInstant : false, // needed?
32590 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32592 isResizingContainer : true,
32594 * @cfg {Number} columnWidth width of the columns
32600 * @cfg {Number} maxCols maximum number of columns
32605 * @cfg {Number} padHeight padding below box..
32611 * @cfg {Boolean} isAutoInitial defalut true
32614 isAutoInitial : true,
32620 initialColumnWidth : 0,
32621 currentSize : null,
32623 colYs : null, // array.
32630 bricks: null, //CompositeElement
32631 cols : 0, // array?
32632 // element : null, // wrapped now this.el
32633 _isLayoutInited : null,
32636 getAutoCreate : function(){
32640 cls: 'blog-masonary-wrapper ' + this.cls,
32642 cls : 'mas-boxes masonary'
32649 getChildContainer: function( )
32651 if (this.boxesEl) {
32652 return this.boxesEl;
32655 this.boxesEl = this.el.select('.mas-boxes').first();
32657 return this.boxesEl;
32661 initEvents : function()
32665 if(this.isAutoInitial){
32666 Roo.log('hook children rendered');
32667 this.on('childrenrendered', function() {
32668 Roo.log('children rendered');
32675 initial : function()
32677 this.reloadItems();
32679 this.currentSize = this.el.getBox(true);
32681 /// was window resize... - let's see if this works..
32682 Roo.EventManager.onWindowResize(this.resize, this);
32684 if(!this.isAutoInitial){
32689 this.layout.defer(500,this);
32692 reloadItems: function()
32694 this.bricks = this.el.select('.masonry-brick', true);
32696 this.bricks.each(function(b) {
32697 //Roo.log(b.getSize());
32698 if (!b.attr('originalwidth')) {
32699 b.attr('originalwidth', b.getSize().width);
32704 Roo.log(this.bricks.elements.length);
32707 resize : function()
32710 var cs = this.el.getBox(true);
32712 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32713 Roo.log("no change in with or X");
32716 this.currentSize = cs;
32720 layout : function()
32723 this._resetLayout();
32724 //this._manageStamps();
32726 // don't animate first layout
32727 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32728 this.layoutItems( isInstant );
32730 // flag for initalized
32731 this._isLayoutInited = true;
32734 layoutItems : function( isInstant )
32736 //var items = this._getItemsForLayout( this.items );
32737 // original code supports filtering layout items.. we just ignore it..
32739 this._layoutItems( this.bricks , isInstant );
32741 this._postLayout();
32743 _layoutItems : function ( items , isInstant)
32745 //this.fireEvent( 'layout', this, items );
32748 if ( !items || !items.elements.length ) {
32749 // no items, emit event with empty array
32754 items.each(function(item) {
32755 Roo.log("layout item");
32757 // get x/y object from method
32758 var position = this._getItemLayoutPosition( item );
32760 position.item = item;
32761 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32762 queue.push( position );
32765 this._processLayoutQueue( queue );
32767 /** Sets position of item in DOM
32768 * @param {Element} item
32769 * @param {Number} x - horizontal position
32770 * @param {Number} y - vertical position
32771 * @param {Boolean} isInstant - disables transitions
32773 _processLayoutQueue : function( queue )
32775 for ( var i=0, len = queue.length; i < len; i++ ) {
32776 var obj = queue[i];
32777 obj.item.position('absolute');
32778 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32784 * Any logic you want to do after each layout,
32785 * i.e. size the container
32787 _postLayout : function()
32789 this.resizeContainer();
32792 resizeContainer : function()
32794 if ( !this.isResizingContainer ) {
32797 var size = this._getContainerSize();
32799 this.el.setSize(size.width,size.height);
32800 this.boxesEl.setSize(size.width,size.height);
32806 _resetLayout : function()
32808 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32809 this.colWidth = this.el.getWidth();
32810 //this.gutter = this.el.getWidth();
32812 this.measureColumns();
32818 this.colYs.push( 0 );
32824 measureColumns : function()
32826 this.getContainerWidth();
32827 // if columnWidth is 0, default to outerWidth of first item
32828 if ( !this.columnWidth ) {
32829 var firstItem = this.bricks.first();
32830 Roo.log(firstItem);
32831 this.columnWidth = this.containerWidth;
32832 if (firstItem && firstItem.attr('originalwidth') ) {
32833 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32835 // columnWidth fall back to item of first element
32836 Roo.log("set column width?");
32837 this.initialColumnWidth = this.columnWidth ;
32839 // if first elem has no width, default to size of container
32844 if (this.initialColumnWidth) {
32845 this.columnWidth = this.initialColumnWidth;
32850 // column width is fixed at the top - however if container width get's smaller we should
32853 // this bit calcs how man columns..
32855 var columnWidth = this.columnWidth += this.gutter;
32857 // calculate columns
32858 var containerWidth = this.containerWidth + this.gutter;
32860 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32861 // fix rounding errors, typically with gutters
32862 var excess = columnWidth - containerWidth % columnWidth;
32865 // if overshoot is less than a pixel, round up, otherwise floor it
32866 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32867 cols = Math[ mathMethod ]( cols );
32868 this.cols = Math.max( cols, 1 );
32869 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32871 // padding positioning..
32872 var totalColWidth = this.cols * this.columnWidth;
32873 var padavail = this.containerWidth - totalColWidth;
32874 // so for 2 columns - we need 3 'pads'
32876 var padNeeded = (1+this.cols) * this.padWidth;
32878 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32880 this.columnWidth += padExtra
32881 //this.padWidth = Math.floor(padavail / ( this.cols));
32883 // adjust colum width so that padding is fixed??
32885 // we have 3 columns ... total = width * 3
32886 // we have X left over... that should be used by
32888 //if (this.expandC) {
32896 getContainerWidth : function()
32898 /* // container is parent if fit width
32899 var container = this.isFitWidth ? this.element.parentNode : this.element;
32900 // check that this.size and size are there
32901 // IE8 triggers resize on body size change, so they might not be
32903 var size = getSize( container ); //FIXME
32904 this.containerWidth = size && size.innerWidth; //FIXME
32907 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32911 _getItemLayoutPosition : function( item ) // what is item?
32913 // we resize the item to our columnWidth..
32915 item.setWidth(this.columnWidth);
32916 item.autoBoxAdjust = false;
32918 var sz = item.getSize();
32920 // how many columns does this brick span
32921 var remainder = this.containerWidth % this.columnWidth;
32923 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32924 // round if off by 1 pixel, otherwise use ceil
32925 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32926 colSpan = Math.min( colSpan, this.cols );
32928 // normally this should be '1' as we dont' currently allow multi width columns..
32930 var colGroup = this._getColGroup( colSpan );
32931 // get the minimum Y value from the columns
32932 var minimumY = Math.min.apply( Math, colGroup );
32933 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32935 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32937 // position the brick
32939 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32940 y: this.currentSize.y + minimumY + this.padHeight
32944 // apply setHeight to necessary columns
32945 var setHeight = minimumY + sz.height + this.padHeight;
32946 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32948 var setSpan = this.cols + 1 - colGroup.length;
32949 for ( var i = 0; i < setSpan; i++ ) {
32950 this.colYs[ shortColIndex + i ] = setHeight ;
32957 * @param {Number} colSpan - number of columns the element spans
32958 * @returns {Array} colGroup
32960 _getColGroup : function( colSpan )
32962 if ( colSpan < 2 ) {
32963 // if brick spans only one column, use all the column Ys
32968 // how many different places could this brick fit horizontally
32969 var groupCount = this.cols + 1 - colSpan;
32970 // for each group potential horizontal position
32971 for ( var i = 0; i < groupCount; i++ ) {
32972 // make an array of colY values for that one group
32973 var groupColYs = this.colYs.slice( i, i + colSpan );
32974 // and get the max value of the array
32975 colGroup[i] = Math.max.apply( Math, groupColYs );
32980 _manageStamp : function( stamp )
32982 var stampSize = stamp.getSize();
32983 var offset = stamp.getBox();
32984 // get the columns that this stamp affects
32985 var firstX = this.isOriginLeft ? offset.x : offset.right;
32986 var lastX = firstX + stampSize.width;
32987 var firstCol = Math.floor( firstX / this.columnWidth );
32988 firstCol = Math.max( 0, firstCol );
32990 var lastCol = Math.floor( lastX / this.columnWidth );
32991 // lastCol should not go over if multiple of columnWidth #425
32992 lastCol -= lastX % this.columnWidth ? 0 : 1;
32993 lastCol = Math.min( this.cols - 1, lastCol );
32995 // set colYs to bottom of the stamp
32996 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32999 for ( var i = firstCol; i <= lastCol; i++ ) {
33000 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
33005 _getContainerSize : function()
33007 this.maxY = Math.max.apply( Math, this.colYs );
33012 if ( this.isFitWidth ) {
33013 size.width = this._getContainerFitWidth();
33019 _getContainerFitWidth : function()
33021 var unusedCols = 0;
33022 // count unused columns
33025 if ( this.colYs[i] !== 0 ) {
33030 // fit container to columns that have been used
33031 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
33034 needsResizeLayout : function()
33036 var previousWidth = this.containerWidth;
33037 this.getContainerWidth();
33038 return previousWidth !== this.containerWidth;
33053 * @class Roo.bootstrap.MasonryBrick
33054 * @extends Roo.bootstrap.Component
33055 * Bootstrap MasonryBrick class
33058 * Create a new MasonryBrick
33059 * @param {Object} config The config object
33062 Roo.bootstrap.MasonryBrick = function(config){
33064 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33066 Roo.bootstrap.MasonryBrick.register(this);
33072 * When a MasonryBrick is clcik
33073 * @param {Roo.bootstrap.MasonryBrick} this
33074 * @param {Roo.EventObject} e
33080 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33083 * @cfg {String} title
33087 * @cfg {String} html
33091 * @cfg {String} bgimage
33095 * @cfg {String} videourl
33099 * @cfg {String} cls
33103 * @cfg {String} href
33107 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33112 * @cfg {String} placetitle (center|bottom)
33117 * @cfg {Boolean} isFitContainer defalut true
33119 isFitContainer : true,
33122 * @cfg {Boolean} preventDefault defalut false
33124 preventDefault : false,
33127 * @cfg {Boolean} inverse defalut false
33129 maskInverse : false,
33131 getAutoCreate : function()
33133 if(!this.isFitContainer){
33134 return this.getSplitAutoCreate();
33137 var cls = 'masonry-brick masonry-brick-full';
33139 if(this.href.length){
33140 cls += ' masonry-brick-link';
33143 if(this.bgimage.length){
33144 cls += ' masonry-brick-image';
33147 if(this.maskInverse){
33148 cls += ' mask-inverse';
33151 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33152 cls += ' enable-mask';
33156 cls += ' masonry-' + this.size + '-brick';
33159 if(this.placetitle.length){
33161 switch (this.placetitle) {
33163 cls += ' masonry-center-title';
33166 cls += ' masonry-bottom-title';
33173 if(!this.html.length && !this.bgimage.length){
33174 cls += ' masonry-center-title';
33177 if(!this.html.length && this.bgimage.length){
33178 cls += ' masonry-bottom-title';
33183 cls += ' ' + this.cls;
33187 tag: (this.href.length) ? 'a' : 'div',
33192 cls: 'masonry-brick-mask'
33196 cls: 'masonry-brick-paragraph',
33202 if(this.href.length){
33203 cfg.href = this.href;
33206 var cn = cfg.cn[1].cn;
33208 if(this.title.length){
33211 cls: 'masonry-brick-title',
33216 if(this.html.length){
33219 cls: 'masonry-brick-text',
33224 if (!this.title.length && !this.html.length) {
33225 cfg.cn[1].cls += ' hide';
33228 if(this.bgimage.length){
33231 cls: 'masonry-brick-image-view',
33236 if(this.videourl.length){
33237 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33238 // youtube support only?
33241 cls: 'masonry-brick-image-view',
33244 allowfullscreen : true
33252 getSplitAutoCreate : function()
33254 var cls = 'masonry-brick masonry-brick-split';
33256 if(this.href.length){
33257 cls += ' masonry-brick-link';
33260 if(this.bgimage.length){
33261 cls += ' masonry-brick-image';
33265 cls += ' masonry-' + this.size + '-brick';
33268 switch (this.placetitle) {
33270 cls += ' masonry-center-title';
33273 cls += ' masonry-bottom-title';
33276 if(!this.bgimage.length){
33277 cls += ' masonry-center-title';
33280 if(this.bgimage.length){
33281 cls += ' masonry-bottom-title';
33287 cls += ' ' + this.cls;
33291 tag: (this.href.length) ? 'a' : 'div',
33296 cls: 'masonry-brick-split-head',
33300 cls: 'masonry-brick-paragraph',
33307 cls: 'masonry-brick-split-body',
33313 if(this.href.length){
33314 cfg.href = this.href;
33317 if(this.title.length){
33318 cfg.cn[0].cn[0].cn.push({
33320 cls: 'masonry-brick-title',
33325 if(this.html.length){
33326 cfg.cn[1].cn.push({
33328 cls: 'masonry-brick-text',
33333 if(this.bgimage.length){
33334 cfg.cn[0].cn.push({
33336 cls: 'masonry-brick-image-view',
33341 if(this.videourl.length){
33342 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33343 // youtube support only?
33344 cfg.cn[0].cn.cn.push({
33346 cls: 'masonry-brick-image-view',
33349 allowfullscreen : true
33356 initEvents: function()
33358 switch (this.size) {
33391 this.el.on('touchstart', this.onTouchStart, this);
33392 this.el.on('touchmove', this.onTouchMove, this);
33393 this.el.on('touchend', this.onTouchEnd, this);
33394 this.el.on('contextmenu', this.onContextMenu, this);
33396 this.el.on('mouseenter' ,this.enter, this);
33397 this.el.on('mouseleave', this.leave, this);
33398 this.el.on('click', this.onClick, this);
33401 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33402 this.parent().bricks.push(this);
33407 onClick: function(e, el)
33409 var time = this.endTimer - this.startTimer;
33410 // Roo.log(e.preventDefault());
33413 e.preventDefault();
33418 if(!this.preventDefault){
33422 e.preventDefault();
33424 if (this.activeClass != '') {
33425 this.selectBrick();
33428 this.fireEvent('click', this, e);
33431 enter: function(e, el)
33433 e.preventDefault();
33435 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33439 if(this.bgimage.length && this.html.length){
33440 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33444 leave: function(e, el)
33446 e.preventDefault();
33448 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33452 if(this.bgimage.length && this.html.length){
33453 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33457 onTouchStart: function(e, el)
33459 // e.preventDefault();
33461 this.touchmoved = false;
33463 if(!this.isFitContainer){
33467 if(!this.bgimage.length || !this.html.length){
33471 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33473 this.timer = new Date().getTime();
33477 onTouchMove: function(e, el)
33479 this.touchmoved = true;
33482 onContextMenu : function(e,el)
33484 e.preventDefault();
33485 e.stopPropagation();
33489 onTouchEnd: function(e, el)
33491 // e.preventDefault();
33493 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33500 if(!this.bgimage.length || !this.html.length){
33502 if(this.href.length){
33503 window.location.href = this.href;
33509 if(!this.isFitContainer){
33513 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33515 window.location.href = this.href;
33518 //selection on single brick only
33519 selectBrick : function() {
33521 if (!this.parentId) {
33525 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33526 var index = m.selectedBrick.indexOf(this.id);
33529 m.selectedBrick.splice(index,1);
33530 this.el.removeClass(this.activeClass);
33534 for(var i = 0; i < m.selectedBrick.length; i++) {
33535 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33536 b.el.removeClass(b.activeClass);
33539 m.selectedBrick = [];
33541 m.selectedBrick.push(this.id);
33542 this.el.addClass(this.activeClass);
33546 isSelected : function(){
33547 return this.el.hasClass(this.activeClass);
33552 Roo.apply(Roo.bootstrap.MasonryBrick, {
33555 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33557 * register a Masonry Brick
33558 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33561 register : function(brick)
33563 //this.groups[brick.id] = brick;
33564 this.groups.add(brick.id, brick);
33567 * fetch a masonry brick based on the masonry brick ID
33568 * @param {string} the masonry brick to add
33569 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33572 get: function(brick_id)
33574 // if (typeof(this.groups[brick_id]) == 'undefined') {
33577 // return this.groups[brick_id] ;
33579 if(this.groups.key(brick_id)) {
33580 return this.groups.key(brick_id);
33598 * @class Roo.bootstrap.Brick
33599 * @extends Roo.bootstrap.Component
33600 * Bootstrap Brick class
33603 * Create a new Brick
33604 * @param {Object} config The config object
33607 Roo.bootstrap.Brick = function(config){
33608 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33614 * When a Brick is click
33615 * @param {Roo.bootstrap.Brick} this
33616 * @param {Roo.EventObject} e
33622 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33625 * @cfg {String} title
33629 * @cfg {String} html
33633 * @cfg {String} bgimage
33637 * @cfg {String} cls
33641 * @cfg {String} href
33645 * @cfg {String} video
33649 * @cfg {Boolean} square
33653 getAutoCreate : function()
33655 var cls = 'roo-brick';
33657 if(this.href.length){
33658 cls += ' roo-brick-link';
33661 if(this.bgimage.length){
33662 cls += ' roo-brick-image';
33665 if(!this.html.length && !this.bgimage.length){
33666 cls += ' roo-brick-center-title';
33669 if(!this.html.length && this.bgimage.length){
33670 cls += ' roo-brick-bottom-title';
33674 cls += ' ' + this.cls;
33678 tag: (this.href.length) ? 'a' : 'div',
33683 cls: 'roo-brick-paragraph',
33689 if(this.href.length){
33690 cfg.href = this.href;
33693 var cn = cfg.cn[0].cn;
33695 if(this.title.length){
33698 cls: 'roo-brick-title',
33703 if(this.html.length){
33706 cls: 'roo-brick-text',
33713 if(this.bgimage.length){
33716 cls: 'roo-brick-image-view',
33724 initEvents: function()
33726 if(this.title.length || this.html.length){
33727 this.el.on('mouseenter' ,this.enter, this);
33728 this.el.on('mouseleave', this.leave, this);
33731 Roo.EventManager.onWindowResize(this.resize, this);
33733 if(this.bgimage.length){
33734 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33735 this.imageEl.on('load', this.onImageLoad, this);
33742 onImageLoad : function()
33747 resize : function()
33749 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33751 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33753 if(this.bgimage.length){
33754 var image = this.el.select('.roo-brick-image-view', true).first();
33756 image.setWidth(paragraph.getWidth());
33759 image.setHeight(paragraph.getWidth());
33762 this.el.setHeight(image.getHeight());
33763 paragraph.setHeight(image.getHeight());
33769 enter: function(e, el)
33771 e.preventDefault();
33773 if(this.bgimage.length){
33774 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33775 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33779 leave: function(e, el)
33781 e.preventDefault();
33783 if(this.bgimage.length){
33784 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33785 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33800 * @class Roo.bootstrap.NumberField
33801 * @extends Roo.bootstrap.Input
33802 * Bootstrap NumberField class
33808 * Create a new NumberField
33809 * @param {Object} config The config object
33812 Roo.bootstrap.NumberField = function(config){
33813 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33816 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33819 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33821 allowDecimals : true,
33823 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33825 decimalSeparator : ".",
33827 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33829 decimalPrecision : 2,
33831 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33833 allowNegative : true,
33836 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33840 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33842 minValue : Number.NEGATIVE_INFINITY,
33844 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33846 maxValue : Number.MAX_VALUE,
33848 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33850 minText : "The minimum value for this field is {0}",
33852 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33854 maxText : "The maximum value for this field is {0}",
33856 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33857 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33859 nanText : "{0} is not a valid number",
33861 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33863 thousandsDelimiter : false,
33865 * @cfg {String} valueAlign alignment of value
33867 valueAlign : "left",
33869 getAutoCreate : function()
33871 var hiddenInput = {
33875 cls: 'hidden-number-input'
33879 hiddenInput.name = this.name;
33884 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33886 this.name = hiddenInput.name;
33888 if(cfg.cn.length > 0) {
33889 cfg.cn.push(hiddenInput);
33896 initEvents : function()
33898 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33900 var allowed = "0123456789";
33902 if(this.allowDecimals){
33903 allowed += this.decimalSeparator;
33906 if(this.allowNegative){
33910 if(this.thousandsDelimiter) {
33914 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33916 var keyPress = function(e){
33918 var k = e.getKey();
33920 var c = e.getCharCode();
33923 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33924 allowed.indexOf(String.fromCharCode(c)) === -1
33930 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33934 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33939 this.el.on("keypress", keyPress, this);
33942 validateValue : function(value)
33945 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33949 var num = this.parseValue(value);
33952 this.markInvalid(String.format(this.nanText, value));
33956 if(num < this.minValue){
33957 this.markInvalid(String.format(this.minText, this.minValue));
33961 if(num > this.maxValue){
33962 this.markInvalid(String.format(this.maxText, this.maxValue));
33969 getValue : function()
33971 var v = this.hiddenEl().getValue();
33973 return this.fixPrecision(this.parseValue(v));
33976 parseValue : function(value)
33978 if(this.thousandsDelimiter) {
33980 r = new RegExp(",", "g");
33981 value = value.replace(r, "");
33984 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33985 return isNaN(value) ? '' : value;
33988 fixPrecision : function(value)
33990 if(this.thousandsDelimiter) {
33992 r = new RegExp(",", "g");
33993 value = value.replace(r, "");
33996 var nan = isNaN(value);
33998 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33999 return nan ? '' : value;
34001 return parseFloat(value).toFixed(this.decimalPrecision);
34004 setValue : function(v)
34006 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
34012 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
34014 this.inputEl().dom.value = (v == '') ? '' :
34015 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
34017 if(!this.allowZero && v === '0') {
34018 this.hiddenEl().dom.value = '';
34019 this.inputEl().dom.value = '';
34026 decimalPrecisionFcn : function(v)
34028 return Math.floor(v);
34031 beforeBlur : function()
34033 var v = this.parseValue(this.getRawValue());
34035 if(v || v === 0 || v === ''){
34040 hiddenEl : function()
34042 return this.el.select('input.hidden-number-input',true).first();
34054 * @class Roo.bootstrap.DocumentSlider
34055 * @extends Roo.bootstrap.Component
34056 * Bootstrap DocumentSlider class
34059 * Create a new DocumentViewer
34060 * @param {Object} config The config object
34063 Roo.bootstrap.DocumentSlider = function(config){
34064 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34071 * Fire after initEvent
34072 * @param {Roo.bootstrap.DocumentSlider} this
34077 * Fire after update
34078 * @param {Roo.bootstrap.DocumentSlider} this
34084 * @param {Roo.bootstrap.DocumentSlider} this
34090 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34096 getAutoCreate : function()
34100 cls : 'roo-document-slider',
34104 cls : 'roo-document-slider-header',
34108 cls : 'roo-document-slider-header-title'
34114 cls : 'roo-document-slider-body',
34118 cls : 'roo-document-slider-prev',
34122 cls : 'fa fa-chevron-left'
34128 cls : 'roo-document-slider-thumb',
34132 cls : 'roo-document-slider-image'
34138 cls : 'roo-document-slider-next',
34142 cls : 'fa fa-chevron-right'
34154 initEvents : function()
34156 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34157 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34159 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34160 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34162 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34163 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34165 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34166 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34168 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34169 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34171 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34172 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34174 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34175 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34177 this.thumbEl.on('click', this.onClick, this);
34179 this.prevIndicator.on('click', this.prev, this);
34181 this.nextIndicator.on('click', this.next, this);
34185 initial : function()
34187 if(this.files.length){
34188 this.indicator = 1;
34192 this.fireEvent('initial', this);
34195 update : function()
34197 this.imageEl.attr('src', this.files[this.indicator - 1]);
34199 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34201 this.prevIndicator.show();
34203 if(this.indicator == 1){
34204 this.prevIndicator.hide();
34207 this.nextIndicator.show();
34209 if(this.indicator == this.files.length){
34210 this.nextIndicator.hide();
34213 this.thumbEl.scrollTo('top');
34215 this.fireEvent('update', this);
34218 onClick : function(e)
34220 e.preventDefault();
34222 this.fireEvent('click', this);
34227 e.preventDefault();
34229 this.indicator = Math.max(1, this.indicator - 1);
34236 e.preventDefault();
34238 this.indicator = Math.min(this.files.length, this.indicator + 1);
34252 * @class Roo.bootstrap.RadioSet
34253 * @extends Roo.bootstrap.Input
34254 * Bootstrap RadioSet class
34255 * @cfg {String} indicatorpos (left|right) default left
34256 * @cfg {Boolean} inline (true|false) inline the element (default true)
34257 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34259 * Create a new RadioSet
34260 * @param {Object} config The config object
34263 Roo.bootstrap.RadioSet = function(config){
34265 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34269 Roo.bootstrap.RadioSet.register(this);
34274 * Fires when the element is checked or unchecked.
34275 * @param {Roo.bootstrap.RadioSet} this This radio
34276 * @param {Roo.bootstrap.Radio} item The checked item
34281 * Fires when the element is click.
34282 * @param {Roo.bootstrap.RadioSet} this This radio set
34283 * @param {Roo.bootstrap.Radio} item The checked item
34284 * @param {Roo.EventObject} e The event object
34291 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34299 indicatorpos : 'left',
34301 getAutoCreate : function()
34305 cls : 'roo-radio-set-label',
34309 html : this.fieldLabel
34313 if (Roo.bootstrap.version == 3) {
34316 if(this.indicatorpos == 'left'){
34319 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34320 tooltip : 'This field is required'
34325 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34326 tooltip : 'This field is required'
34332 cls : 'roo-radio-set-items'
34335 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34337 if (align === 'left' && this.fieldLabel.length) {
34340 cls : "roo-radio-set-right",
34346 if(this.labelWidth > 12){
34347 label.style = "width: " + this.labelWidth + 'px';
34350 if(this.labelWidth < 13 && this.labelmd == 0){
34351 this.labelmd = this.labelWidth;
34354 if(this.labellg > 0){
34355 label.cls += ' col-lg-' + this.labellg;
34356 items.cls += ' col-lg-' + (12 - this.labellg);
34359 if(this.labelmd > 0){
34360 label.cls += ' col-md-' + this.labelmd;
34361 items.cls += ' col-md-' + (12 - this.labelmd);
34364 if(this.labelsm > 0){
34365 label.cls += ' col-sm-' + this.labelsm;
34366 items.cls += ' col-sm-' + (12 - this.labelsm);
34369 if(this.labelxs > 0){
34370 label.cls += ' col-xs-' + this.labelxs;
34371 items.cls += ' col-xs-' + (12 - this.labelxs);
34377 cls : 'roo-radio-set',
34381 cls : 'roo-radio-set-input',
34384 value : this.value ? this.value : ''
34391 if(this.weight.length){
34392 cfg.cls += ' roo-radio-' + this.weight;
34396 cfg.cls += ' roo-radio-set-inline';
34400 ['xs','sm','md','lg'].map(function(size){
34401 if (settings[size]) {
34402 cfg.cls += ' col-' + size + '-' + settings[size];
34410 initEvents : function()
34412 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34413 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34415 if(!this.fieldLabel.length){
34416 this.labelEl.hide();
34419 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34420 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34422 this.indicator = this.indicatorEl();
34424 if(this.indicator){
34425 this.indicator.addClass('invisible');
34428 this.originalValue = this.getValue();
34432 inputEl: function ()
34434 return this.el.select('.roo-radio-set-input', true).first();
34437 getChildContainer : function()
34439 return this.itemsEl;
34442 register : function(item)
34444 this.radioes.push(item);
34448 validate : function()
34450 if(this.getVisibilityEl().hasClass('hidden')){
34456 Roo.each(this.radioes, function(i){
34465 if(this.allowBlank) {
34469 if(this.disabled || valid){
34474 this.markInvalid();
34479 markValid : function()
34481 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34482 this.indicatorEl().removeClass('visible');
34483 this.indicatorEl().addClass('invisible');
34487 if (Roo.bootstrap.version == 3) {
34488 this.el.removeClass([this.invalidClass, this.validClass]);
34489 this.el.addClass(this.validClass);
34491 this.el.removeClass(['is-invalid','is-valid']);
34492 this.el.addClass(['is-valid']);
34494 this.fireEvent('valid', this);
34497 markInvalid : function(msg)
34499 if(this.allowBlank || this.disabled){
34503 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34504 this.indicatorEl().removeClass('invisible');
34505 this.indicatorEl().addClass('visible');
34507 if (Roo.bootstrap.version == 3) {
34508 this.el.removeClass([this.invalidClass, this.validClass]);
34509 this.el.addClass(this.invalidClass);
34511 this.el.removeClass(['is-invalid','is-valid']);
34512 this.el.addClass(['is-invalid']);
34515 this.fireEvent('invalid', this, msg);
34519 setValue : function(v, suppressEvent)
34521 if(this.value === v){
34528 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34531 Roo.each(this.radioes, function(i){
34533 i.el.removeClass('checked');
34536 Roo.each(this.radioes, function(i){
34538 if(i.value === v || i.value.toString() === v.toString()){
34540 i.el.addClass('checked');
34542 if(suppressEvent !== true){
34543 this.fireEvent('check', this, i);
34554 clearInvalid : function(){
34556 if(!this.el || this.preventMark){
34560 this.el.removeClass([this.invalidClass]);
34562 this.fireEvent('valid', this);
34567 Roo.apply(Roo.bootstrap.RadioSet, {
34571 register : function(set)
34573 this.groups[set.name] = set;
34576 get: function(name)
34578 if (typeof(this.groups[name]) == 'undefined') {
34582 return this.groups[name] ;
34588 * Ext JS Library 1.1.1
34589 * Copyright(c) 2006-2007, Ext JS, LLC.
34591 * Originally Released Under LGPL - original licence link has changed is not relivant.
34594 * <script type="text/javascript">
34599 * @class Roo.bootstrap.SplitBar
34600 * @extends Roo.util.Observable
34601 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34605 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34606 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34607 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34608 split.minSize = 100;
34609 split.maxSize = 600;
34610 split.animate = true;
34611 split.on('moved', splitterMoved);
34614 * Create a new SplitBar
34615 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34616 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34617 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34618 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34619 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34620 position of the SplitBar).
34622 Roo.bootstrap.SplitBar = function(cfg){
34627 // dragElement : elm
34628 // resizingElement: el,
34630 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34631 // placement : Roo.bootstrap.SplitBar.LEFT ,
34632 // existingProxy ???
34635 this.el = Roo.get(cfg.dragElement, true);
34636 this.el.dom.unselectable = "on";
34638 this.resizingEl = Roo.get(cfg.resizingElement, true);
34642 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34643 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34646 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34649 * The minimum size of the resizing element. (Defaults to 0)
34655 * The maximum size of the resizing element. (Defaults to 2000)
34658 this.maxSize = 2000;
34661 * Whether to animate the transition to the new size
34664 this.animate = false;
34667 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34670 this.useShim = false;
34675 if(!cfg.existingProxy){
34677 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34679 this.proxy = Roo.get(cfg.existingProxy).dom;
34682 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34685 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34688 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34691 this.dragSpecs = {};
34694 * @private The adapter to use to positon and resize elements
34696 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34697 this.adapter.init(this);
34699 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34701 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34702 this.el.addClass("roo-splitbar-h");
34705 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34706 this.el.addClass("roo-splitbar-v");
34712 * Fires when the splitter is moved (alias for {@link #event-moved})
34713 * @param {Roo.bootstrap.SplitBar} this
34714 * @param {Number} newSize the new width or height
34719 * Fires when the splitter is moved
34720 * @param {Roo.bootstrap.SplitBar} this
34721 * @param {Number} newSize the new width or height
34725 * @event beforeresize
34726 * Fires before the splitter is dragged
34727 * @param {Roo.bootstrap.SplitBar} this
34729 "beforeresize" : true,
34731 "beforeapply" : true
34734 Roo.util.Observable.call(this);
34737 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34738 onStartProxyDrag : function(x, y){
34739 this.fireEvent("beforeresize", this);
34741 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34743 o.enableDisplayMode("block");
34744 // all splitbars share the same overlay
34745 Roo.bootstrap.SplitBar.prototype.overlay = o;
34747 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34748 this.overlay.show();
34749 Roo.get(this.proxy).setDisplayed("block");
34750 var size = this.adapter.getElementSize(this);
34751 this.activeMinSize = this.getMinimumSize();;
34752 this.activeMaxSize = this.getMaximumSize();;
34753 var c1 = size - this.activeMinSize;
34754 var c2 = Math.max(this.activeMaxSize - size, 0);
34755 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34756 this.dd.resetConstraints();
34757 this.dd.setXConstraint(
34758 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34759 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34761 this.dd.setYConstraint(0, 0);
34763 this.dd.resetConstraints();
34764 this.dd.setXConstraint(0, 0);
34765 this.dd.setYConstraint(
34766 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34767 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34770 this.dragSpecs.startSize = size;
34771 this.dragSpecs.startPoint = [x, y];
34772 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34776 * @private Called after the drag operation by the DDProxy
34778 onEndProxyDrag : function(e){
34779 Roo.get(this.proxy).setDisplayed(false);
34780 var endPoint = Roo.lib.Event.getXY(e);
34782 this.overlay.hide();
34785 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34786 newSize = this.dragSpecs.startSize +
34787 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34788 endPoint[0] - this.dragSpecs.startPoint[0] :
34789 this.dragSpecs.startPoint[0] - endPoint[0]
34792 newSize = this.dragSpecs.startSize +
34793 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34794 endPoint[1] - this.dragSpecs.startPoint[1] :
34795 this.dragSpecs.startPoint[1] - endPoint[1]
34798 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34799 if(newSize != this.dragSpecs.startSize){
34800 if(this.fireEvent('beforeapply', this, newSize) !== false){
34801 this.adapter.setElementSize(this, newSize);
34802 this.fireEvent("moved", this, newSize);
34803 this.fireEvent("resize", this, newSize);
34809 * Get the adapter this SplitBar uses
34810 * @return The adapter object
34812 getAdapter : function(){
34813 return this.adapter;
34817 * Set the adapter this SplitBar uses
34818 * @param {Object} adapter A SplitBar adapter object
34820 setAdapter : function(adapter){
34821 this.adapter = adapter;
34822 this.adapter.init(this);
34826 * Gets the minimum size for the resizing element
34827 * @return {Number} The minimum size
34829 getMinimumSize : function(){
34830 return this.minSize;
34834 * Sets the minimum size for the resizing element
34835 * @param {Number} minSize The minimum size
34837 setMinimumSize : function(minSize){
34838 this.minSize = minSize;
34842 * Gets the maximum size for the resizing element
34843 * @return {Number} The maximum size
34845 getMaximumSize : function(){
34846 return this.maxSize;
34850 * Sets the maximum size for the resizing element
34851 * @param {Number} maxSize The maximum size
34853 setMaximumSize : function(maxSize){
34854 this.maxSize = maxSize;
34858 * Sets the initialize size for the resizing element
34859 * @param {Number} size The initial size
34861 setCurrentSize : function(size){
34862 var oldAnimate = this.animate;
34863 this.animate = false;
34864 this.adapter.setElementSize(this, size);
34865 this.animate = oldAnimate;
34869 * Destroy this splitbar.
34870 * @param {Boolean} removeEl True to remove the element
34872 destroy : function(removeEl){
34874 this.shim.remove();
34877 this.proxy.parentNode.removeChild(this.proxy);
34885 * @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.
34887 Roo.bootstrap.SplitBar.createProxy = function(dir){
34888 var proxy = new Roo.Element(document.createElement("div"));
34889 proxy.unselectable();
34890 var cls = 'roo-splitbar-proxy';
34891 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34892 document.body.appendChild(proxy.dom);
34897 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34898 * Default Adapter. It assumes the splitter and resizing element are not positioned
34899 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34901 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34904 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34905 // do nothing for now
34906 init : function(s){
34910 * Called before drag operations to get the current size of the resizing element.
34911 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34913 getElementSize : function(s){
34914 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34915 return s.resizingEl.getWidth();
34917 return s.resizingEl.getHeight();
34922 * Called after drag operations to set the size of the resizing element.
34923 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34924 * @param {Number} newSize The new size to set
34925 * @param {Function} onComplete A function to be invoked when resizing is complete
34927 setElementSize : function(s, newSize, onComplete){
34928 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34930 s.resizingEl.setWidth(newSize);
34932 onComplete(s, newSize);
34935 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34940 s.resizingEl.setHeight(newSize);
34942 onComplete(s, newSize);
34945 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34952 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34953 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34954 * Adapter that moves the splitter element to align with the resized sizing element.
34955 * Used with an absolute positioned SplitBar.
34956 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34957 * document.body, make sure you assign an id to the body element.
34959 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34960 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34961 this.container = Roo.get(container);
34964 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34965 init : function(s){
34966 this.basic.init(s);
34969 getElementSize : function(s){
34970 return this.basic.getElementSize(s);
34973 setElementSize : function(s, newSize, onComplete){
34974 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34977 moveSplitter : function(s){
34978 var yes = Roo.bootstrap.SplitBar;
34979 switch(s.placement){
34981 s.el.setX(s.resizingEl.getRight());
34984 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34987 s.el.setY(s.resizingEl.getBottom());
34990 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34997 * Orientation constant - Create a vertical SplitBar
35001 Roo.bootstrap.SplitBar.VERTICAL = 1;
35004 * Orientation constant - Create a horizontal SplitBar
35008 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
35011 * Placement constant - The resizing element is to the left of the splitter element
35015 Roo.bootstrap.SplitBar.LEFT = 1;
35018 * Placement constant - The resizing element is to the right of the splitter element
35022 Roo.bootstrap.SplitBar.RIGHT = 2;
35025 * Placement constant - The resizing element is positioned above the splitter element
35029 Roo.bootstrap.SplitBar.TOP = 3;
35032 * Placement constant - The resizing element is positioned under splitter element
35036 Roo.bootstrap.SplitBar.BOTTOM = 4;
35037 Roo.namespace("Roo.bootstrap.layout");/*
35039 * Ext JS Library 1.1.1
35040 * Copyright(c) 2006-2007, Ext JS, LLC.
35042 * Originally Released Under LGPL - original licence link has changed is not relivant.
35045 * <script type="text/javascript">
35049 * @class Roo.bootstrap.layout.Manager
35050 * @extends Roo.bootstrap.Component
35051 * Base class for layout managers.
35053 Roo.bootstrap.layout.Manager = function(config)
35055 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35061 /** false to disable window resize monitoring @type Boolean */
35062 this.monitorWindowResize = true;
35067 * Fires when a layout is performed.
35068 * @param {Roo.LayoutManager} this
35072 * @event regionresized
35073 * Fires when the user resizes a region.
35074 * @param {Roo.LayoutRegion} region The resized region
35075 * @param {Number} newSize The new size (width for east/west, height for north/south)
35077 "regionresized" : true,
35079 * @event regioncollapsed
35080 * Fires when a region is collapsed.
35081 * @param {Roo.LayoutRegion} region The collapsed region
35083 "regioncollapsed" : true,
35085 * @event regionexpanded
35086 * Fires when a region is expanded.
35087 * @param {Roo.LayoutRegion} region The expanded region
35089 "regionexpanded" : true
35091 this.updating = false;
35094 this.el = Roo.get(config.el);
35100 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35105 monitorWindowResize : true,
35111 onRender : function(ct, position)
35114 this.el = Roo.get(ct);
35117 //this.fireEvent('render',this);
35121 initEvents: function()
35125 // ie scrollbar fix
35126 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35127 document.body.scroll = "no";
35128 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35129 this.el.position('relative');
35131 this.id = this.el.id;
35132 this.el.addClass("roo-layout-container");
35133 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35134 if(this.el.dom != document.body ) {
35135 this.el.on('resize', this.layout,this);
35136 this.el.on('show', this.layout,this);
35142 * Returns true if this layout is currently being updated
35143 * @return {Boolean}
35145 isUpdating : function(){
35146 return this.updating;
35150 * Suspend the LayoutManager from doing auto-layouts while
35151 * making multiple add or remove calls
35153 beginUpdate : function(){
35154 this.updating = true;
35158 * Restore auto-layouts and optionally disable the manager from performing a layout
35159 * @param {Boolean} noLayout true to disable a layout update
35161 endUpdate : function(noLayout){
35162 this.updating = false;
35168 layout: function(){
35172 onRegionResized : function(region, newSize){
35173 this.fireEvent("regionresized", region, newSize);
35177 onRegionCollapsed : function(region){
35178 this.fireEvent("regioncollapsed", region);
35181 onRegionExpanded : function(region){
35182 this.fireEvent("regionexpanded", region);
35186 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35187 * performs box-model adjustments.
35188 * @return {Object} The size as an object {width: (the width), height: (the height)}
35190 getViewSize : function()
35193 if(this.el.dom != document.body){
35194 size = this.el.getSize();
35196 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35198 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35199 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35204 * Returns the Element this layout is bound to.
35205 * @return {Roo.Element}
35207 getEl : function(){
35212 * Returns the specified region.
35213 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35214 * @return {Roo.LayoutRegion}
35216 getRegion : function(target){
35217 return this.regions[target.toLowerCase()];
35220 onWindowResize : function(){
35221 if(this.monitorWindowResize){
35228 * Ext JS Library 1.1.1
35229 * Copyright(c) 2006-2007, Ext JS, LLC.
35231 * Originally Released Under LGPL - original licence link has changed is not relivant.
35234 * <script type="text/javascript">
35237 * @class Roo.bootstrap.layout.Border
35238 * @extends Roo.bootstrap.layout.Manager
35239 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35240 * please see: examples/bootstrap/nested.html<br><br>
35242 <b>The container the layout is rendered into can be either the body element or any other element.
35243 If it is not the body element, the container needs to either be an absolute positioned element,
35244 or you will need to add "position:relative" to the css of the container. You will also need to specify
35245 the container size if it is not the body element.</b>
35248 * Create a new Border
35249 * @param {Object} config Configuration options
35251 Roo.bootstrap.layout.Border = function(config){
35252 config = config || {};
35253 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35257 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35258 if(config[region]){
35259 config[region].region = region;
35260 this.addRegion(config[region]);
35266 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35268 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35270 parent : false, // this might point to a 'nest' or a ???
35273 * Creates and adds a new region if it doesn't already exist.
35274 * @param {String} target The target region key (north, south, east, west or center).
35275 * @param {Object} config The regions config object
35276 * @return {BorderLayoutRegion} The new region
35278 addRegion : function(config)
35280 if(!this.regions[config.region]){
35281 var r = this.factory(config);
35282 this.bindRegion(r);
35284 return this.regions[config.region];
35288 bindRegion : function(r){
35289 this.regions[r.config.region] = r;
35291 r.on("visibilitychange", this.layout, this);
35292 r.on("paneladded", this.layout, this);
35293 r.on("panelremoved", this.layout, this);
35294 r.on("invalidated", this.layout, this);
35295 r.on("resized", this.onRegionResized, this);
35296 r.on("collapsed", this.onRegionCollapsed, this);
35297 r.on("expanded", this.onRegionExpanded, this);
35301 * Performs a layout update.
35303 layout : function()
35305 if(this.updating) {
35309 // render all the rebions if they have not been done alreayd?
35310 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35311 if(this.regions[region] && !this.regions[region].bodyEl){
35312 this.regions[region].onRender(this.el)
35316 var size = this.getViewSize();
35317 var w = size.width;
35318 var h = size.height;
35323 //var x = 0, y = 0;
35325 var rs = this.regions;
35326 var north = rs["north"];
35327 var south = rs["south"];
35328 var west = rs["west"];
35329 var east = rs["east"];
35330 var center = rs["center"];
35331 //if(this.hideOnLayout){ // not supported anymore
35332 //c.el.setStyle("display", "none");
35334 if(north && north.isVisible()){
35335 var b = north.getBox();
35336 var m = north.getMargins();
35337 b.width = w - (m.left+m.right);
35340 centerY = b.height + b.y + m.bottom;
35341 centerH -= centerY;
35342 north.updateBox(this.safeBox(b));
35344 if(south && south.isVisible()){
35345 var b = south.getBox();
35346 var m = south.getMargins();
35347 b.width = w - (m.left+m.right);
35349 var totalHeight = (b.height + m.top + m.bottom);
35350 b.y = h - totalHeight + m.top;
35351 centerH -= totalHeight;
35352 south.updateBox(this.safeBox(b));
35354 if(west && west.isVisible()){
35355 var b = west.getBox();
35356 var m = west.getMargins();
35357 b.height = centerH - (m.top+m.bottom);
35359 b.y = centerY + m.top;
35360 var totalWidth = (b.width + m.left + m.right);
35361 centerX += totalWidth;
35362 centerW -= totalWidth;
35363 west.updateBox(this.safeBox(b));
35365 if(east && east.isVisible()){
35366 var b = east.getBox();
35367 var m = east.getMargins();
35368 b.height = centerH - (m.top+m.bottom);
35369 var totalWidth = (b.width + m.left + m.right);
35370 b.x = w - totalWidth + m.left;
35371 b.y = centerY + m.top;
35372 centerW -= totalWidth;
35373 east.updateBox(this.safeBox(b));
35376 var m = center.getMargins();
35378 x: centerX + m.left,
35379 y: centerY + m.top,
35380 width: centerW - (m.left+m.right),
35381 height: centerH - (m.top+m.bottom)
35383 //if(this.hideOnLayout){
35384 //center.el.setStyle("display", "block");
35386 center.updateBox(this.safeBox(centerBox));
35389 this.fireEvent("layout", this);
35393 safeBox : function(box){
35394 box.width = Math.max(0, box.width);
35395 box.height = Math.max(0, box.height);
35400 * Adds a ContentPanel (or subclass) to this layout.
35401 * @param {String} target The target region key (north, south, east, west or center).
35402 * @param {Roo.ContentPanel} panel The panel to add
35403 * @return {Roo.ContentPanel} The added panel
35405 add : function(target, panel){
35407 target = target.toLowerCase();
35408 return this.regions[target].add(panel);
35412 * Remove a ContentPanel (or subclass) to this layout.
35413 * @param {String} target The target region key (north, south, east, west or center).
35414 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35415 * @return {Roo.ContentPanel} The removed panel
35417 remove : function(target, panel){
35418 target = target.toLowerCase();
35419 return this.regions[target].remove(panel);
35423 * Searches all regions for a panel with the specified id
35424 * @param {String} panelId
35425 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35427 findPanel : function(panelId){
35428 var rs = this.regions;
35429 for(var target in rs){
35430 if(typeof rs[target] != "function"){
35431 var p = rs[target].getPanel(panelId);
35441 * Searches all regions for a panel with the specified id and activates (shows) it.
35442 * @param {String/ContentPanel} panelId The panels id or the panel itself
35443 * @return {Roo.ContentPanel} The shown panel or null
35445 showPanel : function(panelId) {
35446 var rs = this.regions;
35447 for(var target in rs){
35448 var r = rs[target];
35449 if(typeof r != "function"){
35450 if(r.hasPanel(panelId)){
35451 return r.showPanel(panelId);
35459 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35460 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35463 restoreState : function(provider){
35465 provider = Roo.state.Manager;
35467 var sm = new Roo.LayoutStateManager();
35468 sm.init(this, provider);
35474 * Adds a xtype elements to the layout.
35478 xtype : 'ContentPanel',
35485 xtype : 'NestedLayoutPanel',
35491 items : [ ... list of content panels or nested layout panels.. ]
35495 * @param {Object} cfg Xtype definition of item to add.
35497 addxtype : function(cfg)
35499 // basically accepts a pannel...
35500 // can accept a layout region..!?!?
35501 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35504 // theory? children can only be panels??
35506 //if (!cfg.xtype.match(/Panel$/)) {
35511 if (typeof(cfg.region) == 'undefined') {
35512 Roo.log("Failed to add Panel, region was not set");
35516 var region = cfg.region;
35522 xitems = cfg.items;
35527 if ( region == 'center') {
35528 Roo.log("Center: " + cfg.title);
35534 case 'Content': // ContentPanel (el, cfg)
35535 case 'Scroll': // ContentPanel (el, cfg)
35537 cfg.autoCreate = cfg.autoCreate || true;
35538 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35540 // var el = this.el.createChild();
35541 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35544 this.add(region, ret);
35548 case 'TreePanel': // our new panel!
35549 cfg.el = this.el.createChild();
35550 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35551 this.add(region, ret);
35556 // create a new Layout (which is a Border Layout...
35558 var clayout = cfg.layout;
35559 clayout.el = this.el.createChild();
35560 clayout.items = clayout.items || [];
35564 // replace this exitems with the clayout ones..
35565 xitems = clayout.items;
35567 // force background off if it's in center...
35568 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35569 cfg.background = false;
35571 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35574 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35575 //console.log('adding nested layout panel ' + cfg.toSource());
35576 this.add(region, ret);
35577 nb = {}; /// find first...
35582 // needs grid and region
35584 //var el = this.getRegion(region).el.createChild();
35586 *var el = this.el.createChild();
35587 // create the grid first...
35588 cfg.grid.container = el;
35589 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35592 if (region == 'center' && this.active ) {
35593 cfg.background = false;
35596 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35598 this.add(region, ret);
35600 if (cfg.background) {
35601 // render grid on panel activation (if panel background)
35602 ret.on('activate', function(gp) {
35603 if (!gp.grid.rendered) {
35604 // gp.grid.render(el);
35608 // cfg.grid.render(el);
35614 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35615 // it was the old xcomponent building that caused this before.
35616 // espeically if border is the top element in the tree.
35626 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35628 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35629 this.add(region, ret);
35633 throw "Can not add '" + cfg.xtype + "' to Border";
35639 this.beginUpdate();
35643 Roo.each(xitems, function(i) {
35644 region = nb && i.region ? i.region : false;
35646 var add = ret.addxtype(i);
35649 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35650 if (!i.background) {
35651 abn[region] = nb[region] ;
35658 // make the last non-background panel active..
35659 //if (nb) { Roo.log(abn); }
35662 for(var r in abn) {
35663 region = this.getRegion(r);
35665 // tried using nb[r], but it does not work..
35667 region.showPanel(abn[r]);
35678 factory : function(cfg)
35681 var validRegions = Roo.bootstrap.layout.Border.regions;
35683 var target = cfg.region;
35686 var r = Roo.bootstrap.layout;
35690 return new r.North(cfg);
35692 return new r.South(cfg);
35694 return new r.East(cfg);
35696 return new r.West(cfg);
35698 return new r.Center(cfg);
35700 throw 'Layout region "'+target+'" not supported.';
35707 * Ext JS Library 1.1.1
35708 * Copyright(c) 2006-2007, Ext JS, LLC.
35710 * Originally Released Under LGPL - original licence link has changed is not relivant.
35713 * <script type="text/javascript">
35717 * @class Roo.bootstrap.layout.Basic
35718 * @extends Roo.util.Observable
35719 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35720 * and does not have a titlebar, tabs or any other features. All it does is size and position
35721 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35722 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35723 * @cfg {string} region the region that it inhabits..
35724 * @cfg {bool} skipConfig skip config?
35728 Roo.bootstrap.layout.Basic = function(config){
35730 this.mgr = config.mgr;
35732 this.position = config.region;
35734 var skipConfig = config.skipConfig;
35738 * @scope Roo.BasicLayoutRegion
35742 * @event beforeremove
35743 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35744 * @param {Roo.LayoutRegion} this
35745 * @param {Roo.ContentPanel} panel The panel
35746 * @param {Object} e The cancel event object
35748 "beforeremove" : true,
35750 * @event invalidated
35751 * Fires when the layout for this region is changed.
35752 * @param {Roo.LayoutRegion} this
35754 "invalidated" : true,
35756 * @event visibilitychange
35757 * Fires when this region is shown or hidden
35758 * @param {Roo.LayoutRegion} this
35759 * @param {Boolean} visibility true or false
35761 "visibilitychange" : true,
35763 * @event paneladded
35764 * Fires when a panel is added.
35765 * @param {Roo.LayoutRegion} this
35766 * @param {Roo.ContentPanel} panel The panel
35768 "paneladded" : true,
35770 * @event panelremoved
35771 * Fires when a panel is removed.
35772 * @param {Roo.LayoutRegion} this
35773 * @param {Roo.ContentPanel} panel The panel
35775 "panelremoved" : true,
35777 * @event beforecollapse
35778 * Fires when this region before collapse.
35779 * @param {Roo.LayoutRegion} this
35781 "beforecollapse" : true,
35784 * Fires when this region is collapsed.
35785 * @param {Roo.LayoutRegion} this
35787 "collapsed" : true,
35790 * Fires when this region is expanded.
35791 * @param {Roo.LayoutRegion} this
35796 * Fires when this region is slid into view.
35797 * @param {Roo.LayoutRegion} this
35799 "slideshow" : true,
35802 * Fires when this region slides out of view.
35803 * @param {Roo.LayoutRegion} this
35805 "slidehide" : true,
35807 * @event panelactivated
35808 * Fires when a panel is activated.
35809 * @param {Roo.LayoutRegion} this
35810 * @param {Roo.ContentPanel} panel The activated panel
35812 "panelactivated" : true,
35815 * Fires when the user resizes this region.
35816 * @param {Roo.LayoutRegion} this
35817 * @param {Number} newSize The new size (width for east/west, height for north/south)
35821 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35822 this.panels = new Roo.util.MixedCollection();
35823 this.panels.getKey = this.getPanelId.createDelegate(this);
35825 this.activePanel = null;
35826 // ensure listeners are added...
35828 if (config.listeners || config.events) {
35829 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35830 listeners : config.listeners || {},
35831 events : config.events || {}
35835 if(skipConfig !== true){
35836 this.applyConfig(config);
35840 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35842 getPanelId : function(p){
35846 applyConfig : function(config){
35847 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35848 this.config = config;
35853 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35854 * the width, for horizontal (north, south) the height.
35855 * @param {Number} newSize The new width or height
35857 resizeTo : function(newSize){
35858 var el = this.el ? this.el :
35859 (this.activePanel ? this.activePanel.getEl() : null);
35861 switch(this.position){
35864 el.setWidth(newSize);
35865 this.fireEvent("resized", this, newSize);
35869 el.setHeight(newSize);
35870 this.fireEvent("resized", this, newSize);
35876 getBox : function(){
35877 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35880 getMargins : function(){
35881 return this.margins;
35884 updateBox : function(box){
35886 var el = this.activePanel.getEl();
35887 el.dom.style.left = box.x + "px";
35888 el.dom.style.top = box.y + "px";
35889 this.activePanel.setSize(box.width, box.height);
35893 * Returns the container element for this region.
35894 * @return {Roo.Element}
35896 getEl : function(){
35897 return this.activePanel;
35901 * Returns true if this region is currently visible.
35902 * @return {Boolean}
35904 isVisible : function(){
35905 return this.activePanel ? true : false;
35908 setActivePanel : function(panel){
35909 panel = this.getPanel(panel);
35910 if(this.activePanel && this.activePanel != panel){
35911 this.activePanel.setActiveState(false);
35912 this.activePanel.getEl().setLeftTop(-10000,-10000);
35914 this.activePanel = panel;
35915 panel.setActiveState(true);
35917 panel.setSize(this.box.width, this.box.height);
35919 this.fireEvent("panelactivated", this, panel);
35920 this.fireEvent("invalidated");
35924 * Show the specified panel.
35925 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35926 * @return {Roo.ContentPanel} The shown panel or null
35928 showPanel : function(panel){
35929 panel = this.getPanel(panel);
35931 this.setActivePanel(panel);
35937 * Get the active panel for this region.
35938 * @return {Roo.ContentPanel} The active panel or null
35940 getActivePanel : function(){
35941 return this.activePanel;
35945 * Add the passed ContentPanel(s)
35946 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35947 * @return {Roo.ContentPanel} The panel added (if only one was added)
35949 add : function(panel){
35950 if(arguments.length > 1){
35951 for(var i = 0, len = arguments.length; i < len; i++) {
35952 this.add(arguments[i]);
35956 if(this.hasPanel(panel)){
35957 this.showPanel(panel);
35960 var el = panel.getEl();
35961 if(el.dom.parentNode != this.mgr.el.dom){
35962 this.mgr.el.dom.appendChild(el.dom);
35964 if(panel.setRegion){
35965 panel.setRegion(this);
35967 this.panels.add(panel);
35968 el.setStyle("position", "absolute");
35969 if(!panel.background){
35970 this.setActivePanel(panel);
35971 if(this.config.initialSize && this.panels.getCount()==1){
35972 this.resizeTo(this.config.initialSize);
35975 this.fireEvent("paneladded", this, panel);
35980 * Returns true if the panel is in this region.
35981 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35982 * @return {Boolean}
35984 hasPanel : function(panel){
35985 if(typeof panel == "object"){ // must be panel obj
35986 panel = panel.getId();
35988 return this.getPanel(panel) ? true : false;
35992 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35993 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35994 * @param {Boolean} preservePanel Overrides the config preservePanel option
35995 * @return {Roo.ContentPanel} The panel that was removed
35997 remove : function(panel, preservePanel){
35998 panel = this.getPanel(panel);
36003 this.fireEvent("beforeremove", this, panel, e);
36004 if(e.cancel === true){
36007 var panelId = panel.getId();
36008 this.panels.removeKey(panelId);
36013 * Returns the panel specified or null if it's not in this region.
36014 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
36015 * @return {Roo.ContentPanel}
36017 getPanel : function(id){
36018 if(typeof id == "object"){ // must be panel obj
36021 return this.panels.get(id);
36025 * Returns this regions position (north/south/east/west/center).
36028 getPosition: function(){
36029 return this.position;
36033 * Ext JS Library 1.1.1
36034 * Copyright(c) 2006-2007, Ext JS, LLC.
36036 * Originally Released Under LGPL - original licence link has changed is not relivant.
36039 * <script type="text/javascript">
36043 * @class Roo.bootstrap.layout.Region
36044 * @extends Roo.bootstrap.layout.Basic
36045 * This class represents a region in a layout manager.
36047 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
36048 * @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})
36049 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
36050 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
36051 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36052 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36053 * @cfg {String} title The title for the region (overrides panel titles)
36054 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36055 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36056 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36057 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36058 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36059 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36060 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36061 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36062 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36063 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36065 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36066 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36067 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36068 * @cfg {Number} width For East/West panels
36069 * @cfg {Number} height For North/South panels
36070 * @cfg {Boolean} split To show the splitter
36071 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36073 * @cfg {string} cls Extra CSS classes to add to region
36075 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36076 * @cfg {string} region the region that it inhabits..
36079 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36080 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36082 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36083 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36084 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36086 Roo.bootstrap.layout.Region = function(config)
36088 this.applyConfig(config);
36090 var mgr = config.mgr;
36091 var pos = config.region;
36092 config.skipConfig = true;
36093 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36096 this.onRender(mgr.el);
36099 this.visible = true;
36100 this.collapsed = false;
36101 this.unrendered_panels = [];
36104 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36106 position: '', // set by wrapper (eg. north/south etc..)
36107 unrendered_panels : null, // unrendered panels.
36109 tabPosition : false,
36111 mgr: false, // points to 'Border'
36114 createBody : function(){
36115 /** This region's body element
36116 * @type Roo.Element */
36117 this.bodyEl = this.el.createChild({
36119 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36123 onRender: function(ctr, pos)
36125 var dh = Roo.DomHelper;
36126 /** This region's container element
36127 * @type Roo.Element */
36128 this.el = dh.append(ctr.dom, {
36130 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36132 /** This region's title element
36133 * @type Roo.Element */
36135 this.titleEl = dh.append(this.el.dom, {
36137 unselectable: "on",
36138 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36140 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36141 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36145 this.titleEl.enableDisplayMode();
36146 /** This region's title text element
36147 * @type HTMLElement */
36148 this.titleTextEl = this.titleEl.dom.firstChild;
36149 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36151 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36152 this.closeBtn.enableDisplayMode();
36153 this.closeBtn.on("click", this.closeClicked, this);
36154 this.closeBtn.hide();
36156 this.createBody(this.config);
36157 if(this.config.hideWhenEmpty){
36159 this.on("paneladded", this.validateVisibility, this);
36160 this.on("panelremoved", this.validateVisibility, this);
36162 if(this.autoScroll){
36163 this.bodyEl.setStyle("overflow", "auto");
36165 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36167 //if(c.titlebar !== false){
36168 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36169 this.titleEl.hide();
36171 this.titleEl.show();
36172 if(this.config.title){
36173 this.titleTextEl.innerHTML = this.config.title;
36177 if(this.config.collapsed){
36178 this.collapse(true);
36180 if(this.config.hidden){
36184 if (this.unrendered_panels && this.unrendered_panels.length) {
36185 for (var i =0;i< this.unrendered_panels.length; i++) {
36186 this.add(this.unrendered_panels[i]);
36188 this.unrendered_panels = null;
36194 applyConfig : function(c)
36197 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36198 var dh = Roo.DomHelper;
36199 if(c.titlebar !== false){
36200 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36201 this.collapseBtn.on("click", this.collapse, this);
36202 this.collapseBtn.enableDisplayMode();
36204 if(c.showPin === true || this.showPin){
36205 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36206 this.stickBtn.enableDisplayMode();
36207 this.stickBtn.on("click", this.expand, this);
36208 this.stickBtn.hide();
36213 /** This region's collapsed element
36214 * @type Roo.Element */
36217 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36218 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36221 if(c.floatable !== false){
36222 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36223 this.collapsedEl.on("click", this.collapseClick, this);
36226 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36227 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36228 id: "message", unselectable: "on", style:{"float":"left"}});
36229 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36231 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36232 this.expandBtn.on("click", this.expand, this);
36236 if(this.collapseBtn){
36237 this.collapseBtn.setVisible(c.collapsible == true);
36240 this.cmargins = c.cmargins || this.cmargins ||
36241 (this.position == "west" || this.position == "east" ?
36242 {top: 0, left: 2, right:2, bottom: 0} :
36243 {top: 2, left: 0, right:0, bottom: 2});
36245 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36248 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36250 this.autoScroll = c.autoScroll || false;
36255 this.duration = c.duration || .30;
36256 this.slideDuration = c.slideDuration || .45;
36261 * Returns true if this region is currently visible.
36262 * @return {Boolean}
36264 isVisible : function(){
36265 return this.visible;
36269 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36270 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36272 //setCollapsedTitle : function(title){
36273 // title = title || " ";
36274 // if(this.collapsedTitleTextEl){
36275 // this.collapsedTitleTextEl.innerHTML = title;
36279 getBox : function(){
36281 // if(!this.collapsed){
36282 b = this.el.getBox(false, true);
36284 // b = this.collapsedEl.getBox(false, true);
36289 getMargins : function(){
36290 return this.margins;
36291 //return this.collapsed ? this.cmargins : this.margins;
36294 highlight : function(){
36295 this.el.addClass("x-layout-panel-dragover");
36298 unhighlight : function(){
36299 this.el.removeClass("x-layout-panel-dragover");
36302 updateBox : function(box)
36304 if (!this.bodyEl) {
36305 return; // not rendered yet..
36309 if(!this.collapsed){
36310 this.el.dom.style.left = box.x + "px";
36311 this.el.dom.style.top = box.y + "px";
36312 this.updateBody(box.width, box.height);
36314 this.collapsedEl.dom.style.left = box.x + "px";
36315 this.collapsedEl.dom.style.top = box.y + "px";
36316 this.collapsedEl.setSize(box.width, box.height);
36319 this.tabs.autoSizeTabs();
36323 updateBody : function(w, h)
36326 this.el.setWidth(w);
36327 w -= this.el.getBorderWidth("rl");
36328 if(this.config.adjustments){
36329 w += this.config.adjustments[0];
36332 if(h !== null && h > 0){
36333 this.el.setHeight(h);
36334 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36335 h -= this.el.getBorderWidth("tb");
36336 if(this.config.adjustments){
36337 h += this.config.adjustments[1];
36339 this.bodyEl.setHeight(h);
36341 h = this.tabs.syncHeight(h);
36344 if(this.panelSize){
36345 w = w !== null ? w : this.panelSize.width;
36346 h = h !== null ? h : this.panelSize.height;
36348 if(this.activePanel){
36349 var el = this.activePanel.getEl();
36350 w = w !== null ? w : el.getWidth();
36351 h = h !== null ? h : el.getHeight();
36352 this.panelSize = {width: w, height: h};
36353 this.activePanel.setSize(w, h);
36355 if(Roo.isIE && this.tabs){
36356 this.tabs.el.repaint();
36361 * Returns the container element for this region.
36362 * @return {Roo.Element}
36364 getEl : function(){
36369 * Hides this region.
36372 //if(!this.collapsed){
36373 this.el.dom.style.left = "-2000px";
36376 // this.collapsedEl.dom.style.left = "-2000px";
36377 // this.collapsedEl.hide();
36379 this.visible = false;
36380 this.fireEvent("visibilitychange", this, false);
36384 * Shows this region if it was previously hidden.
36387 //if(!this.collapsed){
36390 // this.collapsedEl.show();
36392 this.visible = true;
36393 this.fireEvent("visibilitychange", this, true);
36396 closeClicked : function(){
36397 if(this.activePanel){
36398 this.remove(this.activePanel);
36402 collapseClick : function(e){
36404 e.stopPropagation();
36407 e.stopPropagation();
36413 * Collapses this region.
36414 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36417 collapse : function(skipAnim, skipCheck = false){
36418 if(this.collapsed) {
36422 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36424 this.collapsed = true;
36426 this.split.el.hide();
36428 if(this.config.animate && skipAnim !== true){
36429 this.fireEvent("invalidated", this);
36430 this.animateCollapse();
36432 this.el.setLocation(-20000,-20000);
36434 this.collapsedEl.show();
36435 this.fireEvent("collapsed", this);
36436 this.fireEvent("invalidated", this);
36442 animateCollapse : function(){
36447 * Expands this region if it was previously collapsed.
36448 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36449 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36452 expand : function(e, skipAnim){
36454 e.stopPropagation();
36456 if(!this.collapsed || this.el.hasActiveFx()) {
36460 this.afterSlideIn();
36463 this.collapsed = false;
36464 if(this.config.animate && skipAnim !== true){
36465 this.animateExpand();
36469 this.split.el.show();
36471 this.collapsedEl.setLocation(-2000,-2000);
36472 this.collapsedEl.hide();
36473 this.fireEvent("invalidated", this);
36474 this.fireEvent("expanded", this);
36478 animateExpand : function(){
36482 initTabs : function()
36484 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36486 var ts = new Roo.bootstrap.panel.Tabs({
36487 el: this.bodyEl.dom,
36489 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36490 disableTooltips: this.config.disableTabTips,
36491 toolbar : this.config.toolbar
36494 if(this.config.hideTabs){
36495 ts.stripWrap.setDisplayed(false);
36498 ts.resizeTabs = this.config.resizeTabs === true;
36499 ts.minTabWidth = this.config.minTabWidth || 40;
36500 ts.maxTabWidth = this.config.maxTabWidth || 250;
36501 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36502 ts.monitorResize = false;
36503 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36504 ts.bodyEl.addClass('roo-layout-tabs-body');
36505 this.panels.each(this.initPanelAsTab, this);
36508 initPanelAsTab : function(panel){
36509 var ti = this.tabs.addTab(
36513 this.config.closeOnTab && panel.isClosable(),
36516 if(panel.tabTip !== undefined){
36517 ti.setTooltip(panel.tabTip);
36519 ti.on("activate", function(){
36520 this.setActivePanel(panel);
36523 if(this.config.closeOnTab){
36524 ti.on("beforeclose", function(t, e){
36526 this.remove(panel);
36530 panel.tabItem = ti;
36535 updatePanelTitle : function(panel, title)
36537 if(this.activePanel == panel){
36538 this.updateTitle(title);
36541 var ti = this.tabs.getTab(panel.getEl().id);
36543 if(panel.tabTip !== undefined){
36544 ti.setTooltip(panel.tabTip);
36549 updateTitle : function(title){
36550 if(this.titleTextEl && !this.config.title){
36551 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36555 setActivePanel : function(panel)
36557 panel = this.getPanel(panel);
36558 if(this.activePanel && this.activePanel != panel){
36559 if(this.activePanel.setActiveState(false) === false){
36563 this.activePanel = panel;
36564 panel.setActiveState(true);
36565 if(this.panelSize){
36566 panel.setSize(this.panelSize.width, this.panelSize.height);
36569 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36571 this.updateTitle(panel.getTitle());
36573 this.fireEvent("invalidated", this);
36575 this.fireEvent("panelactivated", this, panel);
36579 * Shows the specified panel.
36580 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36581 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36583 showPanel : function(panel)
36585 panel = this.getPanel(panel);
36588 var tab = this.tabs.getTab(panel.getEl().id);
36589 if(tab.isHidden()){
36590 this.tabs.unhideTab(tab.id);
36594 this.setActivePanel(panel);
36601 * Get the active panel for this region.
36602 * @return {Roo.ContentPanel} The active panel or null
36604 getActivePanel : function(){
36605 return this.activePanel;
36608 validateVisibility : function(){
36609 if(this.panels.getCount() < 1){
36610 this.updateTitle(" ");
36611 this.closeBtn.hide();
36614 if(!this.isVisible()){
36621 * Adds the passed ContentPanel(s) to this region.
36622 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36623 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36625 add : function(panel)
36627 if(arguments.length > 1){
36628 for(var i = 0, len = arguments.length; i < len; i++) {
36629 this.add(arguments[i]);
36634 // if we have not been rendered yet, then we can not really do much of this..
36635 if (!this.bodyEl) {
36636 this.unrendered_panels.push(panel);
36643 if(this.hasPanel(panel)){
36644 this.showPanel(panel);
36647 panel.setRegion(this);
36648 this.panels.add(panel);
36649 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36650 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36651 // and hide them... ???
36652 this.bodyEl.dom.appendChild(panel.getEl().dom);
36653 if(panel.background !== true){
36654 this.setActivePanel(panel);
36656 this.fireEvent("paneladded", this, panel);
36663 this.initPanelAsTab(panel);
36667 if(panel.background !== true){
36668 this.tabs.activate(panel.getEl().id);
36670 this.fireEvent("paneladded", this, panel);
36675 * Hides the tab for the specified panel.
36676 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36678 hidePanel : function(panel){
36679 if(this.tabs && (panel = this.getPanel(panel))){
36680 this.tabs.hideTab(panel.getEl().id);
36685 * Unhides the tab for a previously hidden panel.
36686 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36688 unhidePanel : function(panel){
36689 if(this.tabs && (panel = this.getPanel(panel))){
36690 this.tabs.unhideTab(panel.getEl().id);
36694 clearPanels : function(){
36695 while(this.panels.getCount() > 0){
36696 this.remove(this.panels.first());
36701 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36702 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36703 * @param {Boolean} preservePanel Overrides the config preservePanel option
36704 * @return {Roo.ContentPanel} The panel that was removed
36706 remove : function(panel, preservePanel)
36708 panel = this.getPanel(panel);
36713 this.fireEvent("beforeremove", this, panel, e);
36714 if(e.cancel === true){
36717 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36718 var panelId = panel.getId();
36719 this.panels.removeKey(panelId);
36721 document.body.appendChild(panel.getEl().dom);
36724 this.tabs.removeTab(panel.getEl().id);
36725 }else if (!preservePanel){
36726 this.bodyEl.dom.removeChild(panel.getEl().dom);
36728 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36729 var p = this.panels.first();
36730 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36731 tempEl.appendChild(p.getEl().dom);
36732 this.bodyEl.update("");
36733 this.bodyEl.dom.appendChild(p.getEl().dom);
36735 this.updateTitle(p.getTitle());
36737 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36738 this.setActivePanel(p);
36740 panel.setRegion(null);
36741 if(this.activePanel == panel){
36742 this.activePanel = null;
36744 if(this.config.autoDestroy !== false && preservePanel !== true){
36745 try{panel.destroy();}catch(e){}
36747 this.fireEvent("panelremoved", this, panel);
36752 * Returns the TabPanel component used by this region
36753 * @return {Roo.TabPanel}
36755 getTabs : function(){
36759 createTool : function(parentEl, className){
36760 var btn = Roo.DomHelper.append(parentEl, {
36762 cls: "x-layout-tools-button",
36765 cls: "roo-layout-tools-button-inner " + className,
36769 btn.addClassOnOver("roo-layout-tools-button-over");
36774 * Ext JS Library 1.1.1
36775 * Copyright(c) 2006-2007, Ext JS, LLC.
36777 * Originally Released Under LGPL - original licence link has changed is not relivant.
36780 * <script type="text/javascript">
36786 * @class Roo.SplitLayoutRegion
36787 * @extends Roo.LayoutRegion
36788 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36790 Roo.bootstrap.layout.Split = function(config){
36791 this.cursor = config.cursor;
36792 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36795 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36797 splitTip : "Drag to resize.",
36798 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36799 useSplitTips : false,
36801 applyConfig : function(config){
36802 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36805 onRender : function(ctr,pos) {
36807 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36808 if(!this.config.split){
36813 var splitEl = Roo.DomHelper.append(ctr.dom, {
36815 id: this.el.id + "-split",
36816 cls: "roo-layout-split roo-layout-split-"+this.position,
36819 /** The SplitBar for this region
36820 * @type Roo.SplitBar */
36821 // does not exist yet...
36822 Roo.log([this.position, this.orientation]);
36824 this.split = new Roo.bootstrap.SplitBar({
36825 dragElement : splitEl,
36826 resizingElement: this.el,
36827 orientation : this.orientation
36830 this.split.on("moved", this.onSplitMove, this);
36831 this.split.useShim = this.config.useShim === true;
36832 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36833 if(this.useSplitTips){
36834 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36836 //if(config.collapsible){
36837 // this.split.el.on("dblclick", this.collapse, this);
36840 if(typeof this.config.minSize != "undefined"){
36841 this.split.minSize = this.config.minSize;
36843 if(typeof this.config.maxSize != "undefined"){
36844 this.split.maxSize = this.config.maxSize;
36846 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36847 this.hideSplitter();
36852 getHMaxSize : function(){
36853 var cmax = this.config.maxSize || 10000;
36854 var center = this.mgr.getRegion("center");
36855 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36858 getVMaxSize : function(){
36859 var cmax = this.config.maxSize || 10000;
36860 var center = this.mgr.getRegion("center");
36861 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36864 onSplitMove : function(split, newSize){
36865 this.fireEvent("resized", this, newSize);
36869 * Returns the {@link Roo.SplitBar} for this region.
36870 * @return {Roo.SplitBar}
36872 getSplitBar : function(){
36877 this.hideSplitter();
36878 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36881 hideSplitter : function(){
36883 this.split.el.setLocation(-2000,-2000);
36884 this.split.el.hide();
36890 this.split.el.show();
36892 Roo.bootstrap.layout.Split.superclass.show.call(this);
36895 beforeSlide: function(){
36896 if(Roo.isGecko){// firefox overflow auto bug workaround
36897 this.bodyEl.clip();
36899 this.tabs.bodyEl.clip();
36901 if(this.activePanel){
36902 this.activePanel.getEl().clip();
36904 if(this.activePanel.beforeSlide){
36905 this.activePanel.beforeSlide();
36911 afterSlide : function(){
36912 if(Roo.isGecko){// firefox overflow auto bug workaround
36913 this.bodyEl.unclip();
36915 this.tabs.bodyEl.unclip();
36917 if(this.activePanel){
36918 this.activePanel.getEl().unclip();
36919 if(this.activePanel.afterSlide){
36920 this.activePanel.afterSlide();
36926 initAutoHide : function(){
36927 if(this.autoHide !== false){
36928 if(!this.autoHideHd){
36929 var st = new Roo.util.DelayedTask(this.slideIn, this);
36930 this.autoHideHd = {
36931 "mouseout": function(e){
36932 if(!e.within(this.el, true)){
36936 "mouseover" : function(e){
36942 this.el.on(this.autoHideHd);
36946 clearAutoHide : function(){
36947 if(this.autoHide !== false){
36948 this.el.un("mouseout", this.autoHideHd.mouseout);
36949 this.el.un("mouseover", this.autoHideHd.mouseover);
36953 clearMonitor : function(){
36954 Roo.get(document).un("click", this.slideInIf, this);
36957 // these names are backwards but not changed for compat
36958 slideOut : function(){
36959 if(this.isSlid || this.el.hasActiveFx()){
36962 this.isSlid = true;
36963 if(this.collapseBtn){
36964 this.collapseBtn.hide();
36966 this.closeBtnState = this.closeBtn.getStyle('display');
36967 this.closeBtn.hide();
36969 this.stickBtn.show();
36972 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36973 this.beforeSlide();
36974 this.el.setStyle("z-index", 10001);
36975 this.el.slideIn(this.getSlideAnchor(), {
36976 callback: function(){
36978 this.initAutoHide();
36979 Roo.get(document).on("click", this.slideInIf, this);
36980 this.fireEvent("slideshow", this);
36987 afterSlideIn : function(){
36988 this.clearAutoHide();
36989 this.isSlid = false;
36990 this.clearMonitor();
36991 this.el.setStyle("z-index", "");
36992 if(this.collapseBtn){
36993 this.collapseBtn.show();
36995 this.closeBtn.setStyle('display', this.closeBtnState);
36997 this.stickBtn.hide();
36999 this.fireEvent("slidehide", this);
37002 slideIn : function(cb){
37003 if(!this.isSlid || this.el.hasActiveFx()){
37007 this.isSlid = false;
37008 this.beforeSlide();
37009 this.el.slideOut(this.getSlideAnchor(), {
37010 callback: function(){
37011 this.el.setLeftTop(-10000, -10000);
37013 this.afterSlideIn();
37021 slideInIf : function(e){
37022 if(!e.within(this.el)){
37027 animateCollapse : function(){
37028 this.beforeSlide();
37029 this.el.setStyle("z-index", 20000);
37030 var anchor = this.getSlideAnchor();
37031 this.el.slideOut(anchor, {
37032 callback : function(){
37033 this.el.setStyle("z-index", "");
37034 this.collapsedEl.slideIn(anchor, {duration:.3});
37036 this.el.setLocation(-10000,-10000);
37038 this.fireEvent("collapsed", this);
37045 animateExpand : function(){
37046 this.beforeSlide();
37047 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
37048 this.el.setStyle("z-index", 20000);
37049 this.collapsedEl.hide({
37052 this.el.slideIn(this.getSlideAnchor(), {
37053 callback : function(){
37054 this.el.setStyle("z-index", "");
37057 this.split.el.show();
37059 this.fireEvent("invalidated", this);
37060 this.fireEvent("expanded", this);
37088 getAnchor : function(){
37089 return this.anchors[this.position];
37092 getCollapseAnchor : function(){
37093 return this.canchors[this.position];
37096 getSlideAnchor : function(){
37097 return this.sanchors[this.position];
37100 getAlignAdj : function(){
37101 var cm = this.cmargins;
37102 switch(this.position){
37118 getExpandAdj : function(){
37119 var c = this.collapsedEl, cm = this.cmargins;
37120 switch(this.position){
37122 return [-(cm.right+c.getWidth()+cm.left), 0];
37125 return [cm.right+c.getWidth()+cm.left, 0];
37128 return [0, -(cm.top+cm.bottom+c.getHeight())];
37131 return [0, cm.top+cm.bottom+c.getHeight()];
37137 * Ext JS Library 1.1.1
37138 * Copyright(c) 2006-2007, Ext JS, LLC.
37140 * Originally Released Under LGPL - original licence link has changed is not relivant.
37143 * <script type="text/javascript">
37146 * These classes are private internal classes
37148 Roo.bootstrap.layout.Center = function(config){
37149 config.region = "center";
37150 Roo.bootstrap.layout.Region.call(this, config);
37151 this.visible = true;
37152 this.minWidth = config.minWidth || 20;
37153 this.minHeight = config.minHeight || 20;
37156 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37158 // center panel can't be hidden
37162 // center panel can't be hidden
37165 getMinWidth: function(){
37166 return this.minWidth;
37169 getMinHeight: function(){
37170 return this.minHeight;
37184 Roo.bootstrap.layout.North = function(config)
37186 config.region = 'north';
37187 config.cursor = 'n-resize';
37189 Roo.bootstrap.layout.Split.call(this, config);
37193 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37194 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37195 this.split.el.addClass("roo-layout-split-v");
37197 var size = config.initialSize || config.height;
37198 if(typeof size != "undefined"){
37199 this.el.setHeight(size);
37202 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37204 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37208 getBox : function(){
37209 if(this.collapsed){
37210 return this.collapsedEl.getBox();
37212 var box = this.el.getBox();
37214 box.height += this.split.el.getHeight();
37219 updateBox : function(box){
37220 if(this.split && !this.collapsed){
37221 box.height -= this.split.el.getHeight();
37222 this.split.el.setLeft(box.x);
37223 this.split.el.setTop(box.y+box.height);
37224 this.split.el.setWidth(box.width);
37226 if(this.collapsed){
37227 this.updateBody(box.width, null);
37229 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37237 Roo.bootstrap.layout.South = function(config){
37238 config.region = 'south';
37239 config.cursor = 's-resize';
37240 Roo.bootstrap.layout.Split.call(this, config);
37242 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37243 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37244 this.split.el.addClass("roo-layout-split-v");
37246 var size = config.initialSize || config.height;
37247 if(typeof size != "undefined"){
37248 this.el.setHeight(size);
37252 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37253 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37254 getBox : function(){
37255 if(this.collapsed){
37256 return this.collapsedEl.getBox();
37258 var box = this.el.getBox();
37260 var sh = this.split.el.getHeight();
37267 updateBox : function(box){
37268 if(this.split && !this.collapsed){
37269 var sh = this.split.el.getHeight();
37272 this.split.el.setLeft(box.x);
37273 this.split.el.setTop(box.y-sh);
37274 this.split.el.setWidth(box.width);
37276 if(this.collapsed){
37277 this.updateBody(box.width, null);
37279 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37283 Roo.bootstrap.layout.East = function(config){
37284 config.region = "east";
37285 config.cursor = "e-resize";
37286 Roo.bootstrap.layout.Split.call(this, config);
37288 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37289 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37290 this.split.el.addClass("roo-layout-split-h");
37292 var size = config.initialSize || config.width;
37293 if(typeof size != "undefined"){
37294 this.el.setWidth(size);
37297 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37298 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37299 getBox : function(){
37300 if(this.collapsed){
37301 return this.collapsedEl.getBox();
37303 var box = this.el.getBox();
37305 var sw = this.split.el.getWidth();
37312 updateBox : function(box){
37313 if(this.split && !this.collapsed){
37314 var sw = this.split.el.getWidth();
37316 this.split.el.setLeft(box.x);
37317 this.split.el.setTop(box.y);
37318 this.split.el.setHeight(box.height);
37321 if(this.collapsed){
37322 this.updateBody(null, box.height);
37324 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37328 Roo.bootstrap.layout.West = function(config){
37329 config.region = "west";
37330 config.cursor = "w-resize";
37332 Roo.bootstrap.layout.Split.call(this, config);
37334 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37335 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37336 this.split.el.addClass("roo-layout-split-h");
37340 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37341 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37343 onRender: function(ctr, pos)
37345 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37346 var size = this.config.initialSize || this.config.width;
37347 if(typeof size != "undefined"){
37348 this.el.setWidth(size);
37352 getBox : function(){
37353 if(this.collapsed){
37354 return this.collapsedEl.getBox();
37356 var box = this.el.getBox();
37358 box.width += this.split.el.getWidth();
37363 updateBox : function(box){
37364 if(this.split && !this.collapsed){
37365 var sw = this.split.el.getWidth();
37367 this.split.el.setLeft(box.x+box.width);
37368 this.split.el.setTop(box.y);
37369 this.split.el.setHeight(box.height);
37371 if(this.collapsed){
37372 this.updateBody(null, box.height);
37374 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37376 });Roo.namespace("Roo.bootstrap.panel");/*
37378 * Ext JS Library 1.1.1
37379 * Copyright(c) 2006-2007, Ext JS, LLC.
37381 * Originally Released Under LGPL - original licence link has changed is not relivant.
37384 * <script type="text/javascript">
37387 * @class Roo.ContentPanel
37388 * @extends Roo.util.Observable
37389 * A basic ContentPanel element.
37390 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37391 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37392 * @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
37393 * @cfg {Boolean} closable True if the panel can be closed/removed
37394 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37395 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37396 * @cfg {Toolbar} toolbar A toolbar for this panel
37397 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37398 * @cfg {String} title The title for this panel
37399 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37400 * @cfg {String} url Calls {@link #setUrl} with this value
37401 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37402 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37403 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37404 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37405 * @cfg {Boolean} badges render the badges
37408 * Create a new ContentPanel.
37409 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37410 * @param {String/Object} config A string to set only the title or a config object
37411 * @param {String} content (optional) Set the HTML content for this panel
37412 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37414 Roo.bootstrap.panel.Content = function( config){
37416 this.tpl = config.tpl || false;
37418 var el = config.el;
37419 var content = config.content;
37421 if(config.autoCreate){ // xtype is available if this is called from factory
37424 this.el = Roo.get(el);
37425 if(!this.el && config && config.autoCreate){
37426 if(typeof config.autoCreate == "object"){
37427 if(!config.autoCreate.id){
37428 config.autoCreate.id = config.id||el;
37430 this.el = Roo.DomHelper.append(document.body,
37431 config.autoCreate, true);
37433 var elcfg = { tag: "div",
37434 cls: "roo-layout-inactive-content",
37438 elcfg.html = config.html;
37442 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37445 this.closable = false;
37446 this.loaded = false;
37447 this.active = false;
37450 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37452 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37454 this.wrapEl = this.el; //this.el.wrap();
37456 if (config.toolbar.items) {
37457 ti = config.toolbar.items ;
37458 delete config.toolbar.items ;
37462 this.toolbar.render(this.wrapEl, 'before');
37463 for(var i =0;i < ti.length;i++) {
37464 // Roo.log(['add child', items[i]]);
37465 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37467 this.toolbar.items = nitems;
37468 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37469 delete config.toolbar;
37473 // xtype created footer. - not sure if will work as we normally have to render first..
37474 if (this.footer && !this.footer.el && this.footer.xtype) {
37475 if (!this.wrapEl) {
37476 this.wrapEl = this.el.wrap();
37479 this.footer.container = this.wrapEl.createChild();
37481 this.footer = Roo.factory(this.footer, Roo);
37486 if(typeof config == "string"){
37487 this.title = config;
37489 Roo.apply(this, config);
37493 this.resizeEl = Roo.get(this.resizeEl, true);
37495 this.resizeEl = this.el;
37497 // handle view.xtype
37505 * Fires when this panel is activated.
37506 * @param {Roo.ContentPanel} this
37510 * @event deactivate
37511 * Fires when this panel is activated.
37512 * @param {Roo.ContentPanel} this
37514 "deactivate" : true,
37518 * Fires when this panel is resized if fitToFrame is true.
37519 * @param {Roo.ContentPanel} this
37520 * @param {Number} width The width after any component adjustments
37521 * @param {Number} height The height after any component adjustments
37527 * Fires when this tab is created
37528 * @param {Roo.ContentPanel} this
37539 if(this.autoScroll){
37540 this.resizeEl.setStyle("overflow", "auto");
37542 // fix randome scrolling
37543 //this.el.on('scroll', function() {
37544 // Roo.log('fix random scolling');
37545 // this.scrollTo('top',0);
37548 content = content || this.content;
37550 this.setContent(content);
37552 if(config && config.url){
37553 this.setUrl(this.url, this.params, this.loadOnce);
37558 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37560 if (this.view && typeof(this.view.xtype) != 'undefined') {
37561 this.view.el = this.el.appendChild(document.createElement("div"));
37562 this.view = Roo.factory(this.view);
37563 this.view.render && this.view.render(false, '');
37567 this.fireEvent('render', this);
37570 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37574 setRegion : function(region){
37575 this.region = region;
37576 this.setActiveClass(region && !this.background);
37580 setActiveClass: function(state)
37583 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37584 this.el.setStyle('position','relative');
37586 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37587 this.el.setStyle('position', 'absolute');
37592 * Returns the toolbar for this Panel if one was configured.
37593 * @return {Roo.Toolbar}
37595 getToolbar : function(){
37596 return this.toolbar;
37599 setActiveState : function(active)
37601 this.active = active;
37602 this.setActiveClass(active);
37604 if(this.fireEvent("deactivate", this) === false){
37609 this.fireEvent("activate", this);
37613 * Updates this panel's element
37614 * @param {String} content The new content
37615 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37617 setContent : function(content, loadScripts){
37618 this.el.update(content, loadScripts);
37621 ignoreResize : function(w, h){
37622 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37625 this.lastSize = {width: w, height: h};
37630 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37631 * @return {Roo.UpdateManager} The UpdateManager
37633 getUpdateManager : function(){
37634 return this.el.getUpdateManager();
37637 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37638 * @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:
37641 url: "your-url.php",
37642 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37643 callback: yourFunction,
37644 scope: yourObject, //(optional scope)
37647 text: "Loading...",
37652 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37653 * 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.
37654 * @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}
37655 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37656 * @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.
37657 * @return {Roo.ContentPanel} this
37660 var um = this.el.getUpdateManager();
37661 um.update.apply(um, arguments);
37667 * 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.
37668 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37669 * @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)
37670 * @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)
37671 * @return {Roo.UpdateManager} The UpdateManager
37673 setUrl : function(url, params, loadOnce){
37674 if(this.refreshDelegate){
37675 this.removeListener("activate", this.refreshDelegate);
37677 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37678 this.on("activate", this.refreshDelegate);
37679 return this.el.getUpdateManager();
37682 _handleRefresh : function(url, params, loadOnce){
37683 if(!loadOnce || !this.loaded){
37684 var updater = this.el.getUpdateManager();
37685 updater.update(url, params, this._setLoaded.createDelegate(this));
37689 _setLoaded : function(){
37690 this.loaded = true;
37694 * Returns this panel's id
37697 getId : function(){
37702 * Returns this panel's element - used by regiosn to add.
37703 * @return {Roo.Element}
37705 getEl : function(){
37706 return this.wrapEl || this.el;
37711 adjustForComponents : function(width, height)
37713 //Roo.log('adjustForComponents ');
37714 if(this.resizeEl != this.el){
37715 width -= this.el.getFrameWidth('lr');
37716 height -= this.el.getFrameWidth('tb');
37719 var te = this.toolbar.getEl();
37720 te.setWidth(width);
37721 height -= te.getHeight();
37724 var te = this.footer.getEl();
37725 te.setWidth(width);
37726 height -= te.getHeight();
37730 if(this.adjustments){
37731 width += this.adjustments[0];
37732 height += this.adjustments[1];
37734 return {"width": width, "height": height};
37737 setSize : function(width, height){
37738 if(this.fitToFrame && !this.ignoreResize(width, height)){
37739 if(this.fitContainer && this.resizeEl != this.el){
37740 this.el.setSize(width, height);
37742 var size = this.adjustForComponents(width, height);
37743 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37744 this.fireEvent('resize', this, size.width, size.height);
37749 * Returns this panel's title
37752 getTitle : function(){
37754 if (typeof(this.title) != 'object') {
37759 for (var k in this.title) {
37760 if (!this.title.hasOwnProperty(k)) {
37764 if (k.indexOf('-') >= 0) {
37765 var s = k.split('-');
37766 for (var i = 0; i<s.length; i++) {
37767 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37770 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37777 * Set this panel's title
37778 * @param {String} title
37780 setTitle : function(title){
37781 this.title = title;
37783 this.region.updatePanelTitle(this, title);
37788 * Returns true is this panel was configured to be closable
37789 * @return {Boolean}
37791 isClosable : function(){
37792 return this.closable;
37795 beforeSlide : function(){
37797 this.resizeEl.clip();
37800 afterSlide : function(){
37802 this.resizeEl.unclip();
37806 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37807 * Will fail silently if the {@link #setUrl} method has not been called.
37808 * This does not activate the panel, just updates its content.
37810 refresh : function(){
37811 if(this.refreshDelegate){
37812 this.loaded = false;
37813 this.refreshDelegate();
37818 * Destroys this panel
37820 destroy : function(){
37821 this.el.removeAllListeners();
37822 var tempEl = document.createElement("span");
37823 tempEl.appendChild(this.el.dom);
37824 tempEl.innerHTML = "";
37830 * form - if the content panel contains a form - this is a reference to it.
37831 * @type {Roo.form.Form}
37835 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37836 * This contains a reference to it.
37842 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37852 * @param {Object} cfg Xtype definition of item to add.
37856 getChildContainer: function () {
37857 return this.getEl();
37862 var ret = new Roo.factory(cfg);
37867 if (cfg.xtype.match(/^Form$/)) {
37870 //if (this.footer) {
37871 // el = this.footer.container.insertSibling(false, 'before');
37873 el = this.el.createChild();
37876 this.form = new Roo.form.Form(cfg);
37879 if ( this.form.allItems.length) {
37880 this.form.render(el.dom);
37884 // should only have one of theses..
37885 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37886 // views.. should not be just added - used named prop 'view''
37888 cfg.el = this.el.appendChild(document.createElement("div"));
37891 var ret = new Roo.factory(cfg);
37893 ret.render && ret.render(false, ''); // render blank..
37903 * @class Roo.bootstrap.panel.Grid
37904 * @extends Roo.bootstrap.panel.Content
37906 * Create a new GridPanel.
37907 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37908 * @param {Object} config A the config object
37914 Roo.bootstrap.panel.Grid = function(config)
37918 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37919 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37921 config.el = this.wrapper;
37922 //this.el = this.wrapper;
37924 if (config.container) {
37925 // ctor'ed from a Border/panel.grid
37928 this.wrapper.setStyle("overflow", "hidden");
37929 this.wrapper.addClass('roo-grid-container');
37934 if(config.toolbar){
37935 var tool_el = this.wrapper.createChild();
37936 this.toolbar = Roo.factory(config.toolbar);
37938 if (config.toolbar.items) {
37939 ti = config.toolbar.items ;
37940 delete config.toolbar.items ;
37944 this.toolbar.render(tool_el);
37945 for(var i =0;i < ti.length;i++) {
37946 // Roo.log(['add child', items[i]]);
37947 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37949 this.toolbar.items = nitems;
37951 delete config.toolbar;
37954 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37955 config.grid.scrollBody = true;;
37956 config.grid.monitorWindowResize = false; // turn off autosizing
37957 config.grid.autoHeight = false;
37958 config.grid.autoWidth = false;
37960 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37962 if (config.background) {
37963 // render grid on panel activation (if panel background)
37964 this.on('activate', function(gp) {
37965 if (!gp.grid.rendered) {
37966 gp.grid.render(this.wrapper);
37967 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37972 this.grid.render(this.wrapper);
37973 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37976 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37977 // ??? needed ??? config.el = this.wrapper;
37982 // xtype created footer. - not sure if will work as we normally have to render first..
37983 if (this.footer && !this.footer.el && this.footer.xtype) {
37985 var ctr = this.grid.getView().getFooterPanel(true);
37986 this.footer.dataSource = this.grid.dataSource;
37987 this.footer = Roo.factory(this.footer, Roo);
37988 this.footer.render(ctr);
37998 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37999 getId : function(){
38000 return this.grid.id;
38004 * Returns the grid for this panel
38005 * @return {Roo.bootstrap.Table}
38007 getGrid : function(){
38011 setSize : function(width, height){
38012 if(!this.ignoreResize(width, height)){
38013 var grid = this.grid;
38014 var size = this.adjustForComponents(width, height);
38015 var gridel = grid.getGridEl();
38016 gridel.setSize(size.width, size.height);
38018 var thd = grid.getGridEl().select('thead',true).first();
38019 var tbd = grid.getGridEl().select('tbody', true).first();
38021 tbd.setSize(width, height - thd.getHeight());
38030 beforeSlide : function(){
38031 this.grid.getView().scroller.clip();
38034 afterSlide : function(){
38035 this.grid.getView().scroller.unclip();
38038 destroy : function(){
38039 this.grid.destroy();
38041 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
38046 * @class Roo.bootstrap.panel.Nest
38047 * @extends Roo.bootstrap.panel.Content
38049 * Create a new Panel, that can contain a layout.Border.
38052 * @param {Roo.BorderLayout} layout The layout for this panel
38053 * @param {String/Object} config A string to set only the title or a config object
38055 Roo.bootstrap.panel.Nest = function(config)
38057 // construct with only one argument..
38058 /* FIXME - implement nicer consturctors
38059 if (layout.layout) {
38061 layout = config.layout;
38062 delete config.layout;
38064 if (layout.xtype && !layout.getEl) {
38065 // then layout needs constructing..
38066 layout = Roo.factory(layout, Roo);
38070 config.el = config.layout.getEl();
38072 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38074 config.layout.monitorWindowResize = false; // turn off autosizing
38075 this.layout = config.layout;
38076 this.layout.getEl().addClass("roo-layout-nested-layout");
38077 this.layout.parent = this;
38084 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38086 setSize : function(width, height){
38087 if(!this.ignoreResize(width, height)){
38088 var size = this.adjustForComponents(width, height);
38089 var el = this.layout.getEl();
38090 if (size.height < 1) {
38091 el.setWidth(size.width);
38093 el.setSize(size.width, size.height);
38095 var touch = el.dom.offsetWidth;
38096 this.layout.layout();
38097 // ie requires a double layout on the first pass
38098 if(Roo.isIE && !this.initialized){
38099 this.initialized = true;
38100 this.layout.layout();
38105 // activate all subpanels if not currently active..
38107 setActiveState : function(active){
38108 this.active = active;
38109 this.setActiveClass(active);
38112 this.fireEvent("deactivate", this);
38116 this.fireEvent("activate", this);
38117 // not sure if this should happen before or after..
38118 if (!this.layout) {
38119 return; // should not happen..
38122 for (var r in this.layout.regions) {
38123 reg = this.layout.getRegion(r);
38124 if (reg.getActivePanel()) {
38125 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38126 reg.setActivePanel(reg.getActivePanel());
38129 if (!reg.panels.length) {
38132 reg.showPanel(reg.getPanel(0));
38141 * Returns the nested BorderLayout for this panel
38142 * @return {Roo.BorderLayout}
38144 getLayout : function(){
38145 return this.layout;
38149 * Adds a xtype elements to the layout of the nested panel
38153 xtype : 'ContentPanel',
38160 xtype : 'NestedLayoutPanel',
38166 items : [ ... list of content panels or nested layout panels.. ]
38170 * @param {Object} cfg Xtype definition of item to add.
38172 addxtype : function(cfg) {
38173 return this.layout.addxtype(cfg);
38178 * Ext JS Library 1.1.1
38179 * Copyright(c) 2006-2007, Ext JS, LLC.
38181 * Originally Released Under LGPL - original licence link has changed is not relivant.
38184 * <script type="text/javascript">
38187 * @class Roo.TabPanel
38188 * @extends Roo.util.Observable
38189 * A lightweight tab container.
38193 // basic tabs 1, built from existing content
38194 var tabs = new Roo.TabPanel("tabs1");
38195 tabs.addTab("script", "View Script");
38196 tabs.addTab("markup", "View Markup");
38197 tabs.activate("script");
38199 // more advanced tabs, built from javascript
38200 var jtabs = new Roo.TabPanel("jtabs");
38201 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38203 // set up the UpdateManager
38204 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38205 var updater = tab2.getUpdateManager();
38206 updater.setDefaultUrl("ajax1.htm");
38207 tab2.on('activate', updater.refresh, updater, true);
38209 // Use setUrl for Ajax loading
38210 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38211 tab3.setUrl("ajax2.htm", null, true);
38214 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38217 jtabs.activate("jtabs-1");
38220 * Create a new TabPanel.
38221 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38222 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38224 Roo.bootstrap.panel.Tabs = function(config){
38226 * The container element for this TabPanel.
38227 * @type Roo.Element
38229 this.el = Roo.get(config.el);
38232 if(typeof config == "boolean"){
38233 this.tabPosition = config ? "bottom" : "top";
38235 Roo.apply(this, config);
38239 if(this.tabPosition == "bottom"){
38240 // if tabs are at the bottom = create the body first.
38241 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38242 this.el.addClass("roo-tabs-bottom");
38244 // next create the tabs holders
38246 if (this.tabPosition == "west"){
38248 var reg = this.region; // fake it..
38250 if (!reg.mgr.parent) {
38253 reg = reg.mgr.parent.region;
38255 Roo.log("got nest?");
38257 if (reg.mgr.getRegion('west')) {
38258 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38259 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38260 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38261 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38262 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38270 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38271 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38272 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38273 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38278 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38281 // finally - if tabs are at the top, then create the body last..
38282 if(this.tabPosition != "bottom"){
38283 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38284 * @type Roo.Element
38286 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38287 this.el.addClass("roo-tabs-top");
38291 this.bodyEl.setStyle("position", "relative");
38293 this.active = null;
38294 this.activateDelegate = this.activate.createDelegate(this);
38299 * Fires when the active tab changes
38300 * @param {Roo.TabPanel} this
38301 * @param {Roo.TabPanelItem} activePanel The new active tab
38305 * @event beforetabchange
38306 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38307 * @param {Roo.TabPanel} this
38308 * @param {Object} e Set cancel to true on this object to cancel the tab change
38309 * @param {Roo.TabPanelItem} tab The tab being changed to
38311 "beforetabchange" : true
38314 Roo.EventManager.onWindowResize(this.onResize, this);
38315 this.cpad = this.el.getPadding("lr");
38316 this.hiddenCount = 0;
38319 // toolbar on the tabbar support...
38320 if (this.toolbar) {
38321 alert("no toolbar support yet");
38322 this.toolbar = false;
38324 var tcfg = this.toolbar;
38325 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38326 this.toolbar = new Roo.Toolbar(tcfg);
38327 if (Roo.isSafari) {
38328 var tbl = tcfg.container.child('table', true);
38329 tbl.setAttribute('width', '100%');
38337 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38340 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38342 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38344 tabPosition : "top",
38346 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38348 currentTabWidth : 0,
38350 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38354 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38358 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38360 preferredTabWidth : 175,
38362 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38364 resizeTabs : false,
38366 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38368 monitorResize : true,
38370 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38372 toolbar : false, // set by caller..
38374 region : false, /// set by caller
38376 disableTooltips : true, // not used yet...
38379 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38380 * @param {String} id The id of the div to use <b>or create</b>
38381 * @param {String} text The text for the tab
38382 * @param {String} content (optional) Content to put in the TabPanelItem body
38383 * @param {Boolean} closable (optional) True to create a close icon on the tab
38384 * @return {Roo.TabPanelItem} The created TabPanelItem
38386 addTab : function(id, text, content, closable, tpl)
38388 var item = new Roo.bootstrap.panel.TabItem({
38392 closable : closable,
38395 this.addTabItem(item);
38397 item.setContent(content);
38403 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38404 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38405 * @return {Roo.TabPanelItem}
38407 getTab : function(id){
38408 return this.items[id];
38412 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38413 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38415 hideTab : function(id){
38416 var t = this.items[id];
38419 this.hiddenCount++;
38420 this.autoSizeTabs();
38425 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38426 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38428 unhideTab : function(id){
38429 var t = this.items[id];
38431 t.setHidden(false);
38432 this.hiddenCount--;
38433 this.autoSizeTabs();
38438 * Adds an existing {@link Roo.TabPanelItem}.
38439 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38441 addTabItem : function(item)
38443 this.items[item.id] = item;
38444 this.items.push(item);
38445 this.autoSizeTabs();
38446 // if(this.resizeTabs){
38447 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38448 // this.autoSizeTabs();
38450 // item.autoSize();
38455 * Removes a {@link Roo.TabPanelItem}.
38456 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38458 removeTab : function(id){
38459 var items = this.items;
38460 var tab = items[id];
38461 if(!tab) { return; }
38462 var index = items.indexOf(tab);
38463 if(this.active == tab && items.length > 1){
38464 var newTab = this.getNextAvailable(index);
38469 this.stripEl.dom.removeChild(tab.pnode.dom);
38470 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38471 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38473 items.splice(index, 1);
38474 delete this.items[tab.id];
38475 tab.fireEvent("close", tab);
38476 tab.purgeListeners();
38477 this.autoSizeTabs();
38480 getNextAvailable : function(start){
38481 var items = this.items;
38483 // look for a next tab that will slide over to
38484 // replace the one being removed
38485 while(index < items.length){
38486 var item = items[++index];
38487 if(item && !item.isHidden()){
38491 // if one isn't found select the previous tab (on the left)
38494 var item = items[--index];
38495 if(item && !item.isHidden()){
38503 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38504 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38506 disableTab : function(id){
38507 var tab = this.items[id];
38508 if(tab && this.active != tab){
38514 * Enables a {@link Roo.TabPanelItem} that is disabled.
38515 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38517 enableTab : function(id){
38518 var tab = this.items[id];
38523 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38524 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38525 * @return {Roo.TabPanelItem} The TabPanelItem.
38527 activate : function(id)
38529 //Roo.log('activite:' + id);
38531 var tab = this.items[id];
38535 if(tab == this.active || tab.disabled){
38539 this.fireEvent("beforetabchange", this, e, tab);
38540 if(e.cancel !== true && !tab.disabled){
38542 this.active.hide();
38544 this.active = this.items[id];
38545 this.active.show();
38546 this.fireEvent("tabchange", this, this.active);
38552 * Gets the active {@link Roo.TabPanelItem}.
38553 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38555 getActiveTab : function(){
38556 return this.active;
38560 * Updates the tab body element to fit the height of the container element
38561 * for overflow scrolling
38562 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38564 syncHeight : function(targetHeight){
38565 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38566 var bm = this.bodyEl.getMargins();
38567 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38568 this.bodyEl.setHeight(newHeight);
38572 onResize : function(){
38573 if(this.monitorResize){
38574 this.autoSizeTabs();
38579 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38581 beginUpdate : function(){
38582 this.updating = true;
38586 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38588 endUpdate : function(){
38589 this.updating = false;
38590 this.autoSizeTabs();
38594 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38596 autoSizeTabs : function()
38598 var count = this.items.length;
38599 var vcount = count - this.hiddenCount;
38602 this.stripEl.hide();
38604 this.stripEl.show();
38607 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38612 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38613 var availWidth = Math.floor(w / vcount);
38614 var b = this.stripBody;
38615 if(b.getWidth() > w){
38616 var tabs = this.items;
38617 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38618 if(availWidth < this.minTabWidth){
38619 /*if(!this.sleft){ // incomplete scrolling code
38620 this.createScrollButtons();
38623 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38626 if(this.currentTabWidth < this.preferredTabWidth){
38627 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38633 * Returns the number of tabs in this TabPanel.
38636 getCount : function(){
38637 return this.items.length;
38641 * Resizes all the tabs to the passed width
38642 * @param {Number} The new width
38644 setTabWidth : function(width){
38645 this.currentTabWidth = width;
38646 for(var i = 0, len = this.items.length; i < len; i++) {
38647 if(!this.items[i].isHidden()) {
38648 this.items[i].setWidth(width);
38654 * Destroys this TabPanel
38655 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38657 destroy : function(removeEl){
38658 Roo.EventManager.removeResizeListener(this.onResize, this);
38659 for(var i = 0, len = this.items.length; i < len; i++){
38660 this.items[i].purgeListeners();
38662 if(removeEl === true){
38663 this.el.update("");
38668 createStrip : function(container)
38670 var strip = document.createElement("nav");
38671 strip.className = Roo.bootstrap.version == 4 ?
38672 "navbar-light bg-light" :
38673 "navbar navbar-default"; //"x-tabs-wrap";
38674 container.appendChild(strip);
38678 createStripList : function(strip)
38680 // div wrapper for retard IE
38681 // returns the "tr" element.
38682 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38683 //'<div class="x-tabs-strip-wrap">'+
38684 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38685 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38686 return strip.firstChild; //.firstChild.firstChild.firstChild;
38688 createBody : function(container)
38690 var body = document.createElement("div");
38691 Roo.id(body, "tab-body");
38692 //Roo.fly(body).addClass("x-tabs-body");
38693 Roo.fly(body).addClass("tab-content");
38694 container.appendChild(body);
38697 createItemBody :function(bodyEl, id){
38698 var body = Roo.getDom(id);
38700 body = document.createElement("div");
38703 //Roo.fly(body).addClass("x-tabs-item-body");
38704 Roo.fly(body).addClass("tab-pane");
38705 bodyEl.insertBefore(body, bodyEl.firstChild);
38709 createStripElements : function(stripEl, text, closable, tpl)
38711 var td = document.createElement("li"); // was td..
38712 td.className = 'nav-item';
38714 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38717 stripEl.appendChild(td);
38719 td.className = "x-tabs-closable";
38720 if(!this.closeTpl){
38721 this.closeTpl = new Roo.Template(
38722 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38723 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38724 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38727 var el = this.closeTpl.overwrite(td, {"text": text});
38728 var close = el.getElementsByTagName("div")[0];
38729 var inner = el.getElementsByTagName("em")[0];
38730 return {"el": el, "close": close, "inner": inner};
38733 // not sure what this is..
38734 // if(!this.tabTpl){
38735 //this.tabTpl = new Roo.Template(
38736 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38737 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38739 // this.tabTpl = new Roo.Template(
38740 // '<a href="#">' +
38741 // '<span unselectable="on"' +
38742 // (this.disableTooltips ? '' : ' title="{text}"') +
38743 // ' >{text}</span></a>'
38749 var template = tpl || this.tabTpl || false;
38752 template = new Roo.Template(
38753 Roo.bootstrap.version == 4 ?
38755 '<a class="nav-link" href="#" unselectable="on"' +
38756 (this.disableTooltips ? '' : ' title="{text}"') +
38759 '<a class="nav-link" href="#">' +
38760 '<span unselectable="on"' +
38761 (this.disableTooltips ? '' : ' title="{text}"') +
38762 ' >{text}</span></a>'
38767 switch (typeof(template)) {
38771 template = new Roo.Template(template);
38777 var el = template.overwrite(td, {"text": text});
38779 var inner = el.getElementsByTagName("span")[0];
38781 return {"el": el, "inner": inner};
38789 * @class Roo.TabPanelItem
38790 * @extends Roo.util.Observable
38791 * Represents an individual item (tab plus body) in a TabPanel.
38792 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38793 * @param {String} id The id of this TabPanelItem
38794 * @param {String} text The text for the tab of this TabPanelItem
38795 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38797 Roo.bootstrap.panel.TabItem = function(config){
38799 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38800 * @type Roo.TabPanel
38802 this.tabPanel = config.panel;
38804 * The id for this TabPanelItem
38807 this.id = config.id;
38809 this.disabled = false;
38811 this.text = config.text;
38813 this.loaded = false;
38814 this.closable = config.closable;
38817 * The body element for this TabPanelItem.
38818 * @type Roo.Element
38820 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38821 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38822 this.bodyEl.setStyle("display", "block");
38823 this.bodyEl.setStyle("zoom", "1");
38824 //this.hideAction();
38826 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38828 this.el = Roo.get(els.el);
38829 this.inner = Roo.get(els.inner, true);
38830 this.textEl = Roo.bootstrap.version == 4 ?
38831 this.el : Roo.get(this.el.dom.firstChild, true);
38833 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38834 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38837 // this.el.on("mousedown", this.onTabMouseDown, this);
38838 this.el.on("click", this.onTabClick, this);
38840 if(config.closable){
38841 var c = Roo.get(els.close, true);
38842 c.dom.title = this.closeText;
38843 c.addClassOnOver("close-over");
38844 c.on("click", this.closeClick, this);
38850 * Fires when this tab becomes the active tab.
38851 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38852 * @param {Roo.TabPanelItem} this
38856 * @event beforeclose
38857 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38858 * @param {Roo.TabPanelItem} this
38859 * @param {Object} e Set cancel to true on this object to cancel the close.
38861 "beforeclose": true,
38864 * Fires when this tab is closed.
38865 * @param {Roo.TabPanelItem} this
38869 * @event deactivate
38870 * Fires when this tab is no longer the active tab.
38871 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38872 * @param {Roo.TabPanelItem} this
38874 "deactivate" : true
38876 this.hidden = false;
38878 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38881 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38883 purgeListeners : function(){
38884 Roo.util.Observable.prototype.purgeListeners.call(this);
38885 this.el.removeAllListeners();
38888 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38891 this.status_node.addClass("active");
38894 this.tabPanel.stripWrap.repaint();
38896 this.fireEvent("activate", this.tabPanel, this);
38900 * Returns true if this tab is the active tab.
38901 * @return {Boolean}
38903 isActive : function(){
38904 return this.tabPanel.getActiveTab() == this;
38908 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38911 this.status_node.removeClass("active");
38913 this.fireEvent("deactivate", this.tabPanel, this);
38916 hideAction : function(){
38917 this.bodyEl.hide();
38918 this.bodyEl.setStyle("position", "absolute");
38919 this.bodyEl.setLeft("-20000px");
38920 this.bodyEl.setTop("-20000px");
38923 showAction : function(){
38924 this.bodyEl.setStyle("position", "relative");
38925 this.bodyEl.setTop("");
38926 this.bodyEl.setLeft("");
38927 this.bodyEl.show();
38931 * Set the tooltip for the tab.
38932 * @param {String} tooltip The tab's tooltip
38934 setTooltip : function(text){
38935 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38936 this.textEl.dom.qtip = text;
38937 this.textEl.dom.removeAttribute('title');
38939 this.textEl.dom.title = text;
38943 onTabClick : function(e){
38944 e.preventDefault();
38945 this.tabPanel.activate(this.id);
38948 onTabMouseDown : function(e){
38949 e.preventDefault();
38950 this.tabPanel.activate(this.id);
38953 getWidth : function(){
38954 return this.inner.getWidth();
38957 setWidth : function(width){
38958 var iwidth = width - this.linode.getPadding("lr");
38959 this.inner.setWidth(iwidth);
38960 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38961 this.linode.setWidth(width);
38965 * Show or hide the tab
38966 * @param {Boolean} hidden True to hide or false to show.
38968 setHidden : function(hidden){
38969 this.hidden = hidden;
38970 this.linode.setStyle("display", hidden ? "none" : "");
38974 * Returns true if this tab is "hidden"
38975 * @return {Boolean}
38977 isHidden : function(){
38978 return this.hidden;
38982 * Returns the text for this tab
38985 getText : function(){
38989 autoSize : function(){
38990 //this.el.beginMeasure();
38991 this.textEl.setWidth(1);
38993 * #2804 [new] Tabs in Roojs
38994 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38996 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38997 //this.el.endMeasure();
39001 * Sets the text for the tab (Note: this also sets the tooltip text)
39002 * @param {String} text The tab's text and tooltip
39004 setText : function(text){
39006 this.textEl.update(text);
39007 this.setTooltip(text);
39008 //if(!this.tabPanel.resizeTabs){
39009 // this.autoSize();
39013 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
39015 activate : function(){
39016 this.tabPanel.activate(this.id);
39020 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
39022 disable : function(){
39023 if(this.tabPanel.active != this){
39024 this.disabled = true;
39025 this.status_node.addClass("disabled");
39030 * Enables this TabPanelItem if it was previously disabled.
39032 enable : function(){
39033 this.disabled = false;
39034 this.status_node.removeClass("disabled");
39038 * Sets the content for this TabPanelItem.
39039 * @param {String} content The content
39040 * @param {Boolean} loadScripts true to look for and load scripts
39042 setContent : function(content, loadScripts){
39043 this.bodyEl.update(content, loadScripts);
39047 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
39048 * @return {Roo.UpdateManager} The UpdateManager
39050 getUpdateManager : function(){
39051 return this.bodyEl.getUpdateManager();
39055 * Set a URL to be used to load the content for this TabPanelItem.
39056 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39057 * @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)
39058 * @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)
39059 * @return {Roo.UpdateManager} The UpdateManager
39061 setUrl : function(url, params, loadOnce){
39062 if(this.refreshDelegate){
39063 this.un('activate', this.refreshDelegate);
39065 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39066 this.on("activate", this.refreshDelegate);
39067 return this.bodyEl.getUpdateManager();
39071 _handleRefresh : function(url, params, loadOnce){
39072 if(!loadOnce || !this.loaded){
39073 var updater = this.bodyEl.getUpdateManager();
39074 updater.update(url, params, this._setLoaded.createDelegate(this));
39079 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39080 * Will fail silently if the setUrl method has not been called.
39081 * This does not activate the panel, just updates its content.
39083 refresh : function(){
39084 if(this.refreshDelegate){
39085 this.loaded = false;
39086 this.refreshDelegate();
39091 _setLoaded : function(){
39092 this.loaded = true;
39096 closeClick : function(e){
39099 this.fireEvent("beforeclose", this, o);
39100 if(o.cancel !== true){
39101 this.tabPanel.removeTab(this.id);
39105 * The text displayed in the tooltip for the close icon.
39108 closeText : "Close this tab"
39111 * This script refer to:
39112 * Title: International Telephone Input
39113 * Author: Jack O'Connor
39114 * Code version: v12.1.12
39115 * Availability: https://github.com/jackocnr/intl-tel-input.git
39118 Roo.bootstrap.PhoneInputData = function() {
39121 "Afghanistan (افغانستان)",
39126 "Albania (Shqipëri)",
39131 "Algeria (الجزائر)",
39156 "Antigua and Barbuda",
39166 "Armenia (Հայաստան)",
39182 "Austria (Österreich)",
39187 "Azerbaijan (Azərbaycan)",
39197 "Bahrain (البحرين)",
39202 "Bangladesh (বাংলাদেশ)",
39212 "Belarus (Беларусь)",
39217 "Belgium (België)",
39247 "Bosnia and Herzegovina (Босна и Херцеговина)",
39262 "British Indian Ocean Territory",
39267 "British Virgin Islands",
39277 "Bulgaria (България)",
39287 "Burundi (Uburundi)",
39292 "Cambodia (កម្ពុជា)",
39297 "Cameroon (Cameroun)",
39306 ["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"]
39309 "Cape Verde (Kabu Verdi)",
39314 "Caribbean Netherlands",
39325 "Central African Republic (République centrafricaine)",
39345 "Christmas Island",
39351 "Cocos (Keeling) Islands",
39362 "Comoros (جزر القمر)",
39367 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39372 "Congo (Republic) (Congo-Brazzaville)",
39392 "Croatia (Hrvatska)",
39413 "Czech Republic (Česká republika)",
39418 "Denmark (Danmark)",
39433 "Dominican Republic (República Dominicana)",
39437 ["809", "829", "849"]
39455 "Equatorial Guinea (Guinea Ecuatorial)",
39475 "Falkland Islands (Islas Malvinas)",
39480 "Faroe Islands (Føroyar)",
39501 "French Guiana (Guyane française)",
39506 "French Polynesia (Polynésie française)",
39521 "Georgia (საქართველო)",
39526 "Germany (Deutschland)",
39546 "Greenland (Kalaallit Nunaat)",
39583 "Guinea-Bissau (Guiné Bissau)",
39608 "Hungary (Magyarország)",
39613 "Iceland (Ísland)",
39633 "Iraq (العراق)",
39649 "Israel (ישראל)",
39676 "Jordan (الأردن)",
39681 "Kazakhstan (Казахстан)",
39702 "Kuwait (الكويت)",
39707 "Kyrgyzstan (Кыргызстан)",
39717 "Latvia (Latvija)",
39722 "Lebanon (لبنان)",
39737 "Libya (ليبيا)",
39747 "Lithuania (Lietuva)",
39762 "Macedonia (FYROM) (Македонија)",
39767 "Madagascar (Madagasikara)",
39797 "Marshall Islands",
39807 "Mauritania (موريتانيا)",
39812 "Mauritius (Moris)",
39833 "Moldova (Republica Moldova)",
39843 "Mongolia (Монгол)",
39848 "Montenegro (Crna Gora)",
39858 "Morocco (المغرب)",
39864 "Mozambique (Moçambique)",
39869 "Myanmar (Burma) (မြန်မာ)",
39874 "Namibia (Namibië)",
39889 "Netherlands (Nederland)",
39894 "New Caledonia (Nouvelle-Calédonie)",
39929 "North Korea (조선 민주주의 인민 공화국)",
39934 "Northern Mariana Islands",
39950 "Pakistan (پاکستان)",
39960 "Palestine (فلسطين)",
39970 "Papua New Guinea",
40012 "Réunion (La Réunion)",
40018 "Romania (România)",
40034 "Saint Barthélemy",
40045 "Saint Kitts and Nevis",
40055 "Saint Martin (Saint-Martin (partie française))",
40061 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40066 "Saint Vincent and the Grenadines",
40081 "São Tomé and Príncipe (São Tomé e Príncipe)",
40086 "Saudi Arabia (المملكة العربية السعودية)",
40091 "Senegal (Sénégal)",
40121 "Slovakia (Slovensko)",
40126 "Slovenia (Slovenija)",
40136 "Somalia (Soomaaliya)",
40146 "South Korea (대한민국)",
40151 "South Sudan (جنوب السودان)",
40161 "Sri Lanka (ශ්රී ලංකාව)",
40166 "Sudan (السودان)",
40176 "Svalbard and Jan Mayen",
40187 "Sweden (Sverige)",
40192 "Switzerland (Schweiz)",
40197 "Syria (سوريا)",
40242 "Trinidad and Tobago",
40247 "Tunisia (تونس)",
40252 "Turkey (Türkiye)",
40262 "Turks and Caicos Islands",
40272 "U.S. Virgin Islands",
40282 "Ukraine (Україна)",
40287 "United Arab Emirates (الإمارات العربية المتحدة)",
40309 "Uzbekistan (Oʻzbekiston)",
40319 "Vatican City (Città del Vaticano)",
40330 "Vietnam (Việt Nam)",
40335 "Wallis and Futuna (Wallis-et-Futuna)",
40340 "Western Sahara (الصحراء الغربية)",
40346 "Yemen (اليمن)",
40370 * This script refer to:
40371 * Title: International Telephone Input
40372 * Author: Jack O'Connor
40373 * Code version: v12.1.12
40374 * Availability: https://github.com/jackocnr/intl-tel-input.git
40378 * @class Roo.bootstrap.PhoneInput
40379 * @extends Roo.bootstrap.TriggerField
40380 * An input with International dial-code selection
40382 * @cfg {String} defaultDialCode default '+852'
40383 * @cfg {Array} preferedCountries default []
40386 * Create a new PhoneInput.
40387 * @param {Object} config Configuration options
40390 Roo.bootstrap.PhoneInput = function(config) {
40391 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40394 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40396 listWidth: undefined,
40398 selectedClass: 'active',
40400 invalidClass : "has-warning",
40402 validClass: 'has-success',
40404 allowed: '0123456789',
40409 * @cfg {String} defaultDialCode The default dial code when initializing the input
40411 defaultDialCode: '+852',
40414 * @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
40416 preferedCountries: false,
40418 getAutoCreate : function()
40420 var data = Roo.bootstrap.PhoneInputData();
40421 var align = this.labelAlign || this.parentLabelAlign();
40424 this.allCountries = [];
40425 this.dialCodeMapping = [];
40427 for (var i = 0; i < data.length; i++) {
40429 this.allCountries[i] = {
40433 priority: c[3] || 0,
40434 areaCodes: c[4] || null
40436 this.dialCodeMapping[c[2]] = {
40439 priority: c[3] || 0,
40440 areaCodes: c[4] || null
40452 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40453 maxlength: this.max_length,
40454 cls : 'form-control tel-input',
40455 autocomplete: 'new-password'
40458 var hiddenInput = {
40461 cls: 'hidden-tel-input'
40465 hiddenInput.name = this.name;
40468 if (this.disabled) {
40469 input.disabled = true;
40472 var flag_container = {
40489 cls: this.hasFeedback ? 'has-feedback' : '',
40495 cls: 'dial-code-holder',
40502 cls: 'roo-select2-container input-group',
40509 if (this.fieldLabel.length) {
40512 tooltip: 'This field is required'
40518 cls: 'control-label',
40524 html: this.fieldLabel
40527 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40533 if(this.indicatorpos == 'right') {
40534 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40541 if(align == 'left') {
40549 if(this.labelWidth > 12){
40550 label.style = "width: " + this.labelWidth + 'px';
40552 if(this.labelWidth < 13 && this.labelmd == 0){
40553 this.labelmd = this.labelWidth;
40555 if(this.labellg > 0){
40556 label.cls += ' col-lg-' + this.labellg;
40557 input.cls += ' col-lg-' + (12 - this.labellg);
40559 if(this.labelmd > 0){
40560 label.cls += ' col-md-' + this.labelmd;
40561 container.cls += ' col-md-' + (12 - this.labelmd);
40563 if(this.labelsm > 0){
40564 label.cls += ' col-sm-' + this.labelsm;
40565 container.cls += ' col-sm-' + (12 - this.labelsm);
40567 if(this.labelxs > 0){
40568 label.cls += ' col-xs-' + this.labelxs;
40569 container.cls += ' col-xs-' + (12 - this.labelxs);
40579 var settings = this;
40581 ['xs','sm','md','lg'].map(function(size){
40582 if (settings[size]) {
40583 cfg.cls += ' col-' + size + '-' + settings[size];
40587 this.store = new Roo.data.Store({
40588 proxy : new Roo.data.MemoryProxy({}),
40589 reader : new Roo.data.JsonReader({
40600 'name' : 'dialCode',
40604 'name' : 'priority',
40608 'name' : 'areaCodes',
40615 if(!this.preferedCountries) {
40616 this.preferedCountries = [
40623 var p = this.preferedCountries.reverse();
40626 for (var i = 0; i < p.length; i++) {
40627 for (var j = 0; j < this.allCountries.length; j++) {
40628 if(this.allCountries[j].iso2 == p[i]) {
40629 var t = this.allCountries[j];
40630 this.allCountries.splice(j,1);
40631 this.allCountries.unshift(t);
40637 this.store.proxy.data = {
40639 data: this.allCountries
40645 initEvents : function()
40648 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40650 this.indicator = this.indicatorEl();
40651 this.flag = this.flagEl();
40652 this.dialCodeHolder = this.dialCodeHolderEl();
40654 this.trigger = this.el.select('div.flag-box',true).first();
40655 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40660 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40661 _this.list.setWidth(lw);
40664 this.list.on('mouseover', this.onViewOver, this);
40665 this.list.on('mousemove', this.onViewMove, this);
40666 this.inputEl().on("keyup", this.onKeyUp, this);
40667 this.inputEl().on("keypress", this.onKeyPress, this);
40669 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40671 this.view = new Roo.View(this.list, this.tpl, {
40672 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40675 this.view.on('click', this.onViewClick, this);
40676 this.setValue(this.defaultDialCode);
40679 onTriggerClick : function(e)
40681 Roo.log('trigger click');
40686 if(this.isExpanded()){
40688 this.hasFocus = false;
40690 this.store.load({});
40691 this.hasFocus = true;
40696 isExpanded : function()
40698 return this.list.isVisible();
40701 collapse : function()
40703 if(!this.isExpanded()){
40707 Roo.get(document).un('mousedown', this.collapseIf, this);
40708 Roo.get(document).un('mousewheel', this.collapseIf, this);
40709 this.fireEvent('collapse', this);
40713 expand : function()
40717 if(this.isExpanded() || !this.hasFocus){
40721 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40722 this.list.setWidth(lw);
40725 this.restrictHeight();
40727 Roo.get(document).on('mousedown', this.collapseIf, this);
40728 Roo.get(document).on('mousewheel', this.collapseIf, this);
40730 this.fireEvent('expand', this);
40733 restrictHeight : function()
40735 this.list.alignTo(this.inputEl(), this.listAlign);
40736 this.list.alignTo(this.inputEl(), this.listAlign);
40739 onViewOver : function(e, t)
40741 if(this.inKeyMode){
40744 var item = this.view.findItemFromChild(t);
40747 var index = this.view.indexOf(item);
40748 this.select(index, false);
40753 onViewClick : function(view, doFocus, el, e)
40755 var index = this.view.getSelectedIndexes()[0];
40757 var r = this.store.getAt(index);
40760 this.onSelect(r, index);
40762 if(doFocus !== false && !this.blockFocus){
40763 this.inputEl().focus();
40767 onViewMove : function(e, t)
40769 this.inKeyMode = false;
40772 select : function(index, scrollIntoView)
40774 this.selectedIndex = index;
40775 this.view.select(index);
40776 if(scrollIntoView !== false){
40777 var el = this.view.getNode(index);
40779 this.list.scrollChildIntoView(el, false);
40784 createList : function()
40786 this.list = Roo.get(document.body).createChild({
40788 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40789 style: 'display:none'
40792 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40795 collapseIf : function(e)
40797 var in_combo = e.within(this.el);
40798 var in_list = e.within(this.list);
40799 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40801 if (in_combo || in_list || is_list) {
40807 onSelect : function(record, index)
40809 if(this.fireEvent('beforeselect', this, record, index) !== false){
40811 this.setFlagClass(record.data.iso2);
40812 this.setDialCode(record.data.dialCode);
40813 this.hasFocus = false;
40815 this.fireEvent('select', this, record, index);
40819 flagEl : function()
40821 var flag = this.el.select('div.flag',true).first();
40828 dialCodeHolderEl : function()
40830 var d = this.el.select('input.dial-code-holder',true).first();
40837 setDialCode : function(v)
40839 this.dialCodeHolder.dom.value = '+'+v;
40842 setFlagClass : function(n)
40844 this.flag.dom.className = 'flag '+n;
40847 getValue : function()
40849 var v = this.inputEl().getValue();
40850 if(this.dialCodeHolder) {
40851 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40856 setValue : function(v)
40858 var d = this.getDialCode(v);
40860 //invalid dial code
40861 if(v.length == 0 || !d || d.length == 0) {
40863 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40864 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40870 this.setFlagClass(this.dialCodeMapping[d].iso2);
40871 this.setDialCode(d);
40872 this.inputEl().dom.value = v.replace('+'+d,'');
40873 this.hiddenEl().dom.value = this.getValue();
40878 getDialCode : function(v)
40882 if (v.length == 0) {
40883 return this.dialCodeHolder.dom.value;
40887 if (v.charAt(0) != "+") {
40890 var numericChars = "";
40891 for (var i = 1; i < v.length; i++) {
40892 var c = v.charAt(i);
40895 if (this.dialCodeMapping[numericChars]) {
40896 dialCode = v.substr(1, i);
40898 if (numericChars.length == 4) {
40908 this.setValue(this.defaultDialCode);
40912 hiddenEl : function()
40914 return this.el.select('input.hidden-tel-input',true).first();
40917 // after setting val
40918 onKeyUp : function(e){
40919 this.setValue(this.getValue());
40922 onKeyPress : function(e){
40923 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40930 * @class Roo.bootstrap.MoneyField
40931 * @extends Roo.bootstrap.ComboBox
40932 * Bootstrap MoneyField class
40935 * Create a new MoneyField.
40936 * @param {Object} config Configuration options
40939 Roo.bootstrap.MoneyField = function(config) {
40941 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40945 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40948 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40950 allowDecimals : true,
40952 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40954 decimalSeparator : ".",
40956 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40958 decimalPrecision : 0,
40960 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40962 allowNegative : true,
40964 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40968 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40970 minValue : Number.NEGATIVE_INFINITY,
40972 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40974 maxValue : Number.MAX_VALUE,
40976 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40978 minText : "The minimum value for this field is {0}",
40980 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40982 maxText : "The maximum value for this field is {0}",
40984 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40985 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40987 nanText : "{0} is not a valid number",
40989 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40993 * @cfg {String} defaults currency of the MoneyField
40994 * value should be in lkey
40996 defaultCurrency : false,
40998 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
41000 thousandsDelimiter : false,
41002 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
41013 getAutoCreate : function()
41015 var align = this.labelAlign || this.parentLabelAlign();
41027 cls : 'form-control roo-money-amount-input',
41028 autocomplete: 'new-password'
41031 var hiddenInput = {
41035 cls: 'hidden-number-input'
41038 if(this.max_length) {
41039 input.maxlength = this.max_length;
41043 hiddenInput.name = this.name;
41046 if (this.disabled) {
41047 input.disabled = true;
41050 var clg = 12 - this.inputlg;
41051 var cmd = 12 - this.inputmd;
41052 var csm = 12 - this.inputsm;
41053 var cxs = 12 - this.inputxs;
41057 cls : 'row roo-money-field',
41061 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41065 cls: 'roo-select2-container input-group',
41069 cls : 'form-control roo-money-currency-input',
41070 autocomplete: 'new-password',
41072 name : this.currencyName
41076 cls : 'input-group-addon',
41090 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41094 cls: this.hasFeedback ? 'has-feedback' : '',
41105 if (this.fieldLabel.length) {
41108 tooltip: 'This field is required'
41114 cls: 'control-label',
41120 html: this.fieldLabel
41123 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41129 if(this.indicatorpos == 'right') {
41130 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41137 if(align == 'left') {
41145 if(this.labelWidth > 12){
41146 label.style = "width: " + this.labelWidth + 'px';
41148 if(this.labelWidth < 13 && this.labelmd == 0){
41149 this.labelmd = this.labelWidth;
41151 if(this.labellg > 0){
41152 label.cls += ' col-lg-' + this.labellg;
41153 input.cls += ' col-lg-' + (12 - this.labellg);
41155 if(this.labelmd > 0){
41156 label.cls += ' col-md-' + this.labelmd;
41157 container.cls += ' col-md-' + (12 - this.labelmd);
41159 if(this.labelsm > 0){
41160 label.cls += ' col-sm-' + this.labelsm;
41161 container.cls += ' col-sm-' + (12 - this.labelsm);
41163 if(this.labelxs > 0){
41164 label.cls += ' col-xs-' + this.labelxs;
41165 container.cls += ' col-xs-' + (12 - this.labelxs);
41176 var settings = this;
41178 ['xs','sm','md','lg'].map(function(size){
41179 if (settings[size]) {
41180 cfg.cls += ' col-' + size + '-' + settings[size];
41187 initEvents : function()
41189 this.indicator = this.indicatorEl();
41191 this.initCurrencyEvent();
41193 this.initNumberEvent();
41196 initCurrencyEvent : function()
41199 throw "can not find store for combo";
41202 this.store = Roo.factory(this.store, Roo.data);
41203 this.store.parent = this;
41207 this.triggerEl = this.el.select('.input-group-addon', true).first();
41209 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41214 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41215 _this.list.setWidth(lw);
41218 this.list.on('mouseover', this.onViewOver, this);
41219 this.list.on('mousemove', this.onViewMove, this);
41220 this.list.on('scroll', this.onViewScroll, this);
41223 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41226 this.view = new Roo.View(this.list, this.tpl, {
41227 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41230 this.view.on('click', this.onViewClick, this);
41232 this.store.on('beforeload', this.onBeforeLoad, this);
41233 this.store.on('load', this.onLoad, this);
41234 this.store.on('loadexception', this.onLoadException, this);
41236 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41237 "up" : function(e){
41238 this.inKeyMode = true;
41242 "down" : function(e){
41243 if(!this.isExpanded()){
41244 this.onTriggerClick();
41246 this.inKeyMode = true;
41251 "enter" : function(e){
41254 if(this.fireEvent("specialkey", this, e)){
41255 this.onViewClick(false);
41261 "esc" : function(e){
41265 "tab" : function(e){
41268 if(this.fireEvent("specialkey", this, e)){
41269 this.onViewClick(false);
41277 doRelay : function(foo, bar, hname){
41278 if(hname == 'down' || this.scope.isExpanded()){
41279 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41287 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41291 initNumberEvent : function(e)
41293 this.inputEl().on("keydown" , this.fireKey, this);
41294 this.inputEl().on("focus", this.onFocus, this);
41295 this.inputEl().on("blur", this.onBlur, this);
41297 this.inputEl().relayEvent('keyup', this);
41299 if(this.indicator){
41300 this.indicator.addClass('invisible');
41303 this.originalValue = this.getValue();
41305 if(this.validationEvent == 'keyup'){
41306 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41307 this.inputEl().on('keyup', this.filterValidation, this);
41309 else if(this.validationEvent !== false){
41310 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41313 if(this.selectOnFocus){
41314 this.on("focus", this.preFocus, this);
41317 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41318 this.inputEl().on("keypress", this.filterKeys, this);
41320 this.inputEl().relayEvent('keypress', this);
41323 var allowed = "0123456789";
41325 if(this.allowDecimals){
41326 allowed += this.decimalSeparator;
41329 if(this.allowNegative){
41333 if(this.thousandsDelimiter) {
41337 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41339 var keyPress = function(e){
41341 var k = e.getKey();
41343 var c = e.getCharCode();
41346 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41347 allowed.indexOf(String.fromCharCode(c)) === -1
41353 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41357 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41362 this.inputEl().on("keypress", keyPress, this);
41366 onTriggerClick : function(e)
41373 this.loadNext = false;
41375 if(this.isExpanded()){
41380 this.hasFocus = true;
41382 if(this.triggerAction == 'all') {
41383 this.doQuery(this.allQuery, true);
41387 this.doQuery(this.getRawValue());
41390 getCurrency : function()
41392 var v = this.currencyEl().getValue();
41397 restrictHeight : function()
41399 this.list.alignTo(this.currencyEl(), this.listAlign);
41400 this.list.alignTo(this.currencyEl(), this.listAlign);
41403 onViewClick : function(view, doFocus, el, e)
41405 var index = this.view.getSelectedIndexes()[0];
41407 var r = this.store.getAt(index);
41410 this.onSelect(r, index);
41414 onSelect : function(record, index){
41416 if(this.fireEvent('beforeselect', this, record, index) !== false){
41418 this.setFromCurrencyData(index > -1 ? record.data : false);
41422 this.fireEvent('select', this, record, index);
41426 setFromCurrencyData : function(o)
41430 this.lastCurrency = o;
41432 if (this.currencyField) {
41433 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41435 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41438 this.lastSelectionText = currency;
41440 //setting default currency
41441 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41442 this.setCurrency(this.defaultCurrency);
41446 this.setCurrency(currency);
41449 setFromData : function(o)
41453 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41455 this.setFromCurrencyData(c);
41460 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41462 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41465 this.setValue(value);
41469 setCurrency : function(v)
41471 this.currencyValue = v;
41474 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41479 setValue : function(v)
41481 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41487 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41489 this.inputEl().dom.value = (v == '') ? '' :
41490 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41492 if(!this.allowZero && v === '0') {
41493 this.hiddenEl().dom.value = '';
41494 this.inputEl().dom.value = '';
41501 getRawValue : function()
41503 var v = this.inputEl().getValue();
41508 getValue : function()
41510 return this.fixPrecision(this.parseValue(this.getRawValue()));
41513 parseValue : function(value)
41515 if(this.thousandsDelimiter) {
41517 r = new RegExp(",", "g");
41518 value = value.replace(r, "");
41521 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41522 return isNaN(value) ? '' : value;
41526 fixPrecision : function(value)
41528 if(this.thousandsDelimiter) {
41530 r = new RegExp(",", "g");
41531 value = value.replace(r, "");
41534 var nan = isNaN(value);
41536 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41537 return nan ? '' : value;
41539 return parseFloat(value).toFixed(this.decimalPrecision);
41542 decimalPrecisionFcn : function(v)
41544 return Math.floor(v);
41547 validateValue : function(value)
41549 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41553 var num = this.parseValue(value);
41556 this.markInvalid(String.format(this.nanText, value));
41560 if(num < this.minValue){
41561 this.markInvalid(String.format(this.minText, this.minValue));
41565 if(num > this.maxValue){
41566 this.markInvalid(String.format(this.maxText, this.maxValue));
41573 validate : function()
41575 if(this.disabled || this.allowBlank){
41580 var currency = this.getCurrency();
41582 if(this.validateValue(this.getRawValue()) && currency.length){
41587 this.markInvalid();
41591 getName: function()
41596 beforeBlur : function()
41602 var v = this.parseValue(this.getRawValue());
41609 onBlur : function()
41613 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41614 //this.el.removeClass(this.focusClass);
41617 this.hasFocus = false;
41619 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41623 var v = this.getValue();
41625 if(String(v) !== String(this.startValue)){
41626 this.fireEvent('change', this, v, this.startValue);
41629 this.fireEvent("blur", this);
41632 inputEl : function()
41634 return this.el.select('.roo-money-amount-input', true).first();
41637 currencyEl : function()
41639 return this.el.select('.roo-money-currency-input', true).first();
41642 hiddenEl : function()
41644 return this.el.select('input.hidden-number-input',true).first();
41648 * @class Roo.bootstrap.BezierSignature
41649 * @extends Roo.bootstrap.Component
41650 * Bootstrap BezierSignature class
41651 * This script refer to:
41652 * Title: Signature Pad
41654 * Availability: https://github.com/szimek/signature_pad
41657 * Create a new BezierSignature
41658 * @param {Object} config The config object
41661 Roo.bootstrap.BezierSignature = function(config){
41662 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41668 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41675 mouse_btn_down: true,
41678 * @cfg {int} canvas height
41680 canvas_height: '200px',
41683 * @cfg {float|function} Radius of a single dot.
41688 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41693 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41698 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41703 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41708 * @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.
41710 bg_color: 'rgba(0, 0, 0, 0)',
41713 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41715 dot_color: 'black',
41718 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41720 velocity_filter_weight: 0.7,
41723 * @cfg {function} Callback when stroke begin.
41728 * @cfg {function} Callback when stroke end.
41732 getAutoCreate : function()
41734 var cls = 'roo-signature column';
41737 cls += ' ' + this.cls;
41747 for(var i = 0; i < col_sizes.length; i++) {
41748 if(this[col_sizes[i]]) {
41749 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41759 cls: 'roo-signature-body',
41763 cls: 'roo-signature-body-canvas',
41764 height: this.canvas_height,
41765 width: this.canvas_width
41772 style: 'display: none'
41780 initEvents: function()
41782 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41784 var canvas = this.canvasEl();
41786 // mouse && touch event swapping...
41787 canvas.dom.style.touchAction = 'none';
41788 canvas.dom.style.msTouchAction = 'none';
41790 this.mouse_btn_down = false;
41791 canvas.on('mousedown', this._handleMouseDown, this);
41792 canvas.on('mousemove', this._handleMouseMove, this);
41793 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41795 if (window.PointerEvent) {
41796 canvas.on('pointerdown', this._handleMouseDown, this);
41797 canvas.on('pointermove', this._handleMouseMove, this);
41798 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41801 if ('ontouchstart' in window) {
41802 canvas.on('touchstart', this._handleTouchStart, this);
41803 canvas.on('touchmove', this._handleTouchMove, this);
41804 canvas.on('touchend', this._handleTouchEnd, this);
41807 Roo.EventManager.onWindowResize(this.resize, this, true);
41809 // file input event
41810 this.fileEl().on('change', this.uploadImage, this);
41817 resize: function(){
41819 var canvas = this.canvasEl().dom;
41820 var ctx = this.canvasElCtx();
41821 var img_data = false;
41823 if(canvas.width > 0) {
41824 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41826 // setting canvas width will clean img data
41829 var style = window.getComputedStyle ?
41830 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41832 var padding_left = parseInt(style.paddingLeft) || 0;
41833 var padding_right = parseInt(style.paddingRight) || 0;
41835 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41838 ctx.putImageData(img_data, 0, 0);
41842 _handleMouseDown: function(e)
41844 if (e.browserEvent.which === 1) {
41845 this.mouse_btn_down = true;
41846 this.strokeBegin(e);
41850 _handleMouseMove: function (e)
41852 if (this.mouse_btn_down) {
41853 this.strokeMoveUpdate(e);
41857 _handleMouseUp: function (e)
41859 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41860 this.mouse_btn_down = false;
41865 _handleTouchStart: function (e) {
41867 e.preventDefault();
41868 if (e.browserEvent.targetTouches.length === 1) {
41869 // var touch = e.browserEvent.changedTouches[0];
41870 // this.strokeBegin(touch);
41872 this.strokeBegin(e); // assume e catching the correct xy...
41876 _handleTouchMove: function (e) {
41877 e.preventDefault();
41878 // var touch = event.targetTouches[0];
41879 // _this._strokeMoveUpdate(touch);
41880 this.strokeMoveUpdate(e);
41883 _handleTouchEnd: function (e) {
41884 var wasCanvasTouched = e.target === this.canvasEl().dom;
41885 if (wasCanvasTouched) {
41886 e.preventDefault();
41887 // var touch = event.changedTouches[0];
41888 // _this._strokeEnd(touch);
41893 reset: function () {
41894 this._lastPoints = [];
41895 this._lastVelocity = 0;
41896 this._lastWidth = (this.min_width + this.max_width) / 2;
41897 this.canvasElCtx().fillStyle = this.dot_color;
41900 strokeMoveUpdate: function(e)
41902 this.strokeUpdate(e);
41904 if (this.throttle) {
41905 this.throttleStroke(this.strokeUpdate, this.throttle);
41908 this.strokeUpdate(e);
41912 strokeBegin: function(e)
41914 var newPointGroup = {
41915 color: this.dot_color,
41919 if (typeof this.onBegin === 'function') {
41923 this.curve_data.push(newPointGroup);
41925 this.strokeUpdate(e);
41928 strokeUpdate: function(e)
41930 var rect = this.canvasEl().dom.getBoundingClientRect();
41931 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41932 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41933 var lastPoints = lastPointGroup.points;
41934 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41935 var isLastPointTooClose = lastPoint
41936 ? point.distanceTo(lastPoint) <= this.min_distance
41938 var color = lastPointGroup.color;
41939 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41940 var curve = this.addPoint(point);
41942 this.drawDot({color: color, point: point});
41945 this.drawCurve({color: color, curve: curve});
41955 strokeEnd: function(e)
41957 this.strokeUpdate(e);
41958 if (typeof this.onEnd === 'function') {
41963 addPoint: function (point) {
41964 var _lastPoints = this._lastPoints;
41965 _lastPoints.push(point);
41966 if (_lastPoints.length > 2) {
41967 if (_lastPoints.length === 3) {
41968 _lastPoints.unshift(_lastPoints[0]);
41970 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41971 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41972 _lastPoints.shift();
41978 calculateCurveWidths: function (startPoint, endPoint) {
41979 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41980 (1 - this.velocity_filter_weight) * this._lastVelocity;
41982 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41985 start: this._lastWidth
41988 this._lastVelocity = velocity;
41989 this._lastWidth = newWidth;
41993 drawDot: function (_a) {
41994 var color = _a.color, point = _a.point;
41995 var ctx = this.canvasElCtx();
41996 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41998 this.drawCurveSegment(point.x, point.y, width);
42000 ctx.fillStyle = color;
42004 drawCurve: function (_a) {
42005 var color = _a.color, curve = _a.curve;
42006 var ctx = this.canvasElCtx();
42007 var widthDelta = curve.endWidth - curve.startWidth;
42008 var drawSteps = Math.floor(curve.length()) * 2;
42010 ctx.fillStyle = color;
42011 for (var i = 0; i < drawSteps; i += 1) {
42012 var t = i / drawSteps;
42018 var x = uuu * curve.startPoint.x;
42019 x += 3 * uu * t * curve.control1.x;
42020 x += 3 * u * tt * curve.control2.x;
42021 x += ttt * curve.endPoint.x;
42022 var y = uuu * curve.startPoint.y;
42023 y += 3 * uu * t * curve.control1.y;
42024 y += 3 * u * tt * curve.control2.y;
42025 y += ttt * curve.endPoint.y;
42026 var width = curve.startWidth + ttt * widthDelta;
42027 this.drawCurveSegment(x, y, width);
42033 drawCurveSegment: function (x, y, width) {
42034 var ctx = this.canvasElCtx();
42036 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
42037 this.is_empty = false;
42042 var ctx = this.canvasElCtx();
42043 var canvas = this.canvasEl().dom;
42044 ctx.fillStyle = this.bg_color;
42045 ctx.clearRect(0, 0, canvas.width, canvas.height);
42046 ctx.fillRect(0, 0, canvas.width, canvas.height);
42047 this.curve_data = [];
42049 this.is_empty = true;
42054 return this.el.select('input',true).first();
42057 canvasEl: function()
42059 return this.el.select('canvas',true).first();
42062 canvasElCtx: function()
42064 return this.el.select('canvas',true).first().dom.getContext('2d');
42067 getImage: function(type)
42069 if(this.is_empty) {
42074 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42077 drawFromImage: function(img_src)
42079 var img = new Image();
42081 img.onload = function(){
42082 this.canvasElCtx().drawImage(img, 0, 0);
42087 this.is_empty = false;
42090 selectImage: function()
42092 this.fileEl().dom.click();
42095 uploadImage: function(e)
42097 var reader = new FileReader();
42099 reader.onload = function(e){
42100 var img = new Image();
42101 img.onload = function(){
42103 this.canvasElCtx().drawImage(img, 0, 0);
42105 img.src = e.target.result;
42108 reader.readAsDataURL(e.target.files[0]);
42111 // Bezier Point Constructor
42112 Point: (function () {
42113 function Point(x, y, time) {
42116 this.time = time || Date.now();
42118 Point.prototype.distanceTo = function (start) {
42119 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42121 Point.prototype.equals = function (other) {
42122 return this.x === other.x && this.y === other.y && this.time === other.time;
42124 Point.prototype.velocityFrom = function (start) {
42125 return this.time !== start.time
42126 ? this.distanceTo(start) / (this.time - start.time)
42133 // Bezier Constructor
42134 Bezier: (function () {
42135 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42136 this.startPoint = startPoint;
42137 this.control2 = control2;
42138 this.control1 = control1;
42139 this.endPoint = endPoint;
42140 this.startWidth = startWidth;
42141 this.endWidth = endWidth;
42143 Bezier.fromPoints = function (points, widths, scope) {
42144 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42145 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42146 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42148 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42149 var dx1 = s1.x - s2.x;
42150 var dy1 = s1.y - s2.y;
42151 var dx2 = s2.x - s3.x;
42152 var dy2 = s2.y - s3.y;
42153 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42154 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42155 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42156 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42157 var dxm = m1.x - m2.x;
42158 var dym = m1.y - m2.y;
42159 var k = l2 / (l1 + l2);
42160 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42161 var tx = s2.x - cm.x;
42162 var ty = s2.y - cm.y;
42164 c1: new scope.Point(m1.x + tx, m1.y + ty),
42165 c2: new scope.Point(m2.x + tx, m2.y + ty)
42168 Bezier.prototype.length = function () {
42173 for (var i = 0; i <= steps; i += 1) {
42175 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42176 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42178 var xdiff = cx - px;
42179 var ydiff = cy - py;
42180 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42187 Bezier.prototype.point = function (t, start, c1, c2, end) {
42188 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42189 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42190 + (3.0 * c2 * (1.0 - t) * t * t)
42191 + (end * t * t * t);
42196 throttleStroke: function(fn, wait) {
42197 if (wait === void 0) { wait = 250; }
42199 var timeout = null;
42203 var later = function () {
42204 previous = Date.now();
42206 result = fn.apply(storedContext, storedArgs);
42208 storedContext = null;
42212 return function wrapper() {
42214 for (var _i = 0; _i < arguments.length; _i++) {
42215 args[_i] = arguments[_i];
42217 var now = Date.now();
42218 var remaining = wait - (now - previous);
42219 storedContext = this;
42221 if (remaining <= 0 || remaining > wait) {
42223 clearTimeout(timeout);
42227 result = fn.apply(storedContext, storedArgs);
42229 storedContext = null;
42233 else if (!timeout) {
42234 timeout = window.setTimeout(later, remaining);