2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
569 * @class Roo.bootstrap.Button
570 * @extends Roo.bootstrap.Component
571 * Bootstrap Button class
572 * @cfg {String} html The button content
573 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
574 * @cfg {String} size ( lg | sm | xs)
575 * @cfg {String} tag ( a | input | submit)
576 * @cfg {String} href empty or href
577 * @cfg {Boolean} disabled default false;
578 * @cfg {Boolean} isClose default false;
579 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
580 * @cfg {String} badge text for badge
581 * @cfg {String} theme (default|glow)
582 * @cfg {Boolean} inverse dark themed version
583 * @cfg {Boolean} toggle is it a slidy toggle button
584 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
585 * @cfg {String} ontext text for on slidy toggle state
586 * @cfg {String} offtext text for off slidy toggle state
587 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
588 * @cfg {Boolean} removeClass remove the standard class..
589 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
592 * Create a new button
593 * @param {Object} config The config object
597 Roo.bootstrap.Button = function(config){
598 Roo.bootstrap.Button.superclass.constructor.call(this, config);
599 this.weightClass = ["btn-default",
611 * When a butotn is pressed
612 * @param {Roo.bootstrap.Button} btn
613 * @param {Roo.EventObject} e
618 * After the button has been toggles
619 * @param {Roo.bootstrap.Button} btn
620 * @param {Roo.EventObject} e
621 * @param {boolean} pressed (also available as button.pressed)
627 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
645 preventDefault: true,
653 getAutoCreate : function(){
661 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
662 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
667 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
669 if (this.toggle == true) {
672 cls: 'slider-frame roo-button',
677 'data-off-text':'OFF',
678 cls: 'slider-button',
684 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
685 cfg.cls += ' '+this.weight;
694 cfg["aria-hidden"] = true;
696 cfg.html = "×";
702 if (this.theme==='default') {
703 cfg.cls = 'btn roo-button';
705 //if (this.parentType != 'Navbar') {
706 this.weight = this.weight.length ? this.weight : 'default';
708 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
710 cfg.cls += ' btn-' + this.weight;
712 } else if (this.theme==='glow') {
715 cfg.cls = 'btn-glow roo-button';
717 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
719 cfg.cls += ' ' + this.weight;
725 this.cls += ' inverse';
729 if (this.active || this.pressed === true) {
730 cfg.cls += ' active';
734 cfg.disabled = 'disabled';
738 Roo.log('changing to ul' );
740 this.glyphicon = 'caret';
743 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
745 //gsRoo.log(this.parentType);
746 if (this.parentType === 'Navbar' && !this.parent().bar) {
747 Roo.log('changing to li?');
756 href : this.href || '#'
759 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
760 cfg.cls += ' dropdown';
767 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
769 if (this.glyphicon) {
770 cfg.html = ' ' + cfg.html;
775 cls: 'glyphicon glyphicon-' + this.glyphicon
785 // cfg.cls='btn roo-button';
789 var value = cfg.html;
794 cls: 'glyphicon glyphicon-' + this.glyphicon,
813 cfg.cls += ' dropdown';
814 cfg.html = typeof(cfg.html) != 'undefined' ?
815 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
818 if (cfg.tag !== 'a' && this.href !== '') {
819 throw "Tag must be a to set href.";
820 } else if (this.href.length > 0) {
821 cfg.href = this.href;
824 if(this.removeClass){
829 cfg.target = this.target;
834 initEvents: function() {
835 // Roo.log('init events?');
836 // Roo.log(this.el.dom);
839 if (typeof (this.menu) != 'undefined') {
840 this.menu.parentType = this.xtype;
841 this.menu.triggerEl = this.el;
842 this.addxtype(Roo.apply({}, this.menu));
846 if (this.el.hasClass('roo-button')) {
847 this.el.on('click', this.onClick, this);
849 this.el.select('.roo-button').on('click', this.onClick, this);
852 if(this.removeClass){
853 this.el.on('click', this.onClick, this);
856 this.el.enableDisplayMode();
859 onClick : function(e)
865 Roo.log('button on click ');
866 if(this.preventDefault){
870 if (this.pressed === true || this.pressed === false) {
871 this.toggleActive(e);
875 this.fireEvent('click', this, e);
879 * Enables this button
883 this.disabled = false;
884 this.el.removeClass('disabled');
888 * Disable this button
892 this.disabled = true;
893 this.el.addClass('disabled');
896 * sets the active state on/off,
897 * @param {Boolean} state (optional) Force a particular state
899 setActive : function(v) {
901 this.el[v ? 'addClass' : 'removeClass']('active');
905 * toggles the current active state
907 toggleActive : function(e)
909 this.setActive(!this.pressed);
910 this.fireEvent('toggle', this, e, !this.pressed);
913 * get the current active state
914 * @return {boolean} true if it's active
916 isActive : function()
918 return this.el.hasClass('active');
921 * set the text of the first selected button
923 setText : function(str)
925 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
928 * get the text of the first selected button
932 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
935 setWeight : function(str)
937 this.el.removeClass(this.weightClass);
938 this.el.addClass('btn-' + str);
952 * @class Roo.bootstrap.Column
953 * @extends Roo.bootstrap.Component
954 * Bootstrap Column class
955 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
956 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
957 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
958 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
959 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
960 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
961 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
962 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
965 * @cfg {Boolean} hidden (true|false) hide the element
966 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
967 * @cfg {String} fa (ban|check|...) font awesome icon
968 * @cfg {Number} fasize (1|2|....) font awsome size
970 * @cfg {String} icon (info-sign|check|...) glyphicon name
972 * @cfg {String} html content of column.
975 * Create a new Column
976 * @param {Object} config The config object
979 Roo.bootstrap.Column = function(config){
980 Roo.bootstrap.Column.superclass.constructor.call(this, config);
983 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1001 getAutoCreate : function(){
1002 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1010 ['xs','sm','md','lg'].map(function(size){
1011 //Roo.log( size + ':' + settings[size]);
1013 if (settings[size+'off'] !== false) {
1014 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1017 if (settings[size] === false) {
1021 if (!settings[size]) { // 0 = hidden
1022 cfg.cls += ' hidden-' + size;
1025 cfg.cls += ' col-' + size + '-' + settings[size];
1030 cfg.cls += ' hidden';
1033 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1034 cfg.cls +=' alert alert-' + this.alert;
1038 if (this.html.length) {
1039 cfg.html = this.html;
1043 if (this.fasize > 1) {
1044 fasize = ' fa-' + this.fasize + 'x';
1046 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1051 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1070 * @class Roo.bootstrap.Container
1071 * @extends Roo.bootstrap.Component
1072 * Bootstrap Container class
1073 * @cfg {Boolean} jumbotron is it a jumbotron element
1074 * @cfg {String} html content of element
1075 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1076 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1077 * @cfg {String} header content of header (for panel)
1078 * @cfg {String} footer content of footer (for panel)
1079 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1080 * @cfg {String} tag (header|aside|section) type of HTML tag.
1081 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1082 * @cfg {String} fa font awesome icon
1083 * @cfg {String} icon (info-sign|check|...) glyphicon name
1084 * @cfg {Boolean} hidden (true|false) hide the element
1085 * @cfg {Boolean} expandable (true|false) default false
1086 * @cfg {Boolean} expanded (true|false) default true
1087 * @cfg {String} rheader contet on the right of header
1088 * @cfg {Boolean} clickable (true|false) default false
1092 * Create a new Container
1093 * @param {Object} config The config object
1096 Roo.bootstrap.Container = function(config){
1097 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1103 * After the panel has been expand
1105 * @param {Roo.bootstrap.Container} this
1110 * After the panel has been collapsed
1112 * @param {Roo.bootstrap.Container} this
1117 * When a element is chick
1118 * @param {Roo.bootstrap.Container} this
1119 * @param {Roo.EventObject} e
1125 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1143 getChildContainer : function() {
1149 if (this.panel.length) {
1150 return this.el.select('.panel-body',true).first();
1157 getAutoCreate : function(){
1160 tag : this.tag || 'div',
1164 if (this.jumbotron) {
1165 cfg.cls = 'jumbotron';
1170 // - this is applied by the parent..
1172 // cfg.cls = this.cls + '';
1175 if (this.sticky.length) {
1177 var bd = Roo.get(document.body);
1178 if (!bd.hasClass('bootstrap-sticky')) {
1179 bd.addClass('bootstrap-sticky');
1180 Roo.select('html',true).setStyle('height', '100%');
1183 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1187 if (this.well.length) {
1188 switch (this.well) {
1191 cfg.cls +=' well well-' +this.well;
1200 cfg.cls += ' hidden';
1204 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1205 cfg.cls +=' alert alert-' + this.alert;
1210 if (this.panel.length) {
1211 cfg.cls += ' panel panel-' + this.panel;
1213 if (this.header.length) {
1217 if(this.expandable){
1219 cfg.cls = cfg.cls + ' expandable';
1223 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1231 cls : 'panel-title',
1232 html : (this.expandable ? ' ' : '') + this.header
1236 cls: 'panel-header-right',
1242 cls : 'panel-heading',
1243 style : this.expandable ? 'cursor: pointer' : '',
1251 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1256 if (this.footer.length) {
1258 cls : 'panel-footer',
1267 body.html = this.html || cfg.html;
1268 // prefix with the icons..
1270 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1273 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1278 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1279 cfg.cls = 'container';
1285 initEvents: function()
1287 if(this.expandable){
1288 var headerEl = this.headerEl();
1291 headerEl.on('click', this.onToggleClick, this);
1296 this.el.on('click', this.onClick, this);
1301 onToggleClick : function()
1303 var headerEl = this.headerEl();
1319 if(this.fireEvent('expand', this)) {
1321 this.expanded = true;
1323 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1325 this.el.select('.panel-body',true).first().removeClass('hide');
1327 var toggleEl = this.toggleEl();
1333 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1338 collapse : function()
1340 if(this.fireEvent('collapse', this)) {
1342 this.expanded = false;
1344 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1345 this.el.select('.panel-body',true).first().addClass('hide');
1347 var toggleEl = this.toggleEl();
1353 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1357 toggleEl : function()
1359 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1363 return this.el.select('.panel-heading .fa',true).first();
1366 headerEl : function()
1368 if(!this.el || !this.panel.length || !this.header.length){
1372 return this.el.select('.panel-heading',true).first()
1377 if(!this.el || !this.panel.length){
1381 return this.el.select('.panel-body',true).first()
1384 titleEl : function()
1386 if(!this.el || !this.panel.length || !this.header.length){
1390 return this.el.select('.panel-title',true).first();
1393 setTitle : function(v)
1395 var titleEl = this.titleEl();
1401 titleEl.dom.innerHTML = v;
1404 getTitle : function()
1407 var titleEl = this.titleEl();
1413 return titleEl.dom.innerHTML;
1416 setRightTitle : function(v)
1418 var t = this.el.select('.panel-header-right',true).first();
1424 t.dom.innerHTML = v;
1427 onClick : function(e)
1431 this.fireEvent('click', this, e);
1444 * @class Roo.bootstrap.Img
1445 * @extends Roo.bootstrap.Component
1446 * Bootstrap Img class
1447 * @cfg {Boolean} imgResponsive false | true
1448 * @cfg {String} border rounded | circle | thumbnail
1449 * @cfg {String} src image source
1450 * @cfg {String} alt image alternative text
1451 * @cfg {String} href a tag href
1452 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1453 * @cfg {String} xsUrl xs image source
1454 * @cfg {String} smUrl sm image source
1455 * @cfg {String} mdUrl md image source
1456 * @cfg {String} lgUrl lg image source
1459 * Create a new Input
1460 * @param {Object} config The config object
1463 Roo.bootstrap.Img = function(config){
1464 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1470 * The img click event for the img.
1471 * @param {Roo.EventObject} e
1477 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1479 imgResponsive: true,
1489 getAutoCreate : function()
1491 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1492 return this.createSingleImg();
1497 cls: 'roo-image-responsive-group',
1502 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1504 if(!_this[size + 'Url']){
1510 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1511 html: _this.html || cfg.html,
1512 src: _this[size + 'Url']
1515 img.cls += ' roo-image-responsive-' + size;
1517 var s = ['xs', 'sm', 'md', 'lg'];
1519 s.splice(s.indexOf(size), 1);
1521 Roo.each(s, function(ss){
1522 img.cls += ' hidden-' + ss;
1525 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1526 cfg.cls += ' img-' + _this.border;
1530 cfg.alt = _this.alt;
1543 a.target = _this.target;
1547 cfg.cn.push((_this.href) ? a : img);
1554 createSingleImg : function()
1558 cls: (this.imgResponsive) ? 'img-responsive' : '',
1560 src : 'about:blank' // just incase src get's set to undefined?!?
1563 cfg.html = this.html || cfg.html;
1565 cfg.src = this.src || cfg.src;
1567 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1568 cfg.cls += ' img-' + this.border;
1585 a.target = this.target;
1590 return (this.href) ? a : cfg;
1593 initEvents: function()
1596 this.el.on('click', this.onClick, this);
1601 onClick : function(e)
1603 Roo.log('img onclick');
1604 this.fireEvent('click', this, e);
1607 * Sets the url of the image - used to update it
1608 * @param {String} url the url of the image
1611 setSrc : function(url)
1615 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1616 this.el.dom.src = url;
1620 this.el.select('img', true).first().dom.src = url;
1636 * @class Roo.bootstrap.Link
1637 * @extends Roo.bootstrap.Component
1638 * Bootstrap Link Class
1639 * @cfg {String} alt image alternative text
1640 * @cfg {String} href a tag href
1641 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1642 * @cfg {String} html the content of the link.
1643 * @cfg {String} anchor name for the anchor link
1644 * @cfg {String} fa - favicon
1646 * @cfg {Boolean} preventDefault (true | false) default false
1650 * Create a new Input
1651 * @param {Object} config The config object
1654 Roo.bootstrap.Link = function(config){
1655 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1661 * The img click event for the img.
1662 * @param {Roo.EventObject} e
1668 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1672 preventDefault: false,
1678 getAutoCreate : function()
1680 var html = this.html || '';
1682 if (this.fa !== false) {
1683 html = '<i class="fa fa-' + this.fa + '"></i>';
1688 // anchor's do not require html/href...
1689 if (this.anchor === false) {
1691 cfg.href = this.href || '#';
1693 cfg.name = this.anchor;
1694 if (this.html !== false || this.fa !== false) {
1697 if (this.href !== false) {
1698 cfg.href = this.href;
1702 if(this.alt !== false){
1707 if(this.target !== false) {
1708 cfg.target = this.target;
1714 initEvents: function() {
1716 if(!this.href || this.preventDefault){
1717 this.el.on('click', this.onClick, this);
1721 onClick : function(e)
1723 if(this.preventDefault){
1726 //Roo.log('img onclick');
1727 this.fireEvent('click', this, e);
1740 * @class Roo.bootstrap.Header
1741 * @extends Roo.bootstrap.Component
1742 * Bootstrap Header class
1743 * @cfg {String} html content of header
1744 * @cfg {Number} level (1|2|3|4|5|6) default 1
1747 * Create a new Header
1748 * @param {Object} config The config object
1752 Roo.bootstrap.Header = function(config){
1753 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1756 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1764 getAutoCreate : function(){
1769 tag: 'h' + (1 *this.level),
1770 html: this.html || ''
1782 * Ext JS Library 1.1.1
1783 * Copyright(c) 2006-2007, Ext JS, LLC.
1785 * Originally Released Under LGPL - original licence link has changed is not relivant.
1788 * <script type="text/javascript">
1792 * @class Roo.bootstrap.MenuMgr
1793 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1796 Roo.bootstrap.MenuMgr = function(){
1797 var menus, active, groups = {}, attached = false, lastShow = new Date();
1799 // private - called when first menu is created
1802 active = new Roo.util.MixedCollection();
1803 Roo.get(document).addKeyListener(27, function(){
1804 if(active.length > 0){
1812 if(active && active.length > 0){
1813 var c = active.clone();
1823 if(active.length < 1){
1824 Roo.get(document).un("mouseup", onMouseDown);
1832 var last = active.last();
1833 lastShow = new Date();
1836 Roo.get(document).on("mouseup", onMouseDown);
1841 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1842 m.parentMenu.activeChild = m;
1843 }else if(last && last.isVisible()){
1844 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1849 function onBeforeHide(m){
1851 m.activeChild.hide();
1853 if(m.autoHideTimer){
1854 clearTimeout(m.autoHideTimer);
1855 delete m.autoHideTimer;
1860 function onBeforeShow(m){
1861 var pm = m.parentMenu;
1862 if(!pm && !m.allowOtherMenus){
1864 }else if(pm && pm.activeChild && active != m){
1865 pm.activeChild.hide();
1869 // private this should really trigger on mouseup..
1870 function onMouseDown(e){
1871 Roo.log("on Mouse Up");
1873 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1874 Roo.log("MenuManager hideAll");
1883 function onBeforeCheck(mi, state){
1885 var g = groups[mi.group];
1886 for(var i = 0, l = g.length; i < l; i++){
1888 g[i].setChecked(false);
1897 * Hides all menus that are currently visible
1899 hideAll : function(){
1904 register : function(menu){
1908 menus[menu.id] = menu;
1909 menu.on("beforehide", onBeforeHide);
1910 menu.on("hide", onHide);
1911 menu.on("beforeshow", onBeforeShow);
1912 menu.on("show", onShow);
1914 if(g && menu.events["checkchange"]){
1918 groups[g].push(menu);
1919 menu.on("checkchange", onCheck);
1924 * Returns a {@link Roo.menu.Menu} object
1925 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1926 * be used to generate and return a new Menu instance.
1928 get : function(menu){
1929 if(typeof menu == "string"){ // menu id
1931 }else if(menu.events){ // menu instance
1934 /*else if(typeof menu.length == 'number'){ // array of menu items?
1935 return new Roo.bootstrap.Menu({items:menu});
1936 }else{ // otherwise, must be a config
1937 return new Roo.bootstrap.Menu(menu);
1944 unregister : function(menu){
1945 delete menus[menu.id];
1946 menu.un("beforehide", onBeforeHide);
1947 menu.un("hide", onHide);
1948 menu.un("beforeshow", onBeforeShow);
1949 menu.un("show", onShow);
1951 if(g && menu.events["checkchange"]){
1952 groups[g].remove(menu);
1953 menu.un("checkchange", onCheck);
1958 registerCheckable : function(menuItem){
1959 var g = menuItem.group;
1964 groups[g].push(menuItem);
1965 menuItem.on("beforecheckchange", onBeforeCheck);
1970 unregisterCheckable : function(menuItem){
1971 var g = menuItem.group;
1973 groups[g].remove(menuItem);
1974 menuItem.un("beforecheckchange", onBeforeCheck);
1986 * @class Roo.bootstrap.Menu
1987 * @extends Roo.bootstrap.Component
1988 * Bootstrap Menu class - container for MenuItems
1989 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1990 * @cfg {bool} hidden if the menu should be hidden when rendered.
1991 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1992 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1996 * @param {Object} config The config object
2000 Roo.bootstrap.Menu = function(config){
2001 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2002 if (this.registerMenu && this.type != 'treeview') {
2003 Roo.bootstrap.MenuMgr.register(this);
2008 * Fires before this menu is displayed
2009 * @param {Roo.menu.Menu} this
2014 * Fires before this menu is hidden
2015 * @param {Roo.menu.Menu} this
2020 * Fires after this menu is displayed
2021 * @param {Roo.menu.Menu} this
2026 * Fires after this menu is hidden
2027 * @param {Roo.menu.Menu} this
2032 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2033 * @param {Roo.menu.Menu} this
2034 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2035 * @param {Roo.EventObject} e
2040 * Fires when the mouse is hovering over this menu
2041 * @param {Roo.menu.Menu} this
2042 * @param {Roo.EventObject} e
2043 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2048 * Fires when the mouse exits this menu
2049 * @param {Roo.menu.Menu} this
2050 * @param {Roo.EventObject} e
2051 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2056 * Fires when a menu item contained in this menu is clicked
2057 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2058 * @param {Roo.EventObject} e
2062 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2065 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2069 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2072 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2074 registerMenu : true,
2076 menuItems :false, // stores the menu items..
2086 getChildContainer : function() {
2090 getAutoCreate : function(){
2092 //if (['right'].indexOf(this.align)!==-1) {
2093 // cfg.cn[1].cls += ' pull-right'
2099 cls : 'dropdown-menu' ,
2100 style : 'z-index:1000'
2104 if (this.type === 'submenu') {
2105 cfg.cls = 'submenu active';
2107 if (this.type === 'treeview') {
2108 cfg.cls = 'treeview-menu';
2113 initEvents : function() {
2115 // Roo.log("ADD event");
2116 // Roo.log(this.triggerEl.dom);
2118 this.triggerEl.on('click', this.onTriggerClick, this);
2120 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2123 if (this.triggerEl.hasClass('nav-item')) {
2124 // dropdown toggle on the 'a' in BS4?
2125 this.triggerEl.addClass('dropdown-toggle').select('.nav-link',true).first().addClass('nav-item');
2127 this.triggerEl.addClass('dropdown-toggle');
2130 this.el.on('touchstart' , this.onTouch, this);
2132 this.el.on('click' , this.onClick, this);
2134 this.el.on("mouseover", this.onMouseOver, this);
2135 this.el.on("mouseout", this.onMouseOut, this);
2139 findTargetItem : function(e)
2141 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2145 //Roo.log(t); Roo.log(t.id);
2147 //Roo.log(this.menuitems);
2148 return this.menuitems.get(t.id);
2150 //return this.items.get(t.menuItemId);
2156 onTouch : function(e)
2158 Roo.log("menu.onTouch");
2159 //e.stopEvent(); this make the user popdown broken
2163 onClick : function(e)
2165 Roo.log("menu.onClick");
2167 var t = this.findTargetItem(e);
2168 if(!t || t.isContainer){
2173 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2174 if(t == this.activeItem && t.shouldDeactivate(e)){
2175 this.activeItem.deactivate();
2176 delete this.activeItem;
2180 this.setActiveItem(t, true);
2188 Roo.log('pass click event');
2192 this.fireEvent("click", this, t, e);
2196 if(!t.href.length || t.href == '#'){
2197 (function() { _this.hide(); }).defer(100);
2202 onMouseOver : function(e){
2203 var t = this.findTargetItem(e);
2206 // if(t.canActivate && !t.disabled){
2207 // this.setActiveItem(t, true);
2211 this.fireEvent("mouseover", this, e, t);
2213 isVisible : function(){
2214 return !this.hidden;
2216 onMouseOut : function(e){
2217 var t = this.findTargetItem(e);
2220 // if(t == this.activeItem && t.shouldDeactivate(e)){
2221 // this.activeItem.deactivate();
2222 // delete this.activeItem;
2225 this.fireEvent("mouseout", this, e, t);
2230 * Displays this menu relative to another element
2231 * @param {String/HTMLElement/Roo.Element} element The element to align to
2232 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2233 * the element (defaults to this.defaultAlign)
2234 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2236 show : function(el, pos, parentMenu){
2237 this.parentMenu = parentMenu;
2241 this.fireEvent("beforeshow", this);
2242 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2245 * Displays this menu at a specific xy position
2246 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2247 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2249 showAt : function(xy, parentMenu, /* private: */_e){
2250 this.parentMenu = parentMenu;
2255 this.fireEvent("beforeshow", this);
2256 //xy = this.el.adjustForConstraints(xy);
2260 this.hideMenuItems();
2261 this.hidden = false;
2262 this.triggerEl.addClass('open');
2264 // reassign x when hitting right
2265 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2266 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2269 // reassign y when hitting bottom
2270 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2271 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2274 // but the list may align on trigger left or trigger top... should it be a properity?
2276 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2281 this.fireEvent("show", this);
2287 this.doFocus.defer(50, this);
2291 doFocus : function(){
2293 this.focusEl.focus();
2298 * Hides this menu and optionally all parent menus
2299 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2301 hide : function(deep)
2304 this.hideMenuItems();
2305 if(this.el && this.isVisible()){
2306 this.fireEvent("beforehide", this);
2307 if(this.activeItem){
2308 this.activeItem.deactivate();
2309 this.activeItem = null;
2311 this.triggerEl.removeClass('open');;
2313 this.fireEvent("hide", this);
2315 if(deep === true && this.parentMenu){
2316 this.parentMenu.hide(true);
2320 onTriggerClick : function(e)
2322 Roo.log('trigger click');
2324 var target = e.getTarget();
2326 Roo.log(target.nodeName.toLowerCase());
2328 if(target.nodeName.toLowerCase() === 'i'){
2334 onTriggerPress : function(e)
2336 Roo.log('trigger press');
2337 //Roo.log(e.getTarget());
2338 // Roo.log(this.triggerEl.dom);
2340 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2341 var pel = Roo.get(e.getTarget());
2342 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2343 Roo.log('is treeview or dropdown?');
2347 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2351 if (this.isVisible()) {
2356 this.show(this.triggerEl, false, false);
2359 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2366 hideMenuItems : function()
2368 Roo.log("hide Menu Items");
2372 //$(backdrop).remove()
2373 this.el.select('.open',true).each(function(aa) {
2375 aa.removeClass('open');
2376 //var parent = getParent($(this))
2377 //var relatedTarget = { relatedTarget: this }
2379 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2380 //if (e.isDefaultPrevented()) return
2381 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2384 addxtypeChild : function (tree, cntr) {
2385 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2387 this.menuitems.add(comp);
2399 this.getEl().dom.innerHTML = '';
2400 this.menuitems.clear();
2414 * @class Roo.bootstrap.MenuItem
2415 * @extends Roo.bootstrap.Component
2416 * Bootstrap MenuItem class
2417 * @cfg {String} html the menu label
2418 * @cfg {String} href the link
2419 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2420 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2421 * @cfg {Boolean} active used on sidebars to highlight active itesm
2422 * @cfg {String} fa favicon to show on left of menu item.
2423 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2427 * Create a new MenuItem
2428 * @param {Object} config The config object
2432 Roo.bootstrap.MenuItem = function(config){
2433 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2438 * The raw click event for the entire grid.
2439 * @param {Roo.bootstrap.MenuItem} this
2440 * @param {Roo.EventObject} e
2446 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2450 preventDefault: false,
2451 isContainer : false,
2455 getAutoCreate : function(){
2457 if(this.isContainer){
2460 cls: 'dropdown-menu-item dropdown-item'
2474 if (this.fa !== false) {
2477 cls : 'fa fa-' + this.fa
2486 cls: 'dropdown-menu-item dropdown-item',
2489 if (this.parent().type == 'treeview') {
2490 cfg.cls = 'treeview-menu';
2493 cfg.cls += ' active';
2498 anc.href = this.href || cfg.cn[0].href ;
2499 ctag.html = this.html || cfg.cn[0].html ;
2503 initEvents: function()
2505 if (this.parent().type == 'treeview') {
2506 this.el.select('a').on('click', this.onClick, this);
2510 this.menu.parentType = this.xtype;
2511 this.menu.triggerEl = this.el;
2512 this.menu = this.addxtype(Roo.apply({}, this.menu));
2516 onClick : function(e)
2518 Roo.log('item on click ');
2520 if(this.preventDefault){
2523 //this.parent().hideMenuItems();
2525 this.fireEvent('click', this, e);
2544 * @class Roo.bootstrap.MenuSeparator
2545 * @extends Roo.bootstrap.Component
2546 * Bootstrap MenuSeparator class
2549 * Create a new MenuItem
2550 * @param {Object} config The config object
2554 Roo.bootstrap.MenuSeparator = function(config){
2555 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2558 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2560 getAutoCreate : function(){
2579 * @class Roo.bootstrap.Modal
2580 * @extends Roo.bootstrap.Component
2581 * Bootstrap Modal class
2582 * @cfg {String} title Title of dialog
2583 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2584 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2585 * @cfg {Boolean} specificTitle default false
2586 * @cfg {Array} buttons Array of buttons or standard button set..
2587 * @cfg {String} buttonPosition (left|right|center) default right
2588 * @cfg {Boolean} animate default true
2589 * @cfg {Boolean} allow_close default true
2590 * @cfg {Boolean} fitwindow default false
2591 * @cfg {String} size (sm|lg) default empty
2592 * @cfg {Number} max_width set the max width of modal
2596 * Create a new Modal Dialog
2597 * @param {Object} config The config object
2600 Roo.bootstrap.Modal = function(config){
2601 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2606 * The raw btnclick event for the button
2607 * @param {Roo.EventObject} e
2612 * Fire when dialog resize
2613 * @param {Roo.bootstrap.Modal} this
2614 * @param {Roo.EventObject} e
2618 this.buttons = this.buttons || [];
2621 this.tmpl = Roo.factory(this.tmpl);
2626 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2628 title : 'test dialog',
2638 specificTitle: false,
2640 buttonPosition: 'right',
2663 onRender : function(ct, position)
2665 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2668 var cfg = Roo.apply({}, this.getAutoCreate());
2671 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2673 //if (!cfg.name.length) {
2677 cfg.cls += ' ' + this.cls;
2680 cfg.style = this.style;
2682 this.el = Roo.get(document.body).createChild(cfg, position);
2684 //var type = this.el.dom.type;
2687 if(this.tabIndex !== undefined){
2688 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2691 this.dialogEl = this.el.select('.modal-dialog',true).first();
2692 this.bodyEl = this.el.select('.modal-body',true).first();
2693 this.closeEl = this.el.select('.modal-header .close', true).first();
2694 this.headerEl = this.el.select('.modal-header',true).first();
2695 this.titleEl = this.el.select('.modal-title',true).first();
2696 this.footerEl = this.el.select('.modal-footer',true).first();
2698 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2700 //this.el.addClass("x-dlg-modal");
2702 if (this.buttons.length) {
2703 Roo.each(this.buttons, function(bb) {
2704 var b = Roo.apply({}, bb);
2705 b.xns = b.xns || Roo.bootstrap;
2706 b.xtype = b.xtype || 'Button';
2707 if (typeof(b.listeners) == 'undefined') {
2708 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2711 var btn = Roo.factory(b);
2713 btn.render(this.el.select('.modal-footer div').first());
2717 // render the children.
2720 if(typeof(this.items) != 'undefined'){
2721 var items = this.items;
2724 for(var i =0;i < items.length;i++) {
2725 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2729 this.items = nitems;
2731 // where are these used - they used to be body/close/footer
2735 //this.el.addClass([this.fieldClass, this.cls]);
2739 getAutoCreate : function()
2743 html : this.html || ''
2748 cls : 'modal-title',
2752 if(this.specificTitle){
2758 if (this.allow_close) {
2770 if(this.size.length){
2771 size = 'modal-' + this.size;
2778 cls: "modal-dialog " + size,
2781 cls : "modal-content",
2784 cls : 'modal-header',
2789 cls : 'modal-footer',
2793 cls: 'btn-' + this.buttonPosition
2810 modal.cls += ' fade';
2816 getChildContainer : function() {
2821 getButtonContainer : function() {
2822 return this.el.select('.modal-footer div',true).first();
2825 initEvents : function()
2827 if (this.allow_close) {
2828 this.closeEl.on('click', this.hide, this);
2830 Roo.EventManager.onWindowResize(this.resize, this, true);
2837 this.maskEl.setSize(
2838 Roo.lib.Dom.getViewWidth(true),
2839 Roo.lib.Dom.getViewHeight(true)
2842 if (this.fitwindow) {
2844 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2845 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2850 if(this.max_width !== 0) {
2852 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2855 this.setSize(w, this.height);
2859 if(this.max_height) {
2860 this.setSize(w,Math.min(
2862 Roo.lib.Dom.getViewportHeight(true) - 60
2868 if(!this.fit_content) {
2869 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2873 this.setSize(w, Math.min(
2875 this.headerEl.getHeight() +
2876 this.footerEl.getHeight() +
2877 this.getChildHeight(this.bodyEl.dom.childNodes),
2878 Roo.lib.Dom.getViewportHeight(true) - 60)
2884 setSize : function(w,h)
2895 if (!this.rendered) {
2899 //this.el.setStyle('display', 'block');
2900 this.el.removeClass('hideing');
2901 this.el.addClass('show');
2903 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2906 this.el.addClass('in');
2909 this.el.addClass('in');
2912 // not sure how we can show data in here..
2914 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2917 Roo.get(document.body).addClass("x-body-masked");
2919 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2920 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2921 this.maskEl.addClass('show');
2925 this.fireEvent('show', this);
2927 // set zindex here - otherwise it appears to be ignored...
2928 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2931 this.items.forEach( function(e) {
2932 e.layout ? e.layout() : false;
2940 if(this.fireEvent("beforehide", this) !== false){
2941 this.maskEl.removeClass('show');
2942 Roo.get(document.body).removeClass("x-body-masked");
2943 this.el.removeClass('in');
2944 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2946 if(this.animate){ // why
2947 this.el.addClass('hideing');
2949 if (!this.el.hasClass('hideing')) {
2950 return; // it's been shown again...
2952 this.el.removeClass('show');
2953 this.el.removeClass('hideing');
2957 this.el.removeClass('show');
2959 this.fireEvent('hide', this);
2962 isVisible : function()
2965 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2969 addButton : function(str, cb)
2973 var b = Roo.apply({}, { html : str } );
2974 b.xns = b.xns || Roo.bootstrap;
2975 b.xtype = b.xtype || 'Button';
2976 if (typeof(b.listeners) == 'undefined') {
2977 b.listeners = { click : cb.createDelegate(this) };
2980 var btn = Roo.factory(b);
2982 btn.render(this.el.select('.modal-footer div').first());
2988 setDefaultButton : function(btn)
2990 //this.el.select('.modal-footer').()
2994 resizeTo: function(w,h)
2998 this.dialogEl.setWidth(w);
2999 if (this.diff === false) {
3000 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3003 this.bodyEl.setHeight(h - this.diff);
3005 this.fireEvent('resize', this);
3008 setContentSize : function(w, h)
3012 onButtonClick: function(btn,e)
3015 this.fireEvent('btnclick', btn.name, e);
3018 * Set the title of the Dialog
3019 * @param {String} str new Title
3021 setTitle: function(str) {
3022 this.titleEl.dom.innerHTML = str;
3025 * Set the body of the Dialog
3026 * @param {String} str new Title
3028 setBody: function(str) {
3029 this.bodyEl.dom.innerHTML = str;
3032 * Set the body of the Dialog using the template
3033 * @param {Obj} data - apply this data to the template and replace the body contents.
3035 applyBody: function(obj)
3038 Roo.log("Error - using apply Body without a template");
3041 this.tmpl.overwrite(this.bodyEl, obj);
3044 getChildHeight : function(child_nodes)
3048 child_nodes.length == 0
3053 var child_height = 0;
3055 for(var i = 0; i < child_nodes.length; i++) {
3058 * for modal with tabs...
3059 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3061 var layout_childs = child_nodes[i].childNodes;
3063 for(var j = 0; j < layout_childs.length; j++) {
3065 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3067 var layout_body_childs = layout_childs[j].childNodes;
3069 for(var k = 0; k < layout_body_childs.length; k++) {
3071 if(layout_body_childs[k].classList.contains('navbar')) {
3072 child_height += layout_body_childs[k].offsetHeight;
3076 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3078 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3080 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3082 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3083 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3098 child_height += child_nodes[i].offsetHeight;
3099 // Roo.log(child_nodes[i].offsetHeight);
3102 return child_height;
3108 Roo.apply(Roo.bootstrap.Modal, {
3110 * Button config that displays a single OK button
3119 * Button config that displays Yes and No buttons
3135 * Button config that displays OK and Cancel buttons
3150 * Button config that displays Yes, No and Cancel buttons
3174 * messagebox - can be used as a replace
3178 * @class Roo.MessageBox
3179 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3183 Roo.Msg.alert('Status', 'Changes saved successfully.');
3185 // Prompt for user data:
3186 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3188 // process text value...
3192 // Show a dialog using config options:
3194 title:'Save Changes?',
3195 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3196 buttons: Roo.Msg.YESNOCANCEL,
3203 Roo.bootstrap.MessageBox = function(){
3204 var dlg, opt, mask, waitTimer;
3205 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3206 var buttons, activeTextEl, bwidth;
3210 var handleButton = function(button){
3212 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3216 var handleHide = function(){
3218 dlg.el.removeClass(opt.cls);
3221 // Roo.TaskMgr.stop(waitTimer);
3222 // waitTimer = null;
3227 var updateButtons = function(b){
3230 buttons["ok"].hide();
3231 buttons["cancel"].hide();
3232 buttons["yes"].hide();
3233 buttons["no"].hide();
3234 //dlg.footer.dom.style.display = 'none';
3237 dlg.footerEl.dom.style.display = '';
3238 for(var k in buttons){
3239 if(typeof buttons[k] != "function"){
3242 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3243 width += buttons[k].el.getWidth()+15;
3253 var handleEsc = function(d, k, e){
3254 if(opt && opt.closable !== false){
3264 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3265 * @return {Roo.BasicDialog} The BasicDialog element
3267 getDialog : function(){
3269 dlg = new Roo.bootstrap.Modal( {
3272 //constraintoviewport:false,
3274 //collapsible : false,
3279 //buttonAlign:"center",
3280 closeClick : function(){
3281 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3284 handleButton("cancel");
3289 dlg.on("hide", handleHide);
3291 //dlg.addKeyListener(27, handleEsc);
3293 this.buttons = buttons;
3294 var bt = this.buttonText;
3295 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3296 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3297 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3298 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3300 bodyEl = dlg.bodyEl.createChild({
3302 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3303 '<textarea class="roo-mb-textarea"></textarea>' +
3304 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3306 msgEl = bodyEl.dom.firstChild;
3307 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3308 textboxEl.enableDisplayMode();
3309 textboxEl.addKeyListener([10,13], function(){
3310 if(dlg.isVisible() && opt && opt.buttons){
3313 }else if(opt.buttons.yes){
3314 handleButton("yes");
3318 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3319 textareaEl.enableDisplayMode();
3320 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3321 progressEl.enableDisplayMode();
3323 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3324 var pf = progressEl.dom.firstChild;
3326 pp = Roo.get(pf.firstChild);
3327 pp.setHeight(pf.offsetHeight);
3335 * Updates the message box body text
3336 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3337 * the XHTML-compliant non-breaking space character '&#160;')
3338 * @return {Roo.MessageBox} This message box
3340 updateText : function(text)
3342 if(!dlg.isVisible() && !opt.width){
3343 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3344 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3346 msgEl.innerHTML = text || ' ';
3348 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3349 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3351 Math.min(opt.width || cw , this.maxWidth),
3352 Math.max(opt.minWidth || this.minWidth, bwidth)
3355 activeTextEl.setWidth(w);
3357 if(dlg.isVisible()){
3358 dlg.fixedcenter = false;
3360 // to big, make it scroll. = But as usual stupid IE does not support
3363 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3364 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3365 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3367 bodyEl.dom.style.height = '';
3368 bodyEl.dom.style.overflowY = '';
3371 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3373 bodyEl.dom.style.overflowX = '';
3376 dlg.setContentSize(w, bodyEl.getHeight());
3377 if(dlg.isVisible()){
3378 dlg.fixedcenter = true;
3384 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3385 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3386 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3387 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3388 * @return {Roo.MessageBox} This message box
3390 updateProgress : function(value, text){
3392 this.updateText(text);
3395 if (pp) { // weird bug on my firefox - for some reason this is not defined
3396 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3397 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3403 * Returns true if the message box is currently displayed
3404 * @return {Boolean} True if the message box is visible, else false
3406 isVisible : function(){
3407 return dlg && dlg.isVisible();
3411 * Hides the message box if it is displayed
3414 if(this.isVisible()){
3420 * Displays a new message box, or reinitializes an existing message box, based on the config options
3421 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3422 * The following config object properties are supported:
3424 Property Type Description
3425 ---------- --------------- ------------------------------------------------------------------------------------
3426 animEl String/Element An id or Element from which the message box should animate as it opens and
3427 closes (defaults to undefined)
3428 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3429 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3430 closable Boolean False to hide the top-right close button (defaults to true). Note that
3431 progress and wait dialogs will ignore this property and always hide the
3432 close button as they can only be closed programmatically.
3433 cls String A custom CSS class to apply to the message box element
3434 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3435 displayed (defaults to 75)
3436 fn Function A callback function to execute after closing the dialog. The arguments to the
3437 function will be btn (the name of the button that was clicked, if applicable,
3438 e.g. "ok"), and text (the value of the active text field, if applicable).
3439 Progress and wait dialogs will ignore this option since they do not respond to
3440 user actions and can only be closed programmatically, so any required function
3441 should be called by the same code after it closes the dialog.
3442 icon String A CSS class that provides a background image to be used as an icon for
3443 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3444 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3445 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3446 modal Boolean False to allow user interaction with the page while the message box is
3447 displayed (defaults to true)
3448 msg String A string that will replace the existing message box body text (defaults
3449 to the XHTML-compliant non-breaking space character ' ')
3450 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3451 progress Boolean True to display a progress bar (defaults to false)
3452 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3453 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3454 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3455 title String The title text
3456 value String The string value to set into the active textbox element if displayed
3457 wait Boolean True to display a progress bar (defaults to false)
3458 width Number The width of the dialog in pixels
3465 msg: 'Please enter your address:',
3467 buttons: Roo.MessageBox.OKCANCEL,
3470 animEl: 'addAddressBtn'
3473 * @param {Object} config Configuration options
3474 * @return {Roo.MessageBox} This message box
3476 show : function(options)
3479 // this causes nightmares if you show one dialog after another
3480 // especially on callbacks..
3482 if(this.isVisible()){
3485 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3486 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3487 Roo.log("New Dialog Message:" + options.msg )
3488 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3489 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3492 var d = this.getDialog();
3494 d.setTitle(opt.title || " ");
3495 d.closeEl.setDisplayed(opt.closable !== false);
3496 activeTextEl = textboxEl;
3497 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3502 textareaEl.setHeight(typeof opt.multiline == "number" ?
3503 opt.multiline : this.defaultTextHeight);
3504 activeTextEl = textareaEl;
3513 progressEl.setDisplayed(opt.progress === true);
3514 this.updateProgress(0);
3515 activeTextEl.dom.value = opt.value || "";
3517 dlg.setDefaultButton(activeTextEl);
3519 var bs = opt.buttons;
3523 }else if(bs && bs.yes){
3524 db = buttons["yes"];
3526 dlg.setDefaultButton(db);
3528 bwidth = updateButtons(opt.buttons);
3529 this.updateText(opt.msg);
3531 d.el.addClass(opt.cls);
3533 d.proxyDrag = opt.proxyDrag === true;
3534 d.modal = opt.modal !== false;
3535 d.mask = opt.modal !== false ? mask : false;
3537 // force it to the end of the z-index stack so it gets a cursor in FF
3538 document.body.appendChild(dlg.el.dom);
3539 d.animateTarget = null;
3540 d.show(options.animEl);
3546 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3547 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3548 * and closing the message box when the process is complete.
3549 * @param {String} title The title bar text
3550 * @param {String} msg The message box body text
3551 * @return {Roo.MessageBox} This message box
3553 progress : function(title, msg){
3560 minWidth: this.minProgressWidth,
3567 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3568 * If a callback function is passed it will be called after the user clicks the button, and the
3569 * id of the button that was clicked will be passed as the only parameter to the callback
3570 * (could also be the top-right close button).
3571 * @param {String} title The title bar text
3572 * @param {String} msg The message box body text
3573 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3574 * @param {Object} scope (optional) The scope of the callback function
3575 * @return {Roo.MessageBox} This message box
3577 alert : function(title, msg, fn, scope)
3592 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3593 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3594 * You are responsible for closing the message box when the process is complete.
3595 * @param {String} msg The message box body text
3596 * @param {String} title (optional) The title bar text
3597 * @return {Roo.MessageBox} This message box
3599 wait : function(msg, title){
3610 waitTimer = Roo.TaskMgr.start({
3612 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3620 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3621 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3622 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3623 * @param {String} title The title bar text
3624 * @param {String} msg The message box body text
3625 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3626 * @param {Object} scope (optional) The scope of the callback function
3627 * @return {Roo.MessageBox} This message box
3629 confirm : function(title, msg, fn, scope){
3633 buttons: this.YESNO,
3642 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3643 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3644 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3645 * (could also be the top-right close button) and the text that was entered will be passed as the two
3646 * parameters to the callback.
3647 * @param {String} title The title bar text
3648 * @param {String} msg The message box body text
3649 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3650 * @param {Object} scope (optional) The scope of the callback function
3651 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3652 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3653 * @return {Roo.MessageBox} This message box
3655 prompt : function(title, msg, fn, scope, multiline){
3659 buttons: this.OKCANCEL,
3664 multiline: multiline,
3671 * Button config that displays a single OK button
3676 * Button config that displays Yes and No buttons
3679 YESNO : {yes:true, no:true},
3681 * Button config that displays OK and Cancel buttons
3684 OKCANCEL : {ok:true, cancel:true},
3686 * Button config that displays Yes, No and Cancel buttons
3689 YESNOCANCEL : {yes:true, no:true, cancel:true},
3692 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3695 defaultTextHeight : 75,
3697 * The maximum width in pixels of the message box (defaults to 600)
3702 * The minimum width in pixels of the message box (defaults to 100)
3707 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3708 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3711 minProgressWidth : 250,
3713 * An object containing the default button text strings that can be overriden for localized language support.
3714 * Supported properties are: ok, cancel, yes and no.
3715 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3728 * Shorthand for {@link Roo.MessageBox}
3730 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3731 Roo.Msg = Roo.Msg || Roo.MessageBox;
3740 * @class Roo.bootstrap.Navbar
3741 * @extends Roo.bootstrap.Component
3742 * Bootstrap Navbar class
3745 * Create a new Navbar
3746 * @param {Object} config The config object
3750 Roo.bootstrap.Navbar = function(config){
3751 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3755 * @event beforetoggle
3756 * Fire before toggle the menu
3757 * @param {Roo.EventObject} e
3759 "beforetoggle" : true
3763 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3772 getAutoCreate : function(){
3775 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3779 initEvents :function ()
3781 //Roo.log(this.el.select('.navbar-toggle',true));
3782 this.el.select('.navbar-toggle',true).on('click', function() {
3783 if(this.fireEvent('beforetoggle', this) !== false){
3784 this.el.select('.navbar-collapse',true).toggleClass('in');
3794 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3796 var size = this.el.getSize();
3797 this.maskEl.setSize(size.width, size.height);
3798 this.maskEl.enableDisplayMode("block");
3807 getChildContainer : function()
3809 if (this.el.select('.collapse').getCount()) {
3810 return this.el.select('.collapse',true).first();
3843 * @class Roo.bootstrap.NavSimplebar
3844 * @extends Roo.bootstrap.Navbar
3845 * Bootstrap Sidebar class
3847 * @cfg {Boolean} inverse is inverted color
3849 * @cfg {String} type (nav | pills | tabs)
3850 * @cfg {Boolean} arrangement stacked | justified
3851 * @cfg {String} align (left | right) alignment
3853 * @cfg {Boolean} main (true|false) main nav bar? default false
3854 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3856 * @cfg {String} tag (header|footer|nav|div) default is nav
3862 * Create a new Sidebar
3863 * @param {Object} config The config object
3867 Roo.bootstrap.NavSimplebar = function(config){
3868 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3871 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3887 getAutoCreate : function(){
3891 tag : this.tag || 'div',
3904 this.type = this.type || 'nav';
3905 if (['tabs','pills'].indexOf(this.type)!==-1) {
3906 cfg.cn[0].cls += ' nav-' + this.type
3910 if (this.type!=='nav') {
3911 Roo.log('nav type must be nav/tabs/pills')
3913 cfg.cn[0].cls += ' navbar-nav'
3919 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3920 cfg.cn[0].cls += ' nav-' + this.arrangement;
3924 if (this.align === 'right') {
3925 cfg.cn[0].cls += ' navbar-right';
3929 cfg.cls += ' navbar-inverse';
3953 * navbar-expand-md fixed-top
3957 * @class Roo.bootstrap.NavHeaderbar
3958 * @extends Roo.bootstrap.NavSimplebar
3959 * Bootstrap Sidebar class
3961 * @cfg {String} brand what is brand
3962 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3963 * @cfg {String} brand_href href of the brand
3964 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3965 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3966 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3967 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3970 * Create a new Sidebar
3971 * @param {Object} config The config object
3975 Roo.bootstrap.NavHeaderbar = function(config){
3976 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3980 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3987 desktopCenter : false,
3990 getAutoCreate : function(){
3993 tag: this.nav || 'nav',
3994 cls: 'navbar navbar-expand-md',
4000 if (this.desktopCenter) {
4001 cn.push({cls : 'container', cn : []});
4008 cls: 'navbar-header',
4013 cls: 'navbar-toggle navbar-toggler',
4014 'data-toggle': 'collapse',
4019 html: 'Toggle navigation'
4023 cls: 'icon-bar navbar-toggler-icon'
4041 cls: 'collapse navbar-collapse',
4045 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4047 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4048 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4050 // tag can override this..
4052 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4055 if (this.brand !== '') {
4058 href: this.brand_href ? this.brand_href : '#',
4059 cls: 'navbar-brand',
4067 cfg.cls += ' main-nav';
4075 getHeaderChildContainer : function()
4077 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4078 return this.el.select('.navbar-header',true).first();
4081 return this.getChildContainer();
4085 initEvents : function()
4087 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4089 if (this.autohide) {
4094 Roo.get(document).on('scroll',function(e) {
4095 var ns = Roo.get(document).getScroll().top;
4096 var os = prevScroll;
4100 ft.removeClass('slideDown');
4101 ft.addClass('slideUp');
4104 ft.removeClass('slideUp');
4105 ft.addClass('slideDown');
4126 * @class Roo.bootstrap.NavSidebar
4127 * @extends Roo.bootstrap.Navbar
4128 * Bootstrap Sidebar class
4131 * Create a new Sidebar
4132 * @param {Object} config The config object
4136 Roo.bootstrap.NavSidebar = function(config){
4137 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4140 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4142 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4144 getAutoCreate : function(){
4149 cls: 'sidebar sidebar-nav'
4171 * @class Roo.bootstrap.NavGroup
4172 * @extends Roo.bootstrap.Component
4173 * Bootstrap NavGroup class
4174 * @cfg {String} align (left|right)
4175 * @cfg {Boolean} inverse
4176 * @cfg {String} type (nav|pills|tab) default nav
4177 * @cfg {String} navId - reference Id for navbar.
4181 * Create a new nav group
4182 * @param {Object} config The config object
4185 Roo.bootstrap.NavGroup = function(config){
4186 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4189 Roo.bootstrap.NavGroup.register(this);
4193 * Fires when the active item changes
4194 * @param {Roo.bootstrap.NavGroup} this
4195 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4196 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4203 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4214 getAutoCreate : function()
4216 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4223 if (['tabs','pills'].indexOf(this.type)!==-1) {
4224 cfg.cls += ' nav-' + this.type
4226 if (this.type!=='nav') {
4227 Roo.log('nav type must be nav/tabs/pills')
4229 cfg.cls += ' navbar-nav mr-auto'
4232 if (this.parent() && this.parent().sidebar) {
4235 cls: 'dashboard-menu sidebar-menu'
4241 if (this.form === true) {
4247 if (this.align === 'right') {
4248 cfg.cls += ' navbar-right';
4250 cfg.cls += ' navbar-left';
4254 if (this.align === 'right') {
4255 cfg.cls += ' navbar-right';
4259 cfg.cls += ' navbar-inverse';
4267 * sets the active Navigation item
4268 * @param {Roo.bootstrap.NavItem} the new current navitem
4270 setActiveItem : function(item)
4273 Roo.each(this.navItems, function(v){
4278 v.setActive(false, true);
4285 item.setActive(true, true);
4286 this.fireEvent('changed', this, item, prev);
4291 * gets the active Navigation item
4292 * @return {Roo.bootstrap.NavItem} the current navitem
4294 getActive : function()
4298 Roo.each(this.navItems, function(v){
4309 indexOfNav : function()
4313 Roo.each(this.navItems, function(v,i){
4324 * adds a Navigation item
4325 * @param {Roo.bootstrap.NavItem} the navitem to add
4327 addItem : function(cfg)
4329 var cn = new Roo.bootstrap.NavItem(cfg);
4331 cn.parentId = this.id;
4332 cn.onRender(this.el, null);
4336 * register a Navigation item
4337 * @param {Roo.bootstrap.NavItem} the navitem to add
4339 register : function(item)
4341 this.navItems.push( item);
4342 item.navId = this.navId;
4347 * clear all the Navigation item
4350 clearAll : function()
4353 this.el.dom.innerHTML = '';
4356 getNavItem: function(tabId)
4359 Roo.each(this.navItems, function(e) {
4360 if (e.tabId == tabId) {
4370 setActiveNext : function()
4372 var i = this.indexOfNav(this.getActive());
4373 if (i > this.navItems.length) {
4376 this.setActiveItem(this.navItems[i+1]);
4378 setActivePrev : function()
4380 var i = this.indexOfNav(this.getActive());
4384 this.setActiveItem(this.navItems[i-1]);
4386 clearWasActive : function(except) {
4387 Roo.each(this.navItems, function(e) {
4388 if (e.tabId != except.tabId && e.was_active) {
4389 e.was_active = false;
4396 getWasActive : function ()
4399 Roo.each(this.navItems, function(e) {
4414 Roo.apply(Roo.bootstrap.NavGroup, {
4418 * register a Navigation Group
4419 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4421 register : function(navgrp)
4423 this.groups[navgrp.navId] = navgrp;
4427 * fetch a Navigation Group based on the navigation ID
4428 * @param {string} the navgroup to add
4429 * @returns {Roo.bootstrap.NavGroup} the navgroup
4431 get: function(navId) {
4432 if (typeof(this.groups[navId]) == 'undefined') {
4434 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4436 return this.groups[navId] ;
4451 * @class Roo.bootstrap.NavItem
4452 * @extends Roo.bootstrap.Component
4453 * Bootstrap Navbar.NavItem class
4454 * @cfg {String} href link to
4455 * @cfg {String} html content of button
4456 * @cfg {String} badge text inside badge
4457 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4458 * @cfg {String} glyphicon name of glyphicon
4459 * @cfg {String} icon name of font awesome icon
4460 * @cfg {Boolean} active Is item active
4461 * @cfg {Boolean} disabled Is item disabled
4463 * @cfg {Boolean} preventDefault (true | false) default false
4464 * @cfg {String} tabId the tab that this item activates.
4465 * @cfg {String} tagtype (a|span) render as a href or span?
4466 * @cfg {Boolean} animateRef (true|false) link to element default false
4469 * Create a new Navbar Item
4470 * @param {Object} config The config object
4472 Roo.bootstrap.NavItem = function(config){
4473 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4478 * The raw click event for the entire grid.
4479 * @param {Roo.EventObject} e
4484 * Fires when the active item active state changes
4485 * @param {Roo.bootstrap.NavItem} this
4486 * @param {boolean} state the new state
4492 * Fires when scroll to element
4493 * @param {Roo.bootstrap.NavItem} this
4494 * @param {Object} options
4495 * @param {Roo.EventObject} e
4503 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4511 preventDefault : false,
4518 getAutoCreate : function(){
4527 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4529 if (this.disabled) {
4530 cfg.cls += ' disabled';
4533 if (this.href || this.html || this.glyphicon || this.icon) {
4537 href : this.href || "#",
4538 html: this.html || ''
4541 if (this.tagtype == 'a') {
4542 cfg.cn[0].cls = 'nav-link';
4545 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4548 if(this.glyphicon) {
4549 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4554 cfg.cn[0].html += " <span class='caret'></span>";
4558 if (this.badge !== '') {
4560 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4568 initEvents: function()
4570 if (typeof (this.menu) != 'undefined') {
4571 this.menu.parentType = this.xtype;
4572 this.menu.triggerEl = this.el;
4573 this.menu = this.addxtype(Roo.apply({}, this.menu));
4576 this.el.select('a',true).on('click', this.onClick, this);
4578 if(this.tagtype == 'span'){
4579 this.el.select('span',true).on('click', this.onClick, this);
4582 // at this point parent should be available..
4583 this.parent().register(this);
4586 onClick : function(e)
4588 if (e.getTarget('.dropdown-menu-item')) {
4589 // did you click on a menu itemm.... - then don't trigger onclick..
4594 this.preventDefault ||
4597 Roo.log("NavItem - prevent Default?");
4601 if (this.disabled) {
4605 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4606 if (tg && tg.transition) {
4607 Roo.log("waiting for the transitionend");
4613 //Roo.log("fire event clicked");
4614 if(this.fireEvent('click', this, e) === false){
4618 if(this.tagtype == 'span'){
4622 //Roo.log(this.href);
4623 var ael = this.el.select('a',true).first();
4626 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4627 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4628 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4629 return; // ignore... - it's a 'hash' to another page.
4631 Roo.log("NavItem - prevent Default?");
4633 this.scrollToElement(e);
4637 var p = this.parent();
4639 if (['tabs','pills'].indexOf(p.type)!==-1) {
4640 if (typeof(p.setActiveItem) !== 'undefined') {
4641 p.setActiveItem(this);
4645 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4646 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4647 // remove the collapsed menu expand...
4648 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4652 isActive: function () {
4655 setActive : function(state, fire, is_was_active)
4657 if (this.active && !state && this.navId) {
4658 this.was_active = true;
4659 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4661 nv.clearWasActive(this);
4665 this.active = state;
4668 this.el.removeClass('active');
4669 } else if (!this.el.hasClass('active')) {
4670 this.el.addClass('active');
4673 this.fireEvent('changed', this, state);
4676 // show a panel if it's registered and related..
4678 if (!this.navId || !this.tabId || !state || is_was_active) {
4682 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4686 var pan = tg.getPanelByName(this.tabId);
4690 // if we can not flip to new panel - go back to old nav highlight..
4691 if (false == tg.showPanel(pan)) {
4692 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4694 var onav = nv.getWasActive();
4696 onav.setActive(true, false, true);
4705 // this should not be here...
4706 setDisabled : function(state)
4708 this.disabled = state;
4710 this.el.removeClass('disabled');
4711 } else if (!this.el.hasClass('disabled')) {
4712 this.el.addClass('disabled');
4718 * Fetch the element to display the tooltip on.
4719 * @return {Roo.Element} defaults to this.el
4721 tooltipEl : function()
4723 return this.el.select('' + this.tagtype + '', true).first();
4726 scrollToElement : function(e)
4728 var c = document.body;
4731 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4733 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4734 c = document.documentElement;
4737 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4743 var o = target.calcOffsetsTo(c);
4750 this.fireEvent('scrollto', this, options, e);
4752 Roo.get(c).scrollTo('top', options.value, true);
4765 * <span> icon </span>
4766 * <span> text </span>
4767 * <span>badge </span>
4771 * @class Roo.bootstrap.NavSidebarItem
4772 * @extends Roo.bootstrap.NavItem
4773 * Bootstrap Navbar.NavSidebarItem class
4774 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4775 * {Boolean} open is the menu open
4776 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4777 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4778 * {String} buttonSize (sm|md|lg)the extra classes for the button
4779 * {Boolean} showArrow show arrow next to the text (default true)
4781 * Create a new Navbar Button
4782 * @param {Object} config The config object
4784 Roo.bootstrap.NavSidebarItem = function(config){
4785 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4790 * The raw click event for the entire grid.
4791 * @param {Roo.EventObject} e
4796 * Fires when the active item active state changes
4797 * @param {Roo.bootstrap.NavSidebarItem} this
4798 * @param {boolean} state the new state
4806 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4808 badgeWeight : 'default',
4814 buttonWeight : 'default',
4820 getAutoCreate : function(){
4825 href : this.href || '#',
4831 if(this.buttonView){
4834 href : this.href || '#',
4835 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4848 cfg.cls += ' active';
4851 if (this.disabled) {
4852 cfg.cls += ' disabled';
4855 cfg.cls += ' open x-open';
4858 if (this.glyphicon || this.icon) {
4859 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4860 a.cn.push({ tag : 'i', cls : c }) ;
4863 if(!this.buttonView){
4866 html : this.html || ''
4873 if (this.badge !== '') {
4874 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4880 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4883 a.cls += ' dropdown-toggle treeview' ;
4889 initEvents : function()
4891 if (typeof (this.menu) != 'undefined') {
4892 this.menu.parentType = this.xtype;
4893 this.menu.triggerEl = this.el;
4894 this.menu = this.addxtype(Roo.apply({}, this.menu));
4897 this.el.on('click', this.onClick, this);
4899 if(this.badge !== ''){
4900 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4905 onClick : function(e)
4912 if(this.preventDefault){
4916 this.fireEvent('click', this);
4919 disable : function()
4921 this.setDisabled(true);
4926 this.setDisabled(false);
4929 setDisabled : function(state)
4931 if(this.disabled == state){
4935 this.disabled = state;
4938 this.el.addClass('disabled');
4942 this.el.removeClass('disabled');
4947 setActive : function(state)
4949 if(this.active == state){
4953 this.active = state;
4956 this.el.addClass('active');
4960 this.el.removeClass('active');
4965 isActive: function ()
4970 setBadge : function(str)
4976 this.badgeEl.dom.innerHTML = str;
4993 * @class Roo.bootstrap.Row
4994 * @extends Roo.bootstrap.Component
4995 * Bootstrap Row class (contains columns...)
4999 * @param {Object} config The config object
5002 Roo.bootstrap.Row = function(config){
5003 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5006 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5008 getAutoCreate : function(){
5027 * @class Roo.bootstrap.Element
5028 * @extends Roo.bootstrap.Component
5029 * Bootstrap Element class
5030 * @cfg {String} html contents of the element
5031 * @cfg {String} tag tag of the element
5032 * @cfg {String} cls class of the element
5033 * @cfg {Boolean} preventDefault (true|false) default false
5034 * @cfg {Boolean} clickable (true|false) default false
5037 * Create a new Element
5038 * @param {Object} config The config object
5041 Roo.bootstrap.Element = function(config){
5042 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5048 * When a element is chick
5049 * @param {Roo.bootstrap.Element} this
5050 * @param {Roo.EventObject} e
5056 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5061 preventDefault: false,
5064 getAutoCreate : function(){
5068 // cls: this.cls, double assign in parent class Component.js :: onRender
5075 initEvents: function()
5077 Roo.bootstrap.Element.superclass.initEvents.call(this);
5080 this.el.on('click', this.onClick, this);
5085 onClick : function(e)
5087 if(this.preventDefault){
5091 this.fireEvent('click', this, e);
5094 getValue : function()
5096 return this.el.dom.innerHTML;
5099 setValue : function(value)
5101 this.el.dom.innerHTML = value;
5116 * @class Roo.bootstrap.Pagination
5117 * @extends Roo.bootstrap.Component
5118 * Bootstrap Pagination class
5119 * @cfg {String} size xs | sm | md | lg
5120 * @cfg {Boolean} inverse false | true
5123 * Create a new Pagination
5124 * @param {Object} config The config object
5127 Roo.bootstrap.Pagination = function(config){
5128 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5131 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5137 getAutoCreate : function(){
5143 cfg.cls += ' inverse';
5149 cfg.cls += " " + this.cls;
5167 * @class Roo.bootstrap.PaginationItem
5168 * @extends Roo.bootstrap.Component
5169 * Bootstrap PaginationItem class
5170 * @cfg {String} html text
5171 * @cfg {String} href the link
5172 * @cfg {Boolean} preventDefault (true | false) default true
5173 * @cfg {Boolean} active (true | false) default false
5174 * @cfg {Boolean} disabled default false
5178 * Create a new PaginationItem
5179 * @param {Object} config The config object
5183 Roo.bootstrap.PaginationItem = function(config){
5184 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5189 * The raw click event for the entire grid.
5190 * @param {Roo.EventObject} e
5196 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5200 preventDefault: true,
5205 getAutoCreate : function(){
5211 href : this.href ? this.href : '#',
5212 html : this.html ? this.html : ''
5222 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5226 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5232 initEvents: function() {
5234 this.el.on('click', this.onClick, this);
5237 onClick : function(e)
5239 Roo.log('PaginationItem on click ');
5240 if(this.preventDefault){
5248 this.fireEvent('click', this, e);
5264 * @class Roo.bootstrap.Slider
5265 * @extends Roo.bootstrap.Component
5266 * Bootstrap Slider class
5269 * Create a new Slider
5270 * @param {Object} config The config object
5273 Roo.bootstrap.Slider = function(config){
5274 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5277 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5279 getAutoCreate : function(){
5283 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5287 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5299 * Ext JS Library 1.1.1
5300 * Copyright(c) 2006-2007, Ext JS, LLC.
5302 * Originally Released Under LGPL - original licence link has changed is not relivant.
5305 * <script type="text/javascript">
5310 * @class Roo.grid.ColumnModel
5311 * @extends Roo.util.Observable
5312 * This is the default implementation of a ColumnModel used by the Grid. It defines
5313 * the columns in the grid.
5316 var colModel = new Roo.grid.ColumnModel([
5317 {header: "Ticker", width: 60, sortable: true, locked: true},
5318 {header: "Company Name", width: 150, sortable: true},
5319 {header: "Market Cap.", width: 100, sortable: true},
5320 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5321 {header: "Employees", width: 100, sortable: true, resizable: false}
5326 * The config options listed for this class are options which may appear in each
5327 * individual column definition.
5328 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5330 * @param {Object} config An Array of column config objects. See this class's
5331 * config objects for details.
5333 Roo.grid.ColumnModel = function(config){
5335 * The config passed into the constructor
5337 this.config = config;
5340 // if no id, create one
5341 // if the column does not have a dataIndex mapping,
5342 // map it to the order it is in the config
5343 for(var i = 0, len = config.length; i < len; i++){
5345 if(typeof c.dataIndex == "undefined"){
5348 if(typeof c.renderer == "string"){
5349 c.renderer = Roo.util.Format[c.renderer];
5351 if(typeof c.id == "undefined"){
5354 if(c.editor && c.editor.xtype){
5355 c.editor = Roo.factory(c.editor, Roo.grid);
5357 if(c.editor && c.editor.isFormField){
5358 c.editor = new Roo.grid.GridEditor(c.editor);
5360 this.lookup[c.id] = c;
5364 * The width of columns which have no width specified (defaults to 100)
5367 this.defaultWidth = 100;
5370 * Default sortable of columns which have no sortable specified (defaults to false)
5373 this.defaultSortable = false;
5377 * @event widthchange
5378 * Fires when the width of a column changes.
5379 * @param {ColumnModel} this
5380 * @param {Number} columnIndex The column index
5381 * @param {Number} newWidth The new width
5383 "widthchange": true,
5385 * @event headerchange
5386 * Fires when the text of a header changes.
5387 * @param {ColumnModel} this
5388 * @param {Number} columnIndex The column index
5389 * @param {Number} newText The new header text
5391 "headerchange": true,
5393 * @event hiddenchange
5394 * Fires when a column is hidden or "unhidden".
5395 * @param {ColumnModel} this
5396 * @param {Number} columnIndex The column index
5397 * @param {Boolean} hidden true if hidden, false otherwise
5399 "hiddenchange": true,
5401 * @event columnmoved
5402 * Fires when a column is moved.
5403 * @param {ColumnModel} this
5404 * @param {Number} oldIndex
5405 * @param {Number} newIndex
5407 "columnmoved" : true,
5409 * @event columlockchange
5410 * Fires when a column's locked state is changed
5411 * @param {ColumnModel} this
5412 * @param {Number} colIndex
5413 * @param {Boolean} locked true if locked
5415 "columnlockchange" : true
5417 Roo.grid.ColumnModel.superclass.constructor.call(this);
5419 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5421 * @cfg {String} header The header text to display in the Grid view.
5424 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5425 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5426 * specified, the column's index is used as an index into the Record's data Array.
5429 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5430 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5433 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5434 * Defaults to the value of the {@link #defaultSortable} property.
5435 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5438 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5441 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5444 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5447 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5450 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5451 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5452 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5453 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5456 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5459 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5462 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5465 * @cfg {String} cursor (Optional)
5468 * @cfg {String} tooltip (Optional)
5471 * @cfg {Number} xs (Optional)
5474 * @cfg {Number} sm (Optional)
5477 * @cfg {Number} md (Optional)
5480 * @cfg {Number} lg (Optional)
5483 * Returns the id of the column at the specified index.
5484 * @param {Number} index The column index
5485 * @return {String} the id
5487 getColumnId : function(index){
5488 return this.config[index].id;
5492 * Returns the column for a specified id.
5493 * @param {String} id The column id
5494 * @return {Object} the column
5496 getColumnById : function(id){
5497 return this.lookup[id];
5502 * Returns the column for a specified dataIndex.
5503 * @param {String} dataIndex The column dataIndex
5504 * @return {Object|Boolean} the column or false if not found
5506 getColumnByDataIndex: function(dataIndex){
5507 var index = this.findColumnIndex(dataIndex);
5508 return index > -1 ? this.config[index] : false;
5512 * Returns the index for a specified column id.
5513 * @param {String} id The column id
5514 * @return {Number} the index, or -1 if not found
5516 getIndexById : function(id){
5517 for(var i = 0, len = this.config.length; i < len; i++){
5518 if(this.config[i].id == id){
5526 * Returns the index for a specified column dataIndex.
5527 * @param {String} dataIndex The column dataIndex
5528 * @return {Number} the index, or -1 if not found
5531 findColumnIndex : function(dataIndex){
5532 for(var i = 0, len = this.config.length; i < len; i++){
5533 if(this.config[i].dataIndex == dataIndex){
5541 moveColumn : function(oldIndex, newIndex){
5542 var c = this.config[oldIndex];
5543 this.config.splice(oldIndex, 1);
5544 this.config.splice(newIndex, 0, c);
5545 this.dataMap = null;
5546 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5549 isLocked : function(colIndex){
5550 return this.config[colIndex].locked === true;
5553 setLocked : function(colIndex, value, suppressEvent){
5554 if(this.isLocked(colIndex) == value){
5557 this.config[colIndex].locked = value;
5559 this.fireEvent("columnlockchange", this, colIndex, value);
5563 getTotalLockedWidth : function(){
5565 for(var i = 0; i < this.config.length; i++){
5566 if(this.isLocked(i) && !this.isHidden(i)){
5567 this.totalWidth += this.getColumnWidth(i);
5573 getLockedCount : function(){
5574 for(var i = 0, len = this.config.length; i < len; i++){
5575 if(!this.isLocked(i)){
5580 return this.config.length;
5584 * Returns the number of columns.
5587 getColumnCount : function(visibleOnly){
5588 if(visibleOnly === true){
5590 for(var i = 0, len = this.config.length; i < len; i++){
5591 if(!this.isHidden(i)){
5597 return this.config.length;
5601 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5602 * @param {Function} fn
5603 * @param {Object} scope (optional)
5604 * @return {Array} result
5606 getColumnsBy : function(fn, scope){
5608 for(var i = 0, len = this.config.length; i < len; i++){
5609 var c = this.config[i];
5610 if(fn.call(scope||this, c, i) === true){
5618 * Returns true if the specified column is sortable.
5619 * @param {Number} col The column index
5622 isSortable : function(col){
5623 if(typeof this.config[col].sortable == "undefined"){
5624 return this.defaultSortable;
5626 return this.config[col].sortable;
5630 * Returns the rendering (formatting) function defined for the column.
5631 * @param {Number} col The column index.
5632 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5634 getRenderer : function(col){
5635 if(!this.config[col].renderer){
5636 return Roo.grid.ColumnModel.defaultRenderer;
5638 return this.config[col].renderer;
5642 * Sets the rendering (formatting) function for a column.
5643 * @param {Number} col The column index
5644 * @param {Function} fn The function to use to process the cell's raw data
5645 * to return HTML markup for the grid view. The render function is called with
5646 * the following parameters:<ul>
5647 * <li>Data value.</li>
5648 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5649 * <li>css A CSS style string to apply to the table cell.</li>
5650 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5651 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5652 * <li>Row index</li>
5653 * <li>Column index</li>
5654 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5656 setRenderer : function(col, fn){
5657 this.config[col].renderer = fn;
5661 * Returns the width for the specified column.
5662 * @param {Number} col The column index
5665 getColumnWidth : function(col){
5666 return this.config[col].width * 1 || this.defaultWidth;
5670 * Sets the width for a column.
5671 * @param {Number} col The column index
5672 * @param {Number} width The new width
5674 setColumnWidth : function(col, width, suppressEvent){
5675 this.config[col].width = width;
5676 this.totalWidth = null;
5678 this.fireEvent("widthchange", this, col, width);
5683 * Returns the total width of all columns.
5684 * @param {Boolean} includeHidden True to include hidden column widths
5687 getTotalWidth : function(includeHidden){
5688 if(!this.totalWidth){
5689 this.totalWidth = 0;
5690 for(var i = 0, len = this.config.length; i < len; i++){
5691 if(includeHidden || !this.isHidden(i)){
5692 this.totalWidth += this.getColumnWidth(i);
5696 return this.totalWidth;
5700 * Returns the header for the specified column.
5701 * @param {Number} col The column index
5704 getColumnHeader : function(col){
5705 return this.config[col].header;
5709 * Sets the header for a column.
5710 * @param {Number} col The column index
5711 * @param {String} header The new header
5713 setColumnHeader : function(col, header){
5714 this.config[col].header = header;
5715 this.fireEvent("headerchange", this, col, header);
5719 * Returns the tooltip for the specified column.
5720 * @param {Number} col The column index
5723 getColumnTooltip : function(col){
5724 return this.config[col].tooltip;
5727 * Sets the tooltip for a column.
5728 * @param {Number} col The column index
5729 * @param {String} tooltip The new tooltip
5731 setColumnTooltip : function(col, tooltip){
5732 this.config[col].tooltip = tooltip;
5736 * Returns the dataIndex for the specified column.
5737 * @param {Number} col The column index
5740 getDataIndex : function(col){
5741 return this.config[col].dataIndex;
5745 * Sets the dataIndex for a column.
5746 * @param {Number} col The column index
5747 * @param {Number} dataIndex The new dataIndex
5749 setDataIndex : function(col, dataIndex){
5750 this.config[col].dataIndex = dataIndex;
5756 * Returns true if the cell is editable.
5757 * @param {Number} colIndex The column index
5758 * @param {Number} rowIndex The row index - this is nto actually used..?
5761 isCellEditable : function(colIndex, rowIndex){
5762 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5766 * Returns the editor defined for the cell/column.
5767 * return false or null to disable editing.
5768 * @param {Number} colIndex The column index
5769 * @param {Number} rowIndex The row index
5772 getCellEditor : function(colIndex, rowIndex){
5773 return this.config[colIndex].editor;
5777 * Sets if a column is editable.
5778 * @param {Number} col The column index
5779 * @param {Boolean} editable True if the column is editable
5781 setEditable : function(col, editable){
5782 this.config[col].editable = editable;
5787 * Returns true if the column is hidden.
5788 * @param {Number} colIndex The column index
5791 isHidden : function(colIndex){
5792 return this.config[colIndex].hidden;
5797 * Returns true if the column width cannot be changed
5799 isFixed : function(colIndex){
5800 return this.config[colIndex].fixed;
5804 * Returns true if the column can be resized
5807 isResizable : function(colIndex){
5808 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5811 * Sets if a column is hidden.
5812 * @param {Number} colIndex The column index
5813 * @param {Boolean} hidden True if the column is hidden
5815 setHidden : function(colIndex, hidden){
5816 this.config[colIndex].hidden = hidden;
5817 this.totalWidth = null;
5818 this.fireEvent("hiddenchange", this, colIndex, hidden);
5822 * Sets the editor for a column.
5823 * @param {Number} col The column index
5824 * @param {Object} editor The editor object
5826 setEditor : function(col, editor){
5827 this.config[col].editor = editor;
5831 Roo.grid.ColumnModel.defaultRenderer = function(value)
5833 if(typeof value == "object") {
5836 if(typeof value == "string" && value.length < 1){
5840 return String.format("{0}", value);
5843 // Alias for backwards compatibility
5844 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5847 * Ext JS Library 1.1.1
5848 * Copyright(c) 2006-2007, Ext JS, LLC.
5850 * Originally Released Under LGPL - original licence link has changed is not relivant.
5853 * <script type="text/javascript">
5857 * @class Roo.LoadMask
5858 * A simple utility class for generically masking elements while loading data. If the element being masked has
5859 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5860 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5861 * element's UpdateManager load indicator and will be destroyed after the initial load.
5863 * Create a new LoadMask
5864 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5865 * @param {Object} config The config object
5867 Roo.LoadMask = function(el, config){
5868 this.el = Roo.get(el);
5869 Roo.apply(this, config);
5871 this.store.on('beforeload', this.onBeforeLoad, this);
5872 this.store.on('load', this.onLoad, this);
5873 this.store.on('loadexception', this.onLoadException, this);
5874 this.removeMask = false;
5876 var um = this.el.getUpdateManager();
5877 um.showLoadIndicator = false; // disable the default indicator
5878 um.on('beforeupdate', this.onBeforeLoad, this);
5879 um.on('update', this.onLoad, this);
5880 um.on('failure', this.onLoad, this);
5881 this.removeMask = true;
5885 Roo.LoadMask.prototype = {
5887 * @cfg {Boolean} removeMask
5888 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5889 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5893 * The text to display in a centered loading message box (defaults to 'Loading...')
5897 * @cfg {String} msgCls
5898 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5900 msgCls : 'x-mask-loading',
5903 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5909 * Disables the mask to prevent it from being displayed
5911 disable : function(){
5912 this.disabled = true;
5916 * Enables the mask so that it can be displayed
5918 enable : function(){
5919 this.disabled = false;
5922 onLoadException : function()
5926 if (typeof(arguments[3]) != 'undefined') {
5927 Roo.MessageBox.alert("Error loading",arguments[3]);
5931 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5932 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5939 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5944 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5948 onBeforeLoad : function(){
5950 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5955 destroy : function(){
5957 this.store.un('beforeload', this.onBeforeLoad, this);
5958 this.store.un('load', this.onLoad, this);
5959 this.store.un('loadexception', this.onLoadException, this);
5961 var um = this.el.getUpdateManager();
5962 um.un('beforeupdate', this.onBeforeLoad, this);
5963 um.un('update', this.onLoad, this);
5964 um.un('failure', this.onLoad, this);
5975 * @class Roo.bootstrap.Table
5976 * @extends Roo.bootstrap.Component
5977 * Bootstrap Table class
5978 * @cfg {String} cls table class
5979 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5980 * @cfg {String} bgcolor Specifies the background color for a table
5981 * @cfg {Number} border Specifies whether the table cells should have borders or not
5982 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5983 * @cfg {Number} cellspacing Specifies the space between cells
5984 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5985 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5986 * @cfg {String} sortable Specifies that the table should be sortable
5987 * @cfg {String} summary Specifies a summary of the content of a table
5988 * @cfg {Number} width Specifies the width of a table
5989 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5991 * @cfg {boolean} striped Should the rows be alternative striped
5992 * @cfg {boolean} bordered Add borders to the table
5993 * @cfg {boolean} hover Add hover highlighting
5994 * @cfg {boolean} condensed Format condensed
5995 * @cfg {boolean} responsive Format condensed
5996 * @cfg {Boolean} loadMask (true|false) default false
5997 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5998 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5999 * @cfg {Boolean} rowSelection (true|false) default false
6000 * @cfg {Boolean} cellSelection (true|false) default false
6001 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6002 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6003 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6004 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6008 * Create a new Table
6009 * @param {Object} config The config object
6012 Roo.bootstrap.Table = function(config){
6013 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6018 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6019 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6020 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6021 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6023 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6025 this.sm.grid = this;
6026 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6027 this.sm = this.selModel;
6028 this.sm.xmodule = this.xmodule || false;
6031 if (this.cm && typeof(this.cm.config) == 'undefined') {
6032 this.colModel = new Roo.grid.ColumnModel(this.cm);
6033 this.cm = this.colModel;
6034 this.cm.xmodule = this.xmodule || false;
6037 this.store= Roo.factory(this.store, Roo.data);
6038 this.ds = this.store;
6039 this.ds.xmodule = this.xmodule || false;
6042 if (this.footer && this.store) {
6043 this.footer.dataSource = this.ds;
6044 this.footer = Roo.factory(this.footer);
6051 * Fires when a cell is clicked
6052 * @param {Roo.bootstrap.Table} this
6053 * @param {Roo.Element} el
6054 * @param {Number} rowIndex
6055 * @param {Number} columnIndex
6056 * @param {Roo.EventObject} e
6060 * @event celldblclick
6061 * Fires when a cell is double clicked
6062 * @param {Roo.bootstrap.Table} this
6063 * @param {Roo.Element} el
6064 * @param {Number} rowIndex
6065 * @param {Number} columnIndex
6066 * @param {Roo.EventObject} e
6068 "celldblclick" : true,
6071 * Fires when a row is clicked
6072 * @param {Roo.bootstrap.Table} this
6073 * @param {Roo.Element} el
6074 * @param {Number} rowIndex
6075 * @param {Roo.EventObject} e
6079 * @event rowdblclick
6080 * Fires when a row is double clicked
6081 * @param {Roo.bootstrap.Table} this
6082 * @param {Roo.Element} el
6083 * @param {Number} rowIndex
6084 * @param {Roo.EventObject} e
6086 "rowdblclick" : true,
6089 * Fires when a mouseover occur
6090 * @param {Roo.bootstrap.Table} this
6091 * @param {Roo.Element} el
6092 * @param {Number} rowIndex
6093 * @param {Number} columnIndex
6094 * @param {Roo.EventObject} e
6099 * Fires when a mouseout occur
6100 * @param {Roo.bootstrap.Table} this
6101 * @param {Roo.Element} el
6102 * @param {Number} rowIndex
6103 * @param {Number} columnIndex
6104 * @param {Roo.EventObject} e
6109 * Fires when a row is rendered, so you can change add a style to it.
6110 * @param {Roo.bootstrap.Table} this
6111 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6115 * @event rowsrendered
6116 * Fires when all the rows have been rendered
6117 * @param {Roo.bootstrap.Table} this
6119 'rowsrendered' : true,
6121 * @event contextmenu
6122 * The raw contextmenu event for the entire grid.
6123 * @param {Roo.EventObject} e
6125 "contextmenu" : true,
6127 * @event rowcontextmenu
6128 * Fires when a row is right clicked
6129 * @param {Roo.bootstrap.Table} this
6130 * @param {Number} rowIndex
6131 * @param {Roo.EventObject} e
6133 "rowcontextmenu" : true,
6135 * @event cellcontextmenu
6136 * Fires when a cell is right clicked
6137 * @param {Roo.bootstrap.Table} this
6138 * @param {Number} rowIndex
6139 * @param {Number} cellIndex
6140 * @param {Roo.EventObject} e
6142 "cellcontextmenu" : true,
6144 * @event headercontextmenu
6145 * Fires when a header is right clicked
6146 * @param {Roo.bootstrap.Table} this
6147 * @param {Number} columnIndex
6148 * @param {Roo.EventObject} e
6150 "headercontextmenu" : true
6154 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6180 rowSelection : false,
6181 cellSelection : false,
6184 // Roo.Element - the tbody
6186 // Roo.Element - thead element
6189 container: false, // used by gridpanel...
6195 auto_hide_footer : false,
6197 getAutoCreate : function()
6199 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6206 if (this.scrollBody) {
6207 cfg.cls += ' table-body-fixed';
6210 cfg.cls += ' table-striped';
6214 cfg.cls += ' table-hover';
6216 if (this.bordered) {
6217 cfg.cls += ' table-bordered';
6219 if (this.condensed) {
6220 cfg.cls += ' table-condensed';
6222 if (this.responsive) {
6223 cfg.cls += ' table-responsive';
6227 cfg.cls+= ' ' +this.cls;
6230 // this lot should be simplifed...
6243 ].forEach(function(k) {
6251 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6254 if(this.store || this.cm){
6255 if(this.headerShow){
6256 cfg.cn.push(this.renderHeader());
6259 cfg.cn.push(this.renderBody());
6261 if(this.footerShow){
6262 cfg.cn.push(this.renderFooter());
6264 // where does this come from?
6265 //cfg.cls+= ' TableGrid';
6268 return { cn : [ cfg ] };
6271 initEvents : function()
6273 if(!this.store || !this.cm){
6276 if (this.selModel) {
6277 this.selModel.initEvents();
6281 //Roo.log('initEvents with ds!!!!');
6283 this.mainBody = this.el.select('tbody', true).first();
6284 this.mainHead = this.el.select('thead', true).first();
6285 this.mainFoot = this.el.select('tfoot', true).first();
6291 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6292 e.on('click', _this.sort, _this);
6295 this.mainBody.on("click", this.onClick, this);
6296 this.mainBody.on("dblclick", this.onDblClick, this);
6298 // why is this done????? = it breaks dialogs??
6299 //this.parent().el.setStyle('position', 'relative');
6303 this.footer.parentId = this.id;
6304 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6307 this.el.select('tfoot tr td').first().addClass('hide');
6312 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6315 this.store.on('load', this.onLoad, this);
6316 this.store.on('beforeload', this.onBeforeLoad, this);
6317 this.store.on('update', this.onUpdate, this);
6318 this.store.on('add', this.onAdd, this);
6319 this.store.on("clear", this.clear, this);
6321 this.el.on("contextmenu", this.onContextMenu, this);
6323 this.mainBody.on('scroll', this.onBodyScroll, this);
6325 this.cm.on("headerchange", this.onHeaderChange, this);
6327 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6331 onContextMenu : function(e, t)
6333 this.processEvent("contextmenu", e);
6336 processEvent : function(name, e)
6338 if (name != 'touchstart' ) {
6339 this.fireEvent(name, e);
6342 var t = e.getTarget();
6344 var cell = Roo.get(t);
6350 if(cell.findParent('tfoot', false, true)){
6354 if(cell.findParent('thead', false, true)){
6356 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6357 cell = Roo.get(t).findParent('th', false, true);
6359 Roo.log("failed to find th in thead?");
6360 Roo.log(e.getTarget());
6365 var cellIndex = cell.dom.cellIndex;
6367 var ename = name == 'touchstart' ? 'click' : name;
6368 this.fireEvent("header" + ename, this, cellIndex, e);
6373 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6374 cell = Roo.get(t).findParent('td', false, true);
6376 Roo.log("failed to find th in tbody?");
6377 Roo.log(e.getTarget());
6382 var row = cell.findParent('tr', false, true);
6383 var cellIndex = cell.dom.cellIndex;
6384 var rowIndex = row.dom.rowIndex - 1;
6388 this.fireEvent("row" + name, this, rowIndex, e);
6392 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6398 onMouseover : function(e, el)
6400 var cell = Roo.get(el);
6406 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6407 cell = cell.findParent('td', false, true);
6410 var row = cell.findParent('tr', false, true);
6411 var cellIndex = cell.dom.cellIndex;
6412 var rowIndex = row.dom.rowIndex - 1; // start from 0
6414 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6418 onMouseout : function(e, el)
6420 var cell = Roo.get(el);
6426 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6427 cell = cell.findParent('td', false, true);
6430 var row = cell.findParent('tr', false, true);
6431 var cellIndex = cell.dom.cellIndex;
6432 var rowIndex = row.dom.rowIndex - 1; // start from 0
6434 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6438 onClick : function(e, el)
6440 var cell = Roo.get(el);
6442 if(!cell || (!this.cellSelection && !this.rowSelection)){
6446 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6447 cell = cell.findParent('td', false, true);
6450 if(!cell || typeof(cell) == 'undefined'){
6454 var row = cell.findParent('tr', false, true);
6456 if(!row || typeof(row) == 'undefined'){
6460 var cellIndex = cell.dom.cellIndex;
6461 var rowIndex = this.getRowIndex(row);
6463 // why??? - should these not be based on SelectionModel?
6464 if(this.cellSelection){
6465 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6468 if(this.rowSelection){
6469 this.fireEvent('rowclick', this, row, rowIndex, e);
6475 onDblClick : function(e,el)
6477 var cell = Roo.get(el);
6479 if(!cell || (!this.cellSelection && !this.rowSelection)){
6483 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6484 cell = cell.findParent('td', false, true);
6487 if(!cell || typeof(cell) == 'undefined'){
6491 var row = cell.findParent('tr', false, true);
6493 if(!row || typeof(row) == 'undefined'){
6497 var cellIndex = cell.dom.cellIndex;
6498 var rowIndex = this.getRowIndex(row);
6500 if(this.cellSelection){
6501 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6504 if(this.rowSelection){
6505 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6509 sort : function(e,el)
6511 var col = Roo.get(el);
6513 if(!col.hasClass('sortable')){
6517 var sort = col.attr('sort');
6520 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6524 this.store.sortInfo = {field : sort, direction : dir};
6527 Roo.log("calling footer first");
6528 this.footer.onClick('first');
6531 this.store.load({ params : { start : 0 } });
6535 renderHeader : function()
6543 this.totalWidth = 0;
6545 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6547 var config = cm.config[i];
6551 cls : 'x-hcol-' + i,
6553 html: cm.getColumnHeader(i)
6558 if(typeof(config.sortable) != 'undefined' && config.sortable){
6560 c.html = '<i class="glyphicon"></i>' + c.html;
6563 if(typeof(config.lgHeader) != 'undefined'){
6564 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6567 if(typeof(config.mdHeader) != 'undefined'){
6568 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6571 if(typeof(config.smHeader) != 'undefined'){
6572 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6575 if(typeof(config.xsHeader) != 'undefined'){
6576 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6583 if(typeof(config.tooltip) != 'undefined'){
6584 c.tooltip = config.tooltip;
6587 if(typeof(config.colspan) != 'undefined'){
6588 c.colspan = config.colspan;
6591 if(typeof(config.hidden) != 'undefined' && config.hidden){
6592 c.style += ' display:none;';
6595 if(typeof(config.dataIndex) != 'undefined'){
6596 c.sort = config.dataIndex;
6601 if(typeof(config.align) != 'undefined' && config.align.length){
6602 c.style += ' text-align:' + config.align + ';';
6605 if(typeof(config.width) != 'undefined'){
6606 c.style += ' width:' + config.width + 'px;';
6607 this.totalWidth += config.width;
6609 this.totalWidth += 100; // assume minimum of 100 per column?
6612 if(typeof(config.cls) != 'undefined'){
6613 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6616 ['xs','sm','md','lg'].map(function(size){
6618 if(typeof(config[size]) == 'undefined'){
6622 if (!config[size]) { // 0 = hidden
6623 c.cls += ' hidden-' + size;
6627 c.cls += ' col-' + size + '-' + config[size];
6637 renderBody : function()
6647 colspan : this.cm.getColumnCount()
6657 renderFooter : function()
6667 colspan : this.cm.getColumnCount()
6681 // Roo.log('ds onload');
6686 var ds = this.store;
6688 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6689 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6690 if (_this.store.sortInfo) {
6692 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6693 e.select('i', true).addClass(['glyphicon-arrow-up']);
6696 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6697 e.select('i', true).addClass(['glyphicon-arrow-down']);
6702 var tbody = this.mainBody;
6704 if(ds.getCount() > 0){
6705 ds.data.each(function(d,rowIndex){
6706 var row = this.renderRow(cm, ds, rowIndex);
6708 tbody.createChild(row);
6712 if(row.cellObjects.length){
6713 Roo.each(row.cellObjects, function(r){
6714 _this.renderCellObject(r);
6721 var tfoot = this.el.select('tfoot', true).first();
6723 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6725 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6727 var total = this.ds.getTotalCount();
6729 if(this.footer.pageSize < total){
6730 this.mainFoot.show();
6734 Roo.each(this.el.select('tbody td', true).elements, function(e){
6735 e.on('mouseover', _this.onMouseover, _this);
6738 Roo.each(this.el.select('tbody td', true).elements, function(e){
6739 e.on('mouseout', _this.onMouseout, _this);
6741 this.fireEvent('rowsrendered', this);
6747 onUpdate : function(ds,record)
6749 this.refreshRow(record);
6753 onRemove : function(ds, record, index, isUpdate){
6754 if(isUpdate !== true){
6755 this.fireEvent("beforerowremoved", this, index, record);
6757 var bt = this.mainBody.dom;
6759 var rows = this.el.select('tbody > tr', true).elements;
6761 if(typeof(rows[index]) != 'undefined'){
6762 bt.removeChild(rows[index].dom);
6765 // if(bt.rows[index]){
6766 // bt.removeChild(bt.rows[index]);
6769 if(isUpdate !== true){
6770 //this.stripeRows(index);
6771 //this.syncRowHeights(index, index);
6773 this.fireEvent("rowremoved", this, index, record);
6777 onAdd : function(ds, records, rowIndex)
6779 //Roo.log('on Add called');
6780 // - note this does not handle multiple adding very well..
6781 var bt = this.mainBody.dom;
6782 for (var i =0 ; i < records.length;i++) {
6783 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6784 //Roo.log(records[i]);
6785 //Roo.log(this.store.getAt(rowIndex+i));
6786 this.insertRow(this.store, rowIndex + i, false);
6793 refreshRow : function(record){
6794 var ds = this.store, index;
6795 if(typeof record == 'number'){
6797 record = ds.getAt(index);
6799 index = ds.indexOf(record);
6801 this.insertRow(ds, index, true);
6803 this.onRemove(ds, record, index+1, true);
6805 //this.syncRowHeights(index, index);
6807 this.fireEvent("rowupdated", this, index, record);
6810 insertRow : function(dm, rowIndex, isUpdate){
6813 this.fireEvent("beforerowsinserted", this, rowIndex);
6815 //var s = this.getScrollState();
6816 var row = this.renderRow(this.cm, this.store, rowIndex);
6817 // insert before rowIndex..
6818 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6822 if(row.cellObjects.length){
6823 Roo.each(row.cellObjects, function(r){
6824 _this.renderCellObject(r);
6829 this.fireEvent("rowsinserted", this, rowIndex);
6830 //this.syncRowHeights(firstRow, lastRow);
6831 //this.stripeRows(firstRow);
6838 getRowDom : function(rowIndex)
6840 var rows = this.el.select('tbody > tr', true).elements;
6842 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6845 // returns the object tree for a tr..
6848 renderRow : function(cm, ds, rowIndex)
6850 var d = ds.getAt(rowIndex);
6854 cls : 'x-row-' + rowIndex,
6858 var cellObjects = [];
6860 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6861 var config = cm.config[i];
6863 var renderer = cm.getRenderer(i);
6867 if(typeof(renderer) !== 'undefined'){
6868 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6870 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6871 // and are rendered into the cells after the row is rendered - using the id for the element.
6873 if(typeof(value) === 'object'){
6883 rowIndex : rowIndex,
6888 this.fireEvent('rowclass', this, rowcfg);
6892 cls : rowcfg.rowClass + ' x-col-' + i,
6894 html: (typeof(value) === 'object') ? '' : value
6901 if(typeof(config.colspan) != 'undefined'){
6902 td.colspan = config.colspan;
6905 if(typeof(config.hidden) != 'undefined' && config.hidden){
6906 td.style += ' display:none;';
6909 if(typeof(config.align) != 'undefined' && config.align.length){
6910 td.style += ' text-align:' + config.align + ';';
6912 if(typeof(config.valign) != 'undefined' && config.valign.length){
6913 td.style += ' vertical-align:' + config.valign + ';';
6916 if(typeof(config.width) != 'undefined'){
6917 td.style += ' width:' + config.width + 'px;';
6920 if(typeof(config.cursor) != 'undefined'){
6921 td.style += ' cursor:' + config.cursor + ';';
6924 if(typeof(config.cls) != 'undefined'){
6925 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6928 ['xs','sm','md','lg'].map(function(size){
6930 if(typeof(config[size]) == 'undefined'){
6934 if (!config[size]) { // 0 = hidden
6935 td.cls += ' hidden-' + size;
6939 td.cls += ' col-' + size + '-' + config[size];
6947 row.cellObjects = cellObjects;
6955 onBeforeLoad : function()
6964 this.el.select('tbody', true).first().dom.innerHTML = '';
6967 * Show or hide a row.
6968 * @param {Number} rowIndex to show or hide
6969 * @param {Boolean} state hide
6971 setRowVisibility : function(rowIndex, state)
6973 var bt = this.mainBody.dom;
6975 var rows = this.el.select('tbody > tr', true).elements;
6977 if(typeof(rows[rowIndex]) == 'undefined'){
6980 rows[rowIndex].dom.style.display = state ? '' : 'none';
6984 getSelectionModel : function(){
6986 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6988 return this.selModel;
6991 * Render the Roo.bootstrap object from renderder
6993 renderCellObject : function(r)
6997 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6999 var t = r.cfg.render(r.container);
7002 Roo.each(r.cfg.cn, function(c){
7004 container: t.getChildContainer(),
7007 _this.renderCellObject(child);
7012 getRowIndex : function(row)
7016 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7027 * Returns the grid's underlying element = used by panel.Grid
7028 * @return {Element} The element
7030 getGridEl : function(){
7034 * Forces a resize - used by panel.Grid
7035 * @return {Element} The element
7037 autoSize : function()
7039 //var ctr = Roo.get(this.container.dom.parentElement);
7040 var ctr = Roo.get(this.el.dom);
7042 var thd = this.getGridEl().select('thead',true).first();
7043 var tbd = this.getGridEl().select('tbody', true).first();
7044 var tfd = this.getGridEl().select('tfoot', true).first();
7046 var cw = ctr.getWidth();
7050 tbd.setSize(ctr.getWidth(),
7051 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7053 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7056 cw = Math.max(cw, this.totalWidth);
7057 this.getGridEl().select('tr',true).setWidth(cw);
7058 // resize 'expandable coloumn?
7060 return; // we doe not have a view in this design..
7063 onBodyScroll: function()
7065 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7067 this.mainHead.setStyle({
7068 'position' : 'relative',
7069 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7075 var scrollHeight = this.mainBody.dom.scrollHeight;
7077 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7079 var height = this.mainBody.getHeight();
7081 if(scrollHeight - height == scrollTop) {
7083 var total = this.ds.getTotalCount();
7085 if(this.footer.cursor + this.footer.pageSize < total){
7087 this.footer.ds.load({
7089 start : this.footer.cursor + this.footer.pageSize,
7090 limit : this.footer.pageSize
7100 onHeaderChange : function()
7102 var header = this.renderHeader();
7103 var table = this.el.select('table', true).first();
7105 this.mainHead.remove();
7106 this.mainHead = table.createChild(header, this.mainBody, false);
7109 onHiddenChange : function(colModel, colIndex, hidden)
7111 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7112 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7114 this.CSS.updateRule(thSelector, "display", "");
7115 this.CSS.updateRule(tdSelector, "display", "");
7118 this.CSS.updateRule(thSelector, "display", "none");
7119 this.CSS.updateRule(tdSelector, "display", "none");
7122 this.onHeaderChange();
7126 setColumnWidth: function(col_index, width)
7128 // width = "md-2 xs-2..."
7129 if(!this.colModel.config[col_index]) {
7133 var w = width.split(" ");
7135 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7137 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7140 for(var j = 0; j < w.length; j++) {
7146 var size_cls = w[j].split("-");
7148 if(!Number.isInteger(size_cls[1] * 1)) {
7152 if(!this.colModel.config[col_index][size_cls[0]]) {
7156 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7160 h_row[0].classList.replace(
7161 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7162 "col-"+size_cls[0]+"-"+size_cls[1]
7165 for(var i = 0; i < rows.length; i++) {
7167 var size_cls = w[j].split("-");
7169 if(!Number.isInteger(size_cls[1] * 1)) {
7173 if(!this.colModel.config[col_index][size_cls[0]]) {
7177 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7181 rows[i].classList.replace(
7182 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7183 "col-"+size_cls[0]+"-"+size_cls[1]
7187 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7202 * @class Roo.bootstrap.TableCell
7203 * @extends Roo.bootstrap.Component
7204 * Bootstrap TableCell class
7205 * @cfg {String} html cell contain text
7206 * @cfg {String} cls cell class
7207 * @cfg {String} tag cell tag (td|th) default td
7208 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7209 * @cfg {String} align Aligns the content in a cell
7210 * @cfg {String} axis Categorizes cells
7211 * @cfg {String} bgcolor Specifies the background color of a cell
7212 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7213 * @cfg {Number} colspan Specifies the number of columns a cell should span
7214 * @cfg {String} headers Specifies one or more header cells a cell is related to
7215 * @cfg {Number} height Sets the height of a cell
7216 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7217 * @cfg {Number} rowspan Sets the number of rows a cell should span
7218 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7219 * @cfg {String} valign Vertical aligns the content in a cell
7220 * @cfg {Number} width Specifies the width of a cell
7223 * Create a new TableCell
7224 * @param {Object} config The config object
7227 Roo.bootstrap.TableCell = function(config){
7228 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7231 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7251 getAutoCreate : function(){
7252 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7272 cfg.align=this.align
7278 cfg.bgcolor=this.bgcolor
7281 cfg.charoff=this.charoff
7284 cfg.colspan=this.colspan
7287 cfg.headers=this.headers
7290 cfg.height=this.height
7293 cfg.nowrap=this.nowrap
7296 cfg.rowspan=this.rowspan
7299 cfg.scope=this.scope
7302 cfg.valign=this.valign
7305 cfg.width=this.width
7324 * @class Roo.bootstrap.TableRow
7325 * @extends Roo.bootstrap.Component
7326 * Bootstrap TableRow class
7327 * @cfg {String} cls row class
7328 * @cfg {String} align Aligns the content in a table row
7329 * @cfg {String} bgcolor Specifies a background color for a table row
7330 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7331 * @cfg {String} valign Vertical aligns the content in a table row
7334 * Create a new TableRow
7335 * @param {Object} config The config object
7338 Roo.bootstrap.TableRow = function(config){
7339 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7342 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7350 getAutoCreate : function(){
7351 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7361 cfg.align = this.align;
7364 cfg.bgcolor = this.bgcolor;
7367 cfg.charoff = this.charoff;
7370 cfg.valign = this.valign;
7388 * @class Roo.bootstrap.TableBody
7389 * @extends Roo.bootstrap.Component
7390 * Bootstrap TableBody class
7391 * @cfg {String} cls element class
7392 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7393 * @cfg {String} align Aligns the content inside the element
7394 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7395 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7398 * Create a new TableBody
7399 * @param {Object} config The config object
7402 Roo.bootstrap.TableBody = function(config){
7403 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7406 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7414 getAutoCreate : function(){
7415 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7429 cfg.align = this.align;
7432 cfg.charoff = this.charoff;
7435 cfg.valign = this.valign;
7442 // initEvents : function()
7449 // this.store = Roo.factory(this.store, Roo.data);
7450 // this.store.on('load', this.onLoad, this);
7452 // this.store.load();
7456 // onLoad: function ()
7458 // this.fireEvent('load', this);
7468 * Ext JS Library 1.1.1
7469 * Copyright(c) 2006-2007, Ext JS, LLC.
7471 * Originally Released Under LGPL - original licence link has changed is not relivant.
7474 * <script type="text/javascript">
7477 // as we use this in bootstrap.
7478 Roo.namespace('Roo.form');
7480 * @class Roo.form.Action
7481 * Internal Class used to handle form actions
7483 * @param {Roo.form.BasicForm} el The form element or its id
7484 * @param {Object} config Configuration options
7489 // define the action interface
7490 Roo.form.Action = function(form, options){
7492 this.options = options || {};
7495 * Client Validation Failed
7498 Roo.form.Action.CLIENT_INVALID = 'client';
7500 * Server Validation Failed
7503 Roo.form.Action.SERVER_INVALID = 'server';
7505 * Connect to Server Failed
7508 Roo.form.Action.CONNECT_FAILURE = 'connect';
7510 * Reading Data from Server Failed
7513 Roo.form.Action.LOAD_FAILURE = 'load';
7515 Roo.form.Action.prototype = {
7517 failureType : undefined,
7518 response : undefined,
7522 run : function(options){
7527 success : function(response){
7532 handleResponse : function(response){
7536 // default connection failure
7537 failure : function(response){
7539 this.response = response;
7540 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7541 this.form.afterAction(this, false);
7544 processResponse : function(response){
7545 this.response = response;
7546 if(!response.responseText){
7549 this.result = this.handleResponse(response);
7553 // utility functions used internally
7554 getUrl : function(appendParams){
7555 var url = this.options.url || this.form.url || this.form.el.dom.action;
7557 var p = this.getParams();
7559 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7565 getMethod : function(){
7566 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7569 getParams : function(){
7570 var bp = this.form.baseParams;
7571 var p = this.options.params;
7573 if(typeof p == "object"){
7574 p = Roo.urlEncode(Roo.applyIf(p, bp));
7575 }else if(typeof p == 'string' && bp){
7576 p += '&' + Roo.urlEncode(bp);
7579 p = Roo.urlEncode(bp);
7584 createCallback : function(){
7586 success: this.success,
7587 failure: this.failure,
7589 timeout: (this.form.timeout*1000),
7590 upload: this.form.fileUpload ? this.success : undefined
7595 Roo.form.Action.Submit = function(form, options){
7596 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7599 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7602 haveProgress : false,
7603 uploadComplete : false,
7605 // uploadProgress indicator.
7606 uploadProgress : function()
7608 if (!this.form.progressUrl) {
7612 if (!this.haveProgress) {
7613 Roo.MessageBox.progress("Uploading", "Uploading");
7615 if (this.uploadComplete) {
7616 Roo.MessageBox.hide();
7620 this.haveProgress = true;
7622 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7624 var c = new Roo.data.Connection();
7626 url : this.form.progressUrl,
7631 success : function(req){
7632 //console.log(data);
7636 rdata = Roo.decode(req.responseText)
7638 Roo.log("Invalid data from server..");
7642 if (!rdata || !rdata.success) {
7644 Roo.MessageBox.alert(Roo.encode(rdata));
7647 var data = rdata.data;
7649 if (this.uploadComplete) {
7650 Roo.MessageBox.hide();
7655 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7656 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7659 this.uploadProgress.defer(2000,this);
7662 failure: function(data) {
7663 Roo.log('progress url failed ');
7674 // run get Values on the form, so it syncs any secondary forms.
7675 this.form.getValues();
7677 var o = this.options;
7678 var method = this.getMethod();
7679 var isPost = method == 'POST';
7680 if(o.clientValidation === false || this.form.isValid()){
7682 if (this.form.progressUrl) {
7683 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7684 (new Date() * 1) + '' + Math.random());
7689 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7690 form:this.form.el.dom,
7691 url:this.getUrl(!isPost),
7693 params:isPost ? this.getParams() : null,
7694 isUpload: this.form.fileUpload
7697 this.uploadProgress();
7699 }else if (o.clientValidation !== false){ // client validation failed
7700 this.failureType = Roo.form.Action.CLIENT_INVALID;
7701 this.form.afterAction(this, false);
7705 success : function(response)
7707 this.uploadComplete= true;
7708 if (this.haveProgress) {
7709 Roo.MessageBox.hide();
7713 var result = this.processResponse(response);
7714 if(result === true || result.success){
7715 this.form.afterAction(this, true);
7719 this.form.markInvalid(result.errors);
7720 this.failureType = Roo.form.Action.SERVER_INVALID;
7722 this.form.afterAction(this, false);
7724 failure : function(response)
7726 this.uploadComplete= true;
7727 if (this.haveProgress) {
7728 Roo.MessageBox.hide();
7731 this.response = response;
7732 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7733 this.form.afterAction(this, false);
7736 handleResponse : function(response){
7737 if(this.form.errorReader){
7738 var rs = this.form.errorReader.read(response);
7741 for(var i = 0, len = rs.records.length; i < len; i++) {
7742 var r = rs.records[i];
7746 if(errors.length < 1){
7750 success : rs.success,
7756 ret = Roo.decode(response.responseText);
7760 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7770 Roo.form.Action.Load = function(form, options){
7771 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7772 this.reader = this.form.reader;
7775 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7780 Roo.Ajax.request(Roo.apply(
7781 this.createCallback(), {
7782 method:this.getMethod(),
7783 url:this.getUrl(false),
7784 params:this.getParams()
7788 success : function(response){
7790 var result = this.processResponse(response);
7791 if(result === true || !result.success || !result.data){
7792 this.failureType = Roo.form.Action.LOAD_FAILURE;
7793 this.form.afterAction(this, false);
7796 this.form.clearInvalid();
7797 this.form.setValues(result.data);
7798 this.form.afterAction(this, true);
7801 handleResponse : function(response){
7802 if(this.form.reader){
7803 var rs = this.form.reader.read(response);
7804 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7806 success : rs.success,
7810 return Roo.decode(response.responseText);
7814 Roo.form.Action.ACTION_TYPES = {
7815 'load' : Roo.form.Action.Load,
7816 'submit' : Roo.form.Action.Submit
7825 * @class Roo.bootstrap.Form
7826 * @extends Roo.bootstrap.Component
7827 * Bootstrap Form class
7828 * @cfg {String} method GET | POST (default POST)
7829 * @cfg {String} labelAlign top | left (default top)
7830 * @cfg {String} align left | right - for navbars
7831 * @cfg {Boolean} loadMask load mask when submit (default true)
7836 * @param {Object} config The config object
7840 Roo.bootstrap.Form = function(config){
7842 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7844 Roo.bootstrap.Form.popover.apply();
7848 * @event clientvalidation
7849 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7850 * @param {Form} this
7851 * @param {Boolean} valid true if the form has passed client-side validation
7853 clientvalidation: true,
7855 * @event beforeaction
7856 * Fires before any action is performed. Return false to cancel the action.
7857 * @param {Form} this
7858 * @param {Action} action The action to be performed
7862 * @event actionfailed
7863 * Fires when an action fails.
7864 * @param {Form} this
7865 * @param {Action} action The action that failed
7867 actionfailed : true,
7869 * @event actioncomplete
7870 * Fires when an action is completed.
7871 * @param {Form} this
7872 * @param {Action} action The action that completed
7874 actioncomplete : true
7878 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7881 * @cfg {String} method
7882 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7887 * The URL to use for form actions if one isn't supplied in the action options.
7890 * @cfg {Boolean} fileUpload
7891 * Set to true if this form is a file upload.
7895 * @cfg {Object} baseParams
7896 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7900 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7904 * @cfg {Sting} align (left|right) for navbar forms
7909 activeAction : null,
7912 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7913 * element by passing it or its id or mask the form itself by passing in true.
7916 waitMsgTarget : false,
7921 * @cfg {Boolean} errorMask (true|false) default false
7926 * @cfg {Number} maskOffset Default 100
7931 * @cfg {Boolean} maskBody
7935 getAutoCreate : function(){
7939 method : this.method || 'POST',
7940 id : this.id || Roo.id(),
7943 if (this.parent().xtype.match(/^Nav/)) {
7944 cfg.cls = 'navbar-form navbar-' + this.align;
7948 if (this.labelAlign == 'left' ) {
7949 cfg.cls += ' form-horizontal';
7955 initEvents : function()
7957 this.el.on('submit', this.onSubmit, this);
7958 // this was added as random key presses on the form where triggering form submit.
7959 this.el.on('keypress', function(e) {
7960 if (e.getCharCode() != 13) {
7963 // we might need to allow it for textareas.. and some other items.
7964 // check e.getTarget().
7966 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7970 Roo.log("keypress blocked");
7978 onSubmit : function(e){
7983 * Returns true if client-side validation on the form is successful.
7986 isValid : function(){
7987 var items = this.getItems();
7991 items.each(function(f){
7997 Roo.log('invalid field: ' + f.name);
8001 if(!target && f.el.isVisible(true)){
8007 if(this.errorMask && !valid){
8008 Roo.bootstrap.Form.popover.mask(this, target);
8015 * Returns true if any fields in this form have changed since their original load.
8018 isDirty : function(){
8020 var items = this.getItems();
8021 items.each(function(f){
8031 * Performs a predefined action (submit or load) or custom actions you define on this form.
8032 * @param {String} actionName The name of the action type
8033 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8034 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8035 * accept other config options):
8037 Property Type Description
8038 ---------------- --------------- ----------------------------------------------------------------------------------
8039 url String The url for the action (defaults to the form's url)
8040 method String The form method to use (defaults to the form's method, or POST if not defined)
8041 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8042 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8043 validate the form on the client (defaults to false)
8045 * @return {BasicForm} this
8047 doAction : function(action, options){
8048 if(typeof action == 'string'){
8049 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8051 if(this.fireEvent('beforeaction', this, action) !== false){
8052 this.beforeAction(action);
8053 action.run.defer(100, action);
8059 beforeAction : function(action){
8060 var o = action.options;
8065 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8067 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8070 // not really supported yet.. ??
8072 //if(this.waitMsgTarget === true){
8073 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8074 //}else if(this.waitMsgTarget){
8075 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8076 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8078 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8084 afterAction : function(action, success){
8085 this.activeAction = null;
8086 var o = action.options;
8091 Roo.get(document.body).unmask();
8097 //if(this.waitMsgTarget === true){
8098 // this.el.unmask();
8099 //}else if(this.waitMsgTarget){
8100 // this.waitMsgTarget.unmask();
8102 // Roo.MessageBox.updateProgress(1);
8103 // Roo.MessageBox.hide();
8110 Roo.callback(o.success, o.scope, [this, action]);
8111 this.fireEvent('actioncomplete', this, action);
8115 // failure condition..
8116 // we have a scenario where updates need confirming.
8117 // eg. if a locking scenario exists..
8118 // we look for { errors : { needs_confirm : true }} in the response.
8120 (typeof(action.result) != 'undefined') &&
8121 (typeof(action.result.errors) != 'undefined') &&
8122 (typeof(action.result.errors.needs_confirm) != 'undefined')
8125 Roo.log("not supported yet");
8128 Roo.MessageBox.confirm(
8129 "Change requires confirmation",
8130 action.result.errorMsg,
8135 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8145 Roo.callback(o.failure, o.scope, [this, action]);
8146 // show an error message if no failed handler is set..
8147 if (!this.hasListener('actionfailed')) {
8148 Roo.log("need to add dialog support");
8150 Roo.MessageBox.alert("Error",
8151 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8152 action.result.errorMsg :
8153 "Saving Failed, please check your entries or try again"
8158 this.fireEvent('actionfailed', this, action);
8163 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8164 * @param {String} id The value to search for
8167 findField : function(id){
8168 var items = this.getItems();
8169 var field = items.get(id);
8171 items.each(function(f){
8172 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8179 return field || null;
8182 * Mark fields in this form invalid in bulk.
8183 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8184 * @return {BasicForm} this
8186 markInvalid : function(errors){
8187 if(errors instanceof Array){
8188 for(var i = 0, len = errors.length; i < len; i++){
8189 var fieldError = errors[i];
8190 var f = this.findField(fieldError.id);
8192 f.markInvalid(fieldError.msg);
8198 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8199 field.markInvalid(errors[id]);
8203 //Roo.each(this.childForms || [], function (f) {
8204 // f.markInvalid(errors);
8211 * Set values for fields in this form in bulk.
8212 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8213 * @return {BasicForm} this
8215 setValues : function(values){
8216 if(values instanceof Array){ // array of objects
8217 for(var i = 0, len = values.length; i < len; i++){
8219 var f = this.findField(v.id);
8221 f.setValue(v.value);
8222 if(this.trackResetOnLoad){
8223 f.originalValue = f.getValue();
8227 }else{ // object hash
8230 if(typeof values[id] != 'function' && (field = this.findField(id))){
8232 if (field.setFromData &&
8234 field.displayField &&
8235 // combos' with local stores can
8236 // be queried via setValue()
8237 // to set their value..
8238 (field.store && !field.store.isLocal)
8242 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8243 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8244 field.setFromData(sd);
8246 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8248 field.setFromData(values);
8251 field.setValue(values[id]);
8255 if(this.trackResetOnLoad){
8256 field.originalValue = field.getValue();
8262 //Roo.each(this.childForms || [], function (f) {
8263 // f.setValues(values);
8270 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8271 * they are returned as an array.
8272 * @param {Boolean} asString
8275 getValues : function(asString){
8276 //if (this.childForms) {
8277 // copy values from the child forms
8278 // Roo.each(this.childForms, function (f) {
8279 // this.setValues(f.getValues());
8285 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8286 if(asString === true){
8289 return Roo.urlDecode(fs);
8293 * Returns the fields in this form as an object with key/value pairs.
8294 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8297 getFieldValues : function(with_hidden)
8299 var items = this.getItems();
8301 items.each(function(f){
8307 var v = f.getValue();
8309 if (f.inputType =='radio') {
8310 if (typeof(ret[f.getName()]) == 'undefined') {
8311 ret[f.getName()] = ''; // empty..
8314 if (!f.el.dom.checked) {
8322 if(f.xtype == 'MoneyField'){
8323 ret[f.currencyName] = f.getCurrency();
8326 // not sure if this supported any more..
8327 if ((typeof(v) == 'object') && f.getRawValue) {
8328 v = f.getRawValue() ; // dates..
8330 // combo boxes where name != hiddenName...
8331 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8332 ret[f.name] = f.getRawValue();
8334 ret[f.getName()] = v;
8341 * Clears all invalid messages in this form.
8342 * @return {BasicForm} this
8344 clearInvalid : function(){
8345 var items = this.getItems();
8347 items.each(function(f){
8356 * @return {BasicForm} this
8359 var items = this.getItems();
8360 items.each(function(f){
8364 Roo.each(this.childForms || [], function (f) {
8372 getItems : function()
8374 var r=new Roo.util.MixedCollection(false, function(o){
8375 return o.id || (o.id = Roo.id());
8377 var iter = function(el) {
8384 Roo.each(el.items,function(e) {
8393 hideFields : function(items)
8395 Roo.each(items, function(i){
8397 var f = this.findField(i);
8408 showFields : function(items)
8410 Roo.each(items, function(i){
8412 var f = this.findField(i);
8425 Roo.apply(Roo.bootstrap.Form, {
8452 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8453 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8454 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8455 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8458 this.maskEl.top.enableDisplayMode("block");
8459 this.maskEl.left.enableDisplayMode("block");
8460 this.maskEl.bottom.enableDisplayMode("block");
8461 this.maskEl.right.enableDisplayMode("block");
8463 this.toolTip = new Roo.bootstrap.Tooltip({
8464 cls : 'roo-form-error-popover',
8466 'left' : ['r-l', [-2,0], 'right'],
8467 'right' : ['l-r', [2,0], 'left'],
8468 'bottom' : ['tl-bl', [0,2], 'top'],
8469 'top' : [ 'bl-tl', [0,-2], 'bottom']
8473 this.toolTip.render(Roo.get(document.body));
8475 this.toolTip.el.enableDisplayMode("block");
8477 Roo.get(document.body).on('click', function(){
8481 Roo.get(document.body).on('touchstart', function(){
8485 this.isApplied = true
8488 mask : function(form, target)
8492 this.target = target;
8494 if(!this.form.errorMask || !target.el){
8498 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8500 Roo.log(scrollable);
8502 var ot = this.target.el.calcOffsetsTo(scrollable);
8504 var scrollTo = ot[1] - this.form.maskOffset;
8506 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8508 scrollable.scrollTo('top', scrollTo);
8510 var box = this.target.el.getBox();
8512 var zIndex = Roo.bootstrap.Modal.zIndex++;
8515 this.maskEl.top.setStyle('position', 'absolute');
8516 this.maskEl.top.setStyle('z-index', zIndex);
8517 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8518 this.maskEl.top.setLeft(0);
8519 this.maskEl.top.setTop(0);
8520 this.maskEl.top.show();
8522 this.maskEl.left.setStyle('position', 'absolute');
8523 this.maskEl.left.setStyle('z-index', zIndex);
8524 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8525 this.maskEl.left.setLeft(0);
8526 this.maskEl.left.setTop(box.y - this.padding);
8527 this.maskEl.left.show();
8529 this.maskEl.bottom.setStyle('position', 'absolute');
8530 this.maskEl.bottom.setStyle('z-index', zIndex);
8531 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8532 this.maskEl.bottom.setLeft(0);
8533 this.maskEl.bottom.setTop(box.bottom + this.padding);
8534 this.maskEl.bottom.show();
8536 this.maskEl.right.setStyle('position', 'absolute');
8537 this.maskEl.right.setStyle('z-index', zIndex);
8538 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8539 this.maskEl.right.setLeft(box.right + this.padding);
8540 this.maskEl.right.setTop(box.y - this.padding);
8541 this.maskEl.right.show();
8543 this.toolTip.bindEl = this.target.el;
8545 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8547 var tip = this.target.blankText;
8549 if(this.target.getValue() !== '' ) {
8551 if (this.target.invalidText.length) {
8552 tip = this.target.invalidText;
8553 } else if (this.target.regexText.length){
8554 tip = this.target.regexText;
8558 this.toolTip.show(tip);
8560 this.intervalID = window.setInterval(function() {
8561 Roo.bootstrap.Form.popover.unmask();
8564 window.onwheel = function(){ return false;};
8566 (function(){ this.isMasked = true; }).defer(500, this);
8572 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8576 this.maskEl.top.setStyle('position', 'absolute');
8577 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8578 this.maskEl.top.hide();
8580 this.maskEl.left.setStyle('position', 'absolute');
8581 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8582 this.maskEl.left.hide();
8584 this.maskEl.bottom.setStyle('position', 'absolute');
8585 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8586 this.maskEl.bottom.hide();
8588 this.maskEl.right.setStyle('position', 'absolute');
8589 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8590 this.maskEl.right.hide();
8592 this.toolTip.hide();
8594 this.toolTip.el.hide();
8596 window.onwheel = function(){ return true;};
8598 if(this.intervalID){
8599 window.clearInterval(this.intervalID);
8600 this.intervalID = false;
8603 this.isMasked = false;
8613 * Ext JS Library 1.1.1
8614 * Copyright(c) 2006-2007, Ext JS, LLC.
8616 * Originally Released Under LGPL - original licence link has changed is not relivant.
8619 * <script type="text/javascript">
8622 * @class Roo.form.VTypes
8623 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8626 Roo.form.VTypes = function(){
8627 // closure these in so they are only created once.
8628 var alpha = /^[a-zA-Z_]+$/;
8629 var alphanum = /^[a-zA-Z0-9_]+$/;
8630 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8631 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8633 // All these messages and functions are configurable
8636 * The function used to validate email addresses
8637 * @param {String} value The email address
8639 'email' : function(v){
8640 return email.test(v);
8643 * The error text to display when the email validation function returns false
8646 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8648 * The keystroke filter mask to be applied on email input
8651 'emailMask' : /[a-z0-9_\.\-@]/i,
8654 * The function used to validate URLs
8655 * @param {String} value The URL
8657 'url' : function(v){
8661 * The error text to display when the url validation function returns false
8664 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8667 * The function used to validate alpha values
8668 * @param {String} value The value
8670 'alpha' : function(v){
8671 return alpha.test(v);
8674 * The error text to display when the alpha validation function returns false
8677 'alphaText' : 'This field should only contain letters and _',
8679 * The keystroke filter mask to be applied on alpha input
8682 'alphaMask' : /[a-z_]/i,
8685 * The function used to validate alphanumeric values
8686 * @param {String} value The value
8688 'alphanum' : function(v){
8689 return alphanum.test(v);
8692 * The error text to display when the alphanumeric validation function returns false
8695 'alphanumText' : 'This field should only contain letters, numbers and _',
8697 * The keystroke filter mask to be applied on alphanumeric input
8700 'alphanumMask' : /[a-z0-9_]/i
8710 * @class Roo.bootstrap.Input
8711 * @extends Roo.bootstrap.Component
8712 * Bootstrap Input class
8713 * @cfg {Boolean} disabled is it disabled
8714 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8715 * @cfg {String} name name of the input
8716 * @cfg {string} fieldLabel - the label associated
8717 * @cfg {string} placeholder - placeholder to put in text.
8718 * @cfg {string} before - input group add on before
8719 * @cfg {string} after - input group add on after
8720 * @cfg {string} size - (lg|sm) or leave empty..
8721 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8722 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8723 * @cfg {Number} md colspan out of 12 for computer-sized screens
8724 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8725 * @cfg {string} value default value of the input
8726 * @cfg {Number} labelWidth set the width of label
8727 * @cfg {Number} labellg set the width of label (1-12)
8728 * @cfg {Number} labelmd set the width of label (1-12)
8729 * @cfg {Number} labelsm set the width of label (1-12)
8730 * @cfg {Number} labelxs set the width of label (1-12)
8731 * @cfg {String} labelAlign (top|left)
8732 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8733 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8734 * @cfg {String} indicatorpos (left|right) default left
8735 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8736 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8738 * @cfg {String} align (left|center|right) Default left
8739 * @cfg {Boolean} forceFeedback (true|false) Default false
8742 * Create a new Input
8743 * @param {Object} config The config object
8746 Roo.bootstrap.Input = function(config){
8748 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8753 * Fires when this field receives input focus.
8754 * @param {Roo.form.Field} this
8759 * Fires when this field loses input focus.
8760 * @param {Roo.form.Field} this
8765 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8766 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8767 * @param {Roo.form.Field} this
8768 * @param {Roo.EventObject} e The event object
8773 * Fires just before the field blurs if the field value has changed.
8774 * @param {Roo.form.Field} this
8775 * @param {Mixed} newValue The new value
8776 * @param {Mixed} oldValue The original value
8781 * Fires after the field has been marked as invalid.
8782 * @param {Roo.form.Field} this
8783 * @param {String} msg The validation message
8788 * Fires after the field has been validated with no errors.
8789 * @param {Roo.form.Field} this
8794 * Fires after the key up
8795 * @param {Roo.form.Field} this
8796 * @param {Roo.EventObject} e The event Object
8802 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8804 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8805 automatic validation (defaults to "keyup").
8807 validationEvent : "keyup",
8809 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8811 validateOnBlur : true,
8813 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8815 validationDelay : 250,
8817 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8819 focusClass : "x-form-focus", // not needed???
8823 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8825 invalidClass : "has-warning",
8828 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8830 validClass : "has-success",
8833 * @cfg {Boolean} hasFeedback (true|false) default true
8838 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8840 invalidFeedbackClass : "glyphicon-warning-sign",
8843 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8845 validFeedbackClass : "glyphicon-ok",
8848 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8850 selectOnFocus : false,
8853 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8857 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8862 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8864 disableKeyFilter : false,
8867 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8871 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8875 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8877 blankText : "Please complete this mandatory field",
8880 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8884 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8886 maxLength : Number.MAX_VALUE,
8888 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8890 minLengthText : "The minimum length for this field is {0}",
8892 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8894 maxLengthText : "The maximum length for this field is {0}",
8898 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8899 * If available, this function will be called only after the basic validators all return true, and will be passed the
8900 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8904 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8905 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8906 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8910 * @cfg {String} regexText -- Depricated - use Invalid Text
8915 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8921 autocomplete: false,
8940 formatedValue : false,
8941 forceFeedback : false,
8943 indicatorpos : 'left',
8953 parentLabelAlign : function()
8956 while (parent.parent()) {
8957 parent = parent.parent();
8958 if (typeof(parent.labelAlign) !='undefined') {
8959 return parent.labelAlign;
8966 getAutoCreate : function()
8968 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8974 if(this.inputType != 'hidden'){
8975 cfg.cls = 'form-group' //input-group
8981 type : this.inputType,
8983 cls : 'form-control',
8984 placeholder : this.placeholder || '',
8985 autocomplete : this.autocomplete || 'new-password'
8988 if(this.capture.length){
8989 input.capture = this.capture;
8992 if(this.accept.length){
8993 input.accept = this.accept + "/*";
8997 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9000 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9001 input.maxLength = this.maxLength;
9004 if (this.disabled) {
9005 input.disabled=true;
9008 if (this.readOnly) {
9009 input.readonly=true;
9013 input.name = this.name;
9017 input.cls += ' input-' + this.size;
9021 ['xs','sm','md','lg'].map(function(size){
9022 if (settings[size]) {
9023 cfg.cls += ' col-' + size + '-' + settings[size];
9027 var inputblock = input;
9031 cls: 'glyphicon form-control-feedback'
9034 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9037 cls : 'has-feedback',
9045 if (this.before || this.after) {
9048 cls : 'input-group',
9052 if (this.before && typeof(this.before) == 'string') {
9054 inputblock.cn.push({
9056 cls : 'roo-input-before input-group-addon',
9060 if (this.before && typeof(this.before) == 'object') {
9061 this.before = Roo.factory(this.before);
9063 inputblock.cn.push({
9065 cls : 'roo-input-before input-group-' +
9066 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9070 inputblock.cn.push(input);
9072 if (this.after && typeof(this.after) == 'string') {
9073 inputblock.cn.push({
9075 cls : 'roo-input-after input-group-addon',
9079 if (this.after && typeof(this.after) == 'object') {
9080 this.after = Roo.factory(this.after);
9082 inputblock.cn.push({
9084 cls : 'roo-input-after input-group-' +
9085 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9089 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9090 inputblock.cls += ' has-feedback';
9091 inputblock.cn.push(feedback);
9095 if (align ==='left' && this.fieldLabel.length) {
9097 cfg.cls += ' roo-form-group-label-left';
9102 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9103 tooltip : 'This field is required'
9108 cls : 'control-label',
9109 html : this.fieldLabel
9120 var labelCfg = cfg.cn[1];
9121 var contentCfg = cfg.cn[2];
9123 if(this.indicatorpos == 'right'){
9128 cls : 'control-label',
9132 html : this.fieldLabel
9136 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9137 tooltip : 'This field is required'
9150 labelCfg = cfg.cn[0];
9151 contentCfg = cfg.cn[1];
9155 if(this.labelWidth > 12){
9156 labelCfg.style = "width: " + this.labelWidth + 'px';
9159 if(this.labelWidth < 13 && this.labelmd == 0){
9160 this.labelmd = this.labelWidth;
9163 if(this.labellg > 0){
9164 labelCfg.cls += ' col-lg-' + this.labellg;
9165 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9168 if(this.labelmd > 0){
9169 labelCfg.cls += ' col-md-' + this.labelmd;
9170 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9173 if(this.labelsm > 0){
9174 labelCfg.cls += ' col-sm-' + this.labelsm;
9175 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9178 if(this.labelxs > 0){
9179 labelCfg.cls += ' col-xs-' + this.labelxs;
9180 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9184 } else if ( this.fieldLabel.length) {
9189 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9190 tooltip : 'This field is required'
9194 //cls : 'input-group-addon',
9195 html : this.fieldLabel
9203 if(this.indicatorpos == 'right'){
9208 //cls : 'input-group-addon',
9209 html : this.fieldLabel
9214 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9215 tooltip : 'This field is required'
9235 if (this.parentType === 'Navbar' && this.parent().bar) {
9236 cfg.cls += ' navbar-form';
9239 if (this.parentType === 'NavGroup') {
9240 cfg.cls += ' navbar-form';
9248 * return the real input element.
9250 inputEl: function ()
9252 return this.el.select('input.form-control',true).first();
9255 tooltipEl : function()
9257 return this.inputEl();
9260 indicatorEl : function()
9262 var indicator = this.el.select('i.roo-required-indicator',true).first();
9272 setDisabled : function(v)
9274 var i = this.inputEl().dom;
9276 i.removeAttribute('disabled');
9280 i.setAttribute('disabled','true');
9282 initEvents : function()
9285 this.inputEl().on("keydown" , this.fireKey, this);
9286 this.inputEl().on("focus", this.onFocus, this);
9287 this.inputEl().on("blur", this.onBlur, this);
9289 this.inputEl().relayEvent('keyup', this);
9291 this.indicator = this.indicatorEl();
9294 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9297 // reference to original value for reset
9298 this.originalValue = this.getValue();
9299 //Roo.form.TextField.superclass.initEvents.call(this);
9300 if(this.validationEvent == 'keyup'){
9301 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9302 this.inputEl().on('keyup', this.filterValidation, this);
9304 else if(this.validationEvent !== false){
9305 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9308 if(this.selectOnFocus){
9309 this.on("focus", this.preFocus, this);
9312 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9313 this.inputEl().on("keypress", this.filterKeys, this);
9315 this.inputEl().relayEvent('keypress', this);
9318 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9319 this.el.on("click", this.autoSize, this);
9322 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9323 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9326 if (typeof(this.before) == 'object') {
9327 this.before.render(this.el.select('.roo-input-before',true).first());
9329 if (typeof(this.after) == 'object') {
9330 this.after.render(this.el.select('.roo-input-after',true).first());
9333 this.inputEl().on('change', this.onChange, this);
9336 filterValidation : function(e){
9337 if(!e.isNavKeyPress()){
9338 this.validationTask.delay(this.validationDelay);
9342 * Validates the field value
9343 * @return {Boolean} True if the value is valid, else false
9345 validate : function(){
9346 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9347 if(this.disabled || this.validateValue(this.getRawValue())){
9358 * Validates a value according to the field's validation rules and marks the field as invalid
9359 * if the validation fails
9360 * @param {Mixed} value The value to validate
9361 * @return {Boolean} True if the value is valid, else false
9363 validateValue : function(value)
9365 if(this.getVisibilityEl().hasClass('hidden')){
9369 if(value.length < 1) { // if it's blank
9370 if(this.allowBlank){
9376 if(value.length < this.minLength){
9379 if(value.length > this.maxLength){
9383 var vt = Roo.form.VTypes;
9384 if(!vt[this.vtype](value, this)){
9388 if(typeof this.validator == "function"){
9389 var msg = this.validator(value);
9393 if (typeof(msg) == 'string') {
9394 this.invalidText = msg;
9398 if(this.regex && !this.regex.test(value)){
9406 fireKey : function(e){
9407 //Roo.log('field ' + e.getKey());
9408 if(e.isNavKeyPress()){
9409 this.fireEvent("specialkey", this, e);
9412 focus : function (selectText){
9414 this.inputEl().focus();
9415 if(selectText === true){
9416 this.inputEl().dom.select();
9422 onFocus : function(){
9423 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9424 // this.el.addClass(this.focusClass);
9427 this.hasFocus = true;
9428 this.startValue = this.getValue();
9429 this.fireEvent("focus", this);
9433 beforeBlur : Roo.emptyFn,
9437 onBlur : function(){
9439 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9440 //this.el.removeClass(this.focusClass);
9442 this.hasFocus = false;
9443 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9446 var v = this.getValue();
9447 if(String(v) !== String(this.startValue)){
9448 this.fireEvent('change', this, v, this.startValue);
9450 this.fireEvent("blur", this);
9453 onChange : function(e)
9455 var v = this.getValue();
9456 if(String(v) !== String(this.startValue)){
9457 this.fireEvent('change', this, v, this.startValue);
9463 * Resets the current field value to the originally loaded value and clears any validation messages
9466 this.setValue(this.originalValue);
9470 * Returns the name of the field
9471 * @return {Mixed} name The name field
9473 getName: function(){
9477 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9478 * @return {Mixed} value The field value
9480 getValue : function(){
9482 var v = this.inputEl().getValue();
9487 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9488 * @return {Mixed} value The field value
9490 getRawValue : function(){
9491 var v = this.inputEl().getValue();
9497 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9498 * @param {Mixed} value The value to set
9500 setRawValue : function(v){
9501 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9504 selectText : function(start, end){
9505 var v = this.getRawValue();
9507 start = start === undefined ? 0 : start;
9508 end = end === undefined ? v.length : end;
9509 var d = this.inputEl().dom;
9510 if(d.setSelectionRange){
9511 d.setSelectionRange(start, end);
9512 }else if(d.createTextRange){
9513 var range = d.createTextRange();
9514 range.moveStart("character", start);
9515 range.moveEnd("character", v.length-end);
9522 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9523 * @param {Mixed} value The value to set
9525 setValue : function(v){
9528 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9534 processValue : function(value){
9535 if(this.stripCharsRe){
9536 var newValue = value.replace(this.stripCharsRe, '');
9537 if(newValue !== value){
9538 this.setRawValue(newValue);
9545 preFocus : function(){
9547 if(this.selectOnFocus){
9548 this.inputEl().dom.select();
9551 filterKeys : function(e){
9553 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9556 var c = e.getCharCode(), cc = String.fromCharCode(c);
9557 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9560 if(!this.maskRe.test(cc)){
9565 * Clear any invalid styles/messages for this field
9567 clearInvalid : function(){
9569 if(!this.el || this.preventMark){ // not rendered
9574 this.el.removeClass(this.invalidClass);
9576 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9578 var feedback = this.el.select('.form-control-feedback', true).first();
9581 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9587 this.indicator.removeClass('visible');
9588 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9591 this.fireEvent('valid', this);
9595 * Mark this field as valid
9597 markValid : function()
9599 if(!this.el || this.preventMark){ // not rendered...
9603 this.el.removeClass([this.invalidClass, this.validClass]);
9605 var feedback = this.el.select('.form-control-feedback', true).first();
9608 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9612 this.indicator.removeClass('visible');
9613 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9620 if(this.allowBlank && !this.getRawValue().length){
9624 this.el.addClass(this.validClass);
9626 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9628 var feedback = this.el.select('.form-control-feedback', true).first();
9631 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9632 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9637 this.fireEvent('valid', this);
9641 * Mark this field as invalid
9642 * @param {String} msg The validation message
9644 markInvalid : function(msg)
9646 if(!this.el || this.preventMark){ // not rendered
9650 this.el.removeClass([this.invalidClass, this.validClass]);
9652 var feedback = this.el.select('.form-control-feedback', true).first();
9655 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9662 if(this.allowBlank && !this.getRawValue().length){
9667 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9668 this.indicator.addClass('visible');
9671 this.el.addClass(this.invalidClass);
9673 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9675 var feedback = this.el.select('.form-control-feedback', true).first();
9678 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9680 if(this.getValue().length || this.forceFeedback){
9681 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9688 this.fireEvent('invalid', this, msg);
9691 SafariOnKeyDown : function(event)
9693 // this is a workaround for a password hang bug on chrome/ webkit.
9694 if (this.inputEl().dom.type != 'password') {
9698 var isSelectAll = false;
9700 if(this.inputEl().dom.selectionEnd > 0){
9701 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9703 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9704 event.preventDefault();
9709 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9711 event.preventDefault();
9712 // this is very hacky as keydown always get's upper case.
9714 var cc = String.fromCharCode(event.getCharCode());
9715 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9719 adjustWidth : function(tag, w){
9720 tag = tag.toLowerCase();
9721 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9722 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9726 if(tag == 'textarea'){
9729 }else if(Roo.isOpera){
9733 if(tag == 'textarea'){
9741 setFieldLabel : function(v)
9748 var ar = this.el.select('label > span',true);
9750 if (ar.elements.length) {
9751 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9752 this.fieldLabel = v;
9756 var br = this.el.select('label',true);
9758 if(br.elements.length) {
9759 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9760 this.fieldLabel = v;
9764 Roo.log('Cannot Found any of label > span || label in input');
9768 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9769 this.fieldLabel = v;
9784 * @class Roo.bootstrap.TextArea
9785 * @extends Roo.bootstrap.Input
9786 * Bootstrap TextArea class
9787 * @cfg {Number} cols Specifies the visible width of a text area
9788 * @cfg {Number} rows Specifies the visible number of lines in a text area
9789 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9790 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9791 * @cfg {string} html text
9794 * Create a new TextArea
9795 * @param {Object} config The config object
9798 Roo.bootstrap.TextArea = function(config){
9799 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9803 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9813 getAutoCreate : function(){
9815 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9821 if(this.inputType != 'hidden'){
9822 cfg.cls = 'form-group' //input-group
9830 value : this.value || '',
9831 html: this.html || '',
9832 cls : 'form-control',
9833 placeholder : this.placeholder || ''
9837 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9838 input.maxLength = this.maxLength;
9842 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9846 input.cols = this.cols;
9849 if (this.readOnly) {
9850 input.readonly = true;
9854 input.name = this.name;
9858 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9862 ['xs','sm','md','lg'].map(function(size){
9863 if (settings[size]) {
9864 cfg.cls += ' col-' + size + '-' + settings[size];
9868 var inputblock = input;
9870 if(this.hasFeedback && !this.allowBlank){
9874 cls: 'glyphicon form-control-feedback'
9878 cls : 'has-feedback',
9887 if (this.before || this.after) {
9890 cls : 'input-group',
9894 inputblock.cn.push({
9896 cls : 'input-group-addon',
9901 inputblock.cn.push(input);
9903 if(this.hasFeedback && !this.allowBlank){
9904 inputblock.cls += ' has-feedback';
9905 inputblock.cn.push(feedback);
9909 inputblock.cn.push({
9911 cls : 'input-group-addon',
9918 if (align ==='left' && this.fieldLabel.length) {
9923 cls : 'control-label',
9924 html : this.fieldLabel
9935 if(this.labelWidth > 12){
9936 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9939 if(this.labelWidth < 13 && this.labelmd == 0){
9940 this.labelmd = this.labelWidth;
9943 if(this.labellg > 0){
9944 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9945 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9948 if(this.labelmd > 0){
9949 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9950 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9953 if(this.labelsm > 0){
9954 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9955 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9958 if(this.labelxs > 0){
9959 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9960 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9963 } else if ( this.fieldLabel.length) {
9968 //cls : 'input-group-addon',
9969 html : this.fieldLabel
9987 if (this.disabled) {
9988 input.disabled=true;
9995 * return the real textarea element.
9997 inputEl: function ()
9999 return this.el.select('textarea.form-control',true).first();
10003 * Clear any invalid styles/messages for this field
10005 clearInvalid : function()
10008 if(!this.el || this.preventMark){ // not rendered
10012 var label = this.el.select('label', true).first();
10013 var icon = this.el.select('i.fa-star', true).first();
10019 this.el.removeClass(this.invalidClass);
10021 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10023 var feedback = this.el.select('.form-control-feedback', true).first();
10026 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10031 this.fireEvent('valid', this);
10035 * Mark this field as valid
10037 markValid : function()
10039 if(!this.el || this.preventMark){ // not rendered
10043 this.el.removeClass([this.invalidClass, this.validClass]);
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]);
10051 if(this.disabled || this.allowBlank){
10055 var label = this.el.select('label', true).first();
10056 var icon = this.el.select('i.fa-star', true).first();
10062 this.el.addClass(this.validClass);
10064 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10066 var feedback = this.el.select('.form-control-feedback', true).first();
10069 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10070 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10075 this.fireEvent('valid', this);
10079 * Mark this field as invalid
10080 * @param {String} msg The validation message
10082 markInvalid : function(msg)
10084 if(!this.el || this.preventMark){ // not rendered
10088 this.el.removeClass([this.invalidClass, this.validClass]);
10090 var feedback = this.el.select('.form-control-feedback', true).first();
10093 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10096 if(this.disabled || this.allowBlank){
10100 var label = this.el.select('label', true).first();
10101 var icon = this.el.select('i.fa-star', true).first();
10103 if(!this.getValue().length && label && !icon){
10104 this.el.createChild({
10106 cls : 'text-danger fa fa-lg fa-star',
10107 tooltip : 'This field is required',
10108 style : 'margin-right:5px;'
10112 this.el.addClass(this.invalidClass);
10114 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10116 var feedback = this.el.select('.form-control-feedback', true).first();
10119 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10121 if(this.getValue().length || this.forceFeedback){
10122 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10129 this.fireEvent('invalid', this, msg);
10137 * trigger field - base class for combo..
10142 * @class Roo.bootstrap.TriggerField
10143 * @extends Roo.bootstrap.Input
10144 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10145 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10146 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10147 * for which you can provide a custom implementation. For example:
10149 var trigger = new Roo.bootstrap.TriggerField();
10150 trigger.onTriggerClick = myTriggerFn;
10151 trigger.applyTo('my-field');
10154 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10155 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10156 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10157 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10158 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10161 * Create a new TriggerField.
10162 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10163 * to the base TextField)
10165 Roo.bootstrap.TriggerField = function(config){
10166 this.mimicing = false;
10167 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10170 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10172 * @cfg {String} triggerClass A CSS class to apply to the trigger
10175 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10180 * @cfg {Boolean} removable (true|false) special filter default false
10184 /** @cfg {Boolean} grow @hide */
10185 /** @cfg {Number} growMin @hide */
10186 /** @cfg {Number} growMax @hide */
10192 autoSize: Roo.emptyFn,
10196 deferHeight : true,
10199 actionMode : 'wrap',
10204 getAutoCreate : function(){
10206 var align = this.labelAlign || this.parentLabelAlign();
10211 cls: 'form-group' //input-group
10218 type : this.inputType,
10219 cls : 'form-control',
10220 autocomplete: 'new-password',
10221 placeholder : this.placeholder || ''
10225 input.name = this.name;
10228 input.cls += ' input-' + this.size;
10231 if (this.disabled) {
10232 input.disabled=true;
10235 var inputblock = input;
10237 if(this.hasFeedback && !this.allowBlank){
10241 cls: 'glyphicon form-control-feedback'
10244 if(this.removable && !this.editable && !this.tickable){
10246 cls : 'has-feedback',
10252 cls : 'roo-combo-removable-btn close'
10259 cls : 'has-feedback',
10268 if(this.removable && !this.editable && !this.tickable){
10270 cls : 'roo-removable',
10276 cls : 'roo-combo-removable-btn close'
10283 if (this.before || this.after) {
10286 cls : 'input-group',
10290 inputblock.cn.push({
10292 cls : 'input-group-addon',
10297 inputblock.cn.push(input);
10299 if(this.hasFeedback && !this.allowBlank){
10300 inputblock.cls += ' has-feedback';
10301 inputblock.cn.push(feedback);
10305 inputblock.cn.push({
10307 cls : 'input-group-addon',
10320 cls: 'form-hidden-field'
10334 cls: 'form-hidden-field'
10338 cls: 'roo-select2-choices',
10342 cls: 'roo-select2-search-field',
10355 cls: 'roo-select2-container input-group',
10360 // cls: 'typeahead typeahead-long dropdown-menu',
10361 // style: 'display:none'
10366 if(!this.multiple && this.showToggleBtn){
10372 if (this.caret != false) {
10375 cls: 'fa fa-' + this.caret
10382 cls : 'input-group-addon btn dropdown-toggle',
10387 cls: 'combobox-clear',
10401 combobox.cls += ' roo-select2-container-multi';
10404 if (align ==='left' && this.fieldLabel.length) {
10406 cfg.cls += ' roo-form-group-label-left';
10411 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10412 tooltip : 'This field is required'
10417 cls : 'control-label',
10418 html : this.fieldLabel
10430 var labelCfg = cfg.cn[1];
10431 var contentCfg = cfg.cn[2];
10433 if(this.indicatorpos == 'right'){
10438 cls : 'control-label',
10442 html : this.fieldLabel
10446 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10447 tooltip : 'This field is required'
10460 labelCfg = cfg.cn[0];
10461 contentCfg = cfg.cn[1];
10464 if(this.labelWidth > 12){
10465 labelCfg.style = "width: " + this.labelWidth + 'px';
10468 if(this.labelWidth < 13 && this.labelmd == 0){
10469 this.labelmd = this.labelWidth;
10472 if(this.labellg > 0){
10473 labelCfg.cls += ' col-lg-' + this.labellg;
10474 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10477 if(this.labelmd > 0){
10478 labelCfg.cls += ' col-md-' + this.labelmd;
10479 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10482 if(this.labelsm > 0){
10483 labelCfg.cls += ' col-sm-' + this.labelsm;
10484 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10487 if(this.labelxs > 0){
10488 labelCfg.cls += ' col-xs-' + this.labelxs;
10489 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10492 } else if ( this.fieldLabel.length) {
10493 // Roo.log(" label");
10497 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10498 tooltip : 'This field is required'
10502 //cls : 'input-group-addon',
10503 html : this.fieldLabel
10511 if(this.indicatorpos == 'right'){
10519 html : this.fieldLabel
10523 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10524 tooltip : 'This field is required'
10537 // Roo.log(" no label && no align");
10544 ['xs','sm','md','lg'].map(function(size){
10545 if (settings[size]) {
10546 cfg.cls += ' col-' + size + '-' + settings[size];
10557 onResize : function(w, h){
10558 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10559 // if(typeof w == 'number'){
10560 // var x = w - this.trigger.getWidth();
10561 // this.inputEl().setWidth(this.adjustWidth('input', x));
10562 // this.trigger.setStyle('left', x+'px');
10567 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10570 getResizeEl : function(){
10571 return this.inputEl();
10575 getPositionEl : function(){
10576 return this.inputEl();
10580 alignErrorIcon : function(){
10581 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10585 initEvents : function(){
10589 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10590 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10591 if(!this.multiple && this.showToggleBtn){
10592 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10593 if(this.hideTrigger){
10594 this.trigger.setDisplayed(false);
10596 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10600 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10603 if(this.removable && !this.editable && !this.tickable){
10604 var close = this.closeTriggerEl();
10607 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10608 close.on('click', this.removeBtnClick, this, close);
10612 //this.trigger.addClassOnOver('x-form-trigger-over');
10613 //this.trigger.addClassOnClick('x-form-trigger-click');
10616 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10620 closeTriggerEl : function()
10622 var close = this.el.select('.roo-combo-removable-btn', true).first();
10623 return close ? close : false;
10626 removeBtnClick : function(e, h, el)
10628 e.preventDefault();
10630 if(this.fireEvent("remove", this) !== false){
10632 this.fireEvent("afterremove", this)
10636 createList : function()
10638 this.list = Roo.get(document.body).createChild({
10640 cls: 'typeahead typeahead-long dropdown-menu',
10641 style: 'display:none'
10644 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10649 initTrigger : function(){
10654 onDestroy : function(){
10656 this.trigger.removeAllListeners();
10657 // this.trigger.remove();
10660 // this.wrap.remove();
10662 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10666 onFocus : function(){
10667 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10669 if(!this.mimicing){
10670 this.wrap.addClass('x-trigger-wrap-focus');
10671 this.mimicing = true;
10672 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10673 if(this.monitorTab){
10674 this.el.on("keydown", this.checkTab, this);
10681 checkTab : function(e){
10682 if(e.getKey() == e.TAB){
10683 this.triggerBlur();
10688 onBlur : function(){
10693 mimicBlur : function(e, t){
10695 if(!this.wrap.contains(t) && this.validateBlur()){
10696 this.triggerBlur();
10702 triggerBlur : function(){
10703 this.mimicing = false;
10704 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10705 if(this.monitorTab){
10706 this.el.un("keydown", this.checkTab, this);
10708 //this.wrap.removeClass('x-trigger-wrap-focus');
10709 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10713 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10714 validateBlur : function(e, t){
10719 onDisable : function(){
10720 this.inputEl().dom.disabled = true;
10721 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10723 // this.wrap.addClass('x-item-disabled');
10728 onEnable : function(){
10729 this.inputEl().dom.disabled = false;
10730 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10732 // this.el.removeClass('x-item-disabled');
10737 onShow : function(){
10738 var ae = this.getActionEl();
10741 ae.dom.style.display = '';
10742 ae.dom.style.visibility = 'visible';
10748 onHide : function(){
10749 var ae = this.getActionEl();
10750 ae.dom.style.display = 'none';
10754 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10755 * by an implementing function.
10757 * @param {EventObject} e
10759 onTriggerClick : Roo.emptyFn
10763 * Ext JS Library 1.1.1
10764 * Copyright(c) 2006-2007, Ext JS, LLC.
10766 * Originally Released Under LGPL - original licence link has changed is not relivant.
10769 * <script type="text/javascript">
10774 * @class Roo.data.SortTypes
10776 * Defines the default sorting (casting?) comparison functions used when sorting data.
10778 Roo.data.SortTypes = {
10780 * Default sort that does nothing
10781 * @param {Mixed} s The value being converted
10782 * @return {Mixed} The comparison value
10784 none : function(s){
10789 * The regular expression used to strip tags
10793 stripTagsRE : /<\/?[^>]+>/gi,
10796 * Strips all HTML tags to sort on text only
10797 * @param {Mixed} s The value being converted
10798 * @return {String} The comparison value
10800 asText : function(s){
10801 return String(s).replace(this.stripTagsRE, "");
10805 * Strips all HTML tags to sort on text only - Case insensitive
10806 * @param {Mixed} s The value being converted
10807 * @return {String} The comparison value
10809 asUCText : function(s){
10810 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10814 * Case insensitive string
10815 * @param {Mixed} s The value being converted
10816 * @return {String} The comparison value
10818 asUCString : function(s) {
10819 return String(s).toUpperCase();
10824 * @param {Mixed} s The value being converted
10825 * @return {Number} The comparison value
10827 asDate : function(s) {
10831 if(s instanceof Date){
10832 return s.getTime();
10834 return Date.parse(String(s));
10839 * @param {Mixed} s The value being converted
10840 * @return {Float} The comparison value
10842 asFloat : function(s) {
10843 var val = parseFloat(String(s).replace(/,/g, ""));
10852 * @param {Mixed} s The value being converted
10853 * @return {Number} The comparison value
10855 asInt : function(s) {
10856 var val = parseInt(String(s).replace(/,/g, ""));
10864 * Ext JS Library 1.1.1
10865 * Copyright(c) 2006-2007, Ext JS, LLC.
10867 * Originally Released Under LGPL - original licence link has changed is not relivant.
10870 * <script type="text/javascript">
10874 * @class Roo.data.Record
10875 * Instances of this class encapsulate both record <em>definition</em> information, and record
10876 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10877 * to access Records cached in an {@link Roo.data.Store} object.<br>
10879 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10880 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10883 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10885 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10886 * {@link #create}. The parameters are the same.
10887 * @param {Array} data An associative Array of data values keyed by the field name.
10888 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10889 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10890 * not specified an integer id is generated.
10892 Roo.data.Record = function(data, id){
10893 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10898 * Generate a constructor for a specific record layout.
10899 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10900 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10901 * Each field definition object may contain the following properties: <ul>
10902 * <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,
10903 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10904 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10905 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10906 * is being used, then this is a string containing the javascript expression to reference the data relative to
10907 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10908 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10909 * this may be omitted.</p></li>
10910 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10911 * <ul><li>auto (Default, implies no conversion)</li>
10916 * <li>date</li></ul></p></li>
10917 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10918 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10919 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10920 * by the Reader into an object that will be stored in the Record. It is passed the
10921 * following parameters:<ul>
10922 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10924 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10926 * <br>usage:<br><pre><code>
10927 var TopicRecord = Roo.data.Record.create(
10928 {name: 'title', mapping: 'topic_title'},
10929 {name: 'author', mapping: 'username'},
10930 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10931 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10932 {name: 'lastPoster', mapping: 'user2'},
10933 {name: 'excerpt', mapping: 'post_text'}
10936 var myNewRecord = new TopicRecord({
10937 title: 'Do my job please',
10940 lastPost: new Date(),
10941 lastPoster: 'Animal',
10942 excerpt: 'No way dude!'
10944 myStore.add(myNewRecord);
10949 Roo.data.Record.create = function(o){
10950 var f = function(){
10951 f.superclass.constructor.apply(this, arguments);
10953 Roo.extend(f, Roo.data.Record);
10954 var p = f.prototype;
10955 p.fields = new Roo.util.MixedCollection(false, function(field){
10958 for(var i = 0, len = o.length; i < len; i++){
10959 p.fields.add(new Roo.data.Field(o[i]));
10961 f.getField = function(name){
10962 return p.fields.get(name);
10967 Roo.data.Record.AUTO_ID = 1000;
10968 Roo.data.Record.EDIT = 'edit';
10969 Roo.data.Record.REJECT = 'reject';
10970 Roo.data.Record.COMMIT = 'commit';
10972 Roo.data.Record.prototype = {
10974 * Readonly flag - true if this record has been modified.
10983 join : function(store){
10984 this.store = store;
10988 * Set the named field to the specified value.
10989 * @param {String} name The name of the field to set.
10990 * @param {Object} value The value to set the field to.
10992 set : function(name, value){
10993 if(this.data[name] == value){
10997 if(!this.modified){
10998 this.modified = {};
11000 if(typeof this.modified[name] == 'undefined'){
11001 this.modified[name] = this.data[name];
11003 this.data[name] = value;
11004 if(!this.editing && this.store){
11005 this.store.afterEdit(this);
11010 * Get the value of the named field.
11011 * @param {String} name The name of the field to get the value of.
11012 * @return {Object} The value of the field.
11014 get : function(name){
11015 return this.data[name];
11019 beginEdit : function(){
11020 this.editing = true;
11021 this.modified = {};
11025 cancelEdit : function(){
11026 this.editing = false;
11027 delete this.modified;
11031 endEdit : function(){
11032 this.editing = false;
11033 if(this.dirty && this.store){
11034 this.store.afterEdit(this);
11039 * Usually called by the {@link Roo.data.Store} which owns the Record.
11040 * Rejects all changes made to the Record since either creation, or the last commit operation.
11041 * Modified fields are reverted to their original values.
11043 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11044 * of reject operations.
11046 reject : function(){
11047 var m = this.modified;
11049 if(typeof m[n] != "function"){
11050 this.data[n] = m[n];
11053 this.dirty = false;
11054 delete this.modified;
11055 this.editing = false;
11057 this.store.afterReject(this);
11062 * Usually called by the {@link Roo.data.Store} which owns the Record.
11063 * Commits all changes made to the Record since either creation, or the last commit operation.
11065 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11066 * of commit operations.
11068 commit : function(){
11069 this.dirty = false;
11070 delete this.modified;
11071 this.editing = false;
11073 this.store.afterCommit(this);
11078 hasError : function(){
11079 return this.error != null;
11083 clearError : function(){
11088 * Creates a copy of this record.
11089 * @param {String} id (optional) A new record id if you don't want to use this record's id
11092 copy : function(newId) {
11093 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11097 * Ext JS Library 1.1.1
11098 * Copyright(c) 2006-2007, Ext JS, LLC.
11100 * Originally Released Under LGPL - original licence link has changed is not relivant.
11103 * <script type="text/javascript">
11109 * @class Roo.data.Store
11110 * @extends Roo.util.Observable
11111 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11112 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11114 * 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
11115 * has no knowledge of the format of the data returned by the Proxy.<br>
11117 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11118 * instances from the data object. These records are cached and made available through accessor functions.
11120 * Creates a new Store.
11121 * @param {Object} config A config object containing the objects needed for the Store to access data,
11122 * and read the data into Records.
11124 Roo.data.Store = function(config){
11125 this.data = new Roo.util.MixedCollection(false);
11126 this.data.getKey = function(o){
11129 this.baseParams = {};
11131 this.paramNames = {
11136 "multisort" : "_multisort"
11139 if(config && config.data){
11140 this.inlineData = config.data;
11141 delete config.data;
11144 Roo.apply(this, config);
11146 if(this.reader){ // reader passed
11147 this.reader = Roo.factory(this.reader, Roo.data);
11148 this.reader.xmodule = this.xmodule || false;
11149 if(!this.recordType){
11150 this.recordType = this.reader.recordType;
11152 if(this.reader.onMetaChange){
11153 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11157 if(this.recordType){
11158 this.fields = this.recordType.prototype.fields;
11160 this.modified = [];
11164 * @event datachanged
11165 * Fires when the data cache has changed, and a widget which is using this Store
11166 * as a Record cache should refresh its view.
11167 * @param {Store} this
11169 datachanged : true,
11171 * @event metachange
11172 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11173 * @param {Store} this
11174 * @param {Object} meta The JSON metadata
11179 * Fires when Records have been added to the Store
11180 * @param {Store} this
11181 * @param {Roo.data.Record[]} records The array of Records added
11182 * @param {Number} index The index at which the record(s) were added
11187 * Fires when a Record has been removed from the Store
11188 * @param {Store} this
11189 * @param {Roo.data.Record} record The Record that was removed
11190 * @param {Number} index The index at which the record was removed
11195 * Fires when a Record has been updated
11196 * @param {Store} this
11197 * @param {Roo.data.Record} record The Record that was updated
11198 * @param {String} operation The update operation being performed. Value may be one of:
11200 Roo.data.Record.EDIT
11201 Roo.data.Record.REJECT
11202 Roo.data.Record.COMMIT
11208 * Fires when the data cache has been cleared.
11209 * @param {Store} this
11213 * @event beforeload
11214 * Fires before a request is made for a new data object. If the beforeload handler returns false
11215 * the load action will be canceled.
11216 * @param {Store} this
11217 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11221 * @event beforeloadadd
11222 * Fires after a new set of Records has been loaded.
11223 * @param {Store} this
11224 * @param {Roo.data.Record[]} records The Records that were loaded
11225 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11227 beforeloadadd : true,
11230 * Fires after a new set of Records has been loaded, before they are added to the store.
11231 * @param {Store} this
11232 * @param {Roo.data.Record[]} records The Records that were loaded
11233 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11234 * @params {Object} return from reader
11238 * @event loadexception
11239 * Fires if an exception occurs in the Proxy during loading.
11240 * Called with the signature of the Proxy's "loadexception" event.
11241 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11244 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11245 * @param {Object} load options
11246 * @param {Object} jsonData from your request (normally this contains the Exception)
11248 loadexception : true
11252 this.proxy = Roo.factory(this.proxy, Roo.data);
11253 this.proxy.xmodule = this.xmodule || false;
11254 this.relayEvents(this.proxy, ["loadexception"]);
11256 this.sortToggle = {};
11257 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11259 Roo.data.Store.superclass.constructor.call(this);
11261 if(this.inlineData){
11262 this.loadData(this.inlineData);
11263 delete this.inlineData;
11267 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11269 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11270 * without a remote query - used by combo/forms at present.
11274 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11277 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11280 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11281 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11284 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11285 * on any HTTP request
11288 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11291 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11295 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11296 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11298 remoteSort : false,
11301 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11302 * loaded or when a record is removed. (defaults to false).
11304 pruneModifiedRecords : false,
11307 lastOptions : null,
11310 * Add Records to the Store and fires the add event.
11311 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11313 add : function(records){
11314 records = [].concat(records);
11315 for(var i = 0, len = records.length; i < len; i++){
11316 records[i].join(this);
11318 var index = this.data.length;
11319 this.data.addAll(records);
11320 this.fireEvent("add", this, records, index);
11324 * Remove a Record from the Store and fires the remove event.
11325 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11327 remove : function(record){
11328 var index = this.data.indexOf(record);
11329 this.data.removeAt(index);
11331 if(this.pruneModifiedRecords){
11332 this.modified.remove(record);
11334 this.fireEvent("remove", this, record, index);
11338 * Remove all Records from the Store and fires the clear event.
11340 removeAll : function(){
11342 if(this.pruneModifiedRecords){
11343 this.modified = [];
11345 this.fireEvent("clear", this);
11349 * Inserts Records to the Store at the given index and fires the add event.
11350 * @param {Number} index The start index at which to insert the passed Records.
11351 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11353 insert : function(index, records){
11354 records = [].concat(records);
11355 for(var i = 0, len = records.length; i < len; i++){
11356 this.data.insert(index, records[i]);
11357 records[i].join(this);
11359 this.fireEvent("add", this, records, index);
11363 * Get the index within the cache of the passed Record.
11364 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11365 * @return {Number} The index of the passed Record. Returns -1 if not found.
11367 indexOf : function(record){
11368 return this.data.indexOf(record);
11372 * Get the index within the cache of the Record with the passed id.
11373 * @param {String} id The id of the Record to find.
11374 * @return {Number} The index of the Record. Returns -1 if not found.
11376 indexOfId : function(id){
11377 return this.data.indexOfKey(id);
11381 * Get the Record with the specified id.
11382 * @param {String} id The id of the Record to find.
11383 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11385 getById : function(id){
11386 return this.data.key(id);
11390 * Get the Record at the specified index.
11391 * @param {Number} index The index of the Record to find.
11392 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11394 getAt : function(index){
11395 return this.data.itemAt(index);
11399 * Returns a range of Records between specified indices.
11400 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11401 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11402 * @return {Roo.data.Record[]} An array of Records
11404 getRange : function(start, end){
11405 return this.data.getRange(start, end);
11409 storeOptions : function(o){
11410 o = Roo.apply({}, o);
11413 this.lastOptions = o;
11417 * Loads the Record cache from the configured Proxy using the configured Reader.
11419 * If using remote paging, then the first load call must specify the <em>start</em>
11420 * and <em>limit</em> properties in the options.params property to establish the initial
11421 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11423 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11424 * and this call will return before the new data has been loaded. Perform any post-processing
11425 * in a callback function, or in a "load" event handler.</strong>
11427 * @param {Object} options An object containing properties which control loading options:<ul>
11428 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11429 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11430 * passed the following arguments:<ul>
11431 * <li>r : Roo.data.Record[]</li>
11432 * <li>options: Options object from the load call</li>
11433 * <li>success: Boolean success indicator</li></ul></li>
11434 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11435 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11438 load : function(options){
11439 options = options || {};
11440 if(this.fireEvent("beforeload", this, options) !== false){
11441 this.storeOptions(options);
11442 var p = Roo.apply(options.params || {}, this.baseParams);
11443 // if meta was not loaded from remote source.. try requesting it.
11444 if (!this.reader.metaFromRemote) {
11445 p._requestMeta = 1;
11447 if(this.sortInfo && this.remoteSort){
11448 var pn = this.paramNames;
11449 p[pn["sort"]] = this.sortInfo.field;
11450 p[pn["dir"]] = this.sortInfo.direction;
11452 if (this.multiSort) {
11453 var pn = this.paramNames;
11454 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11457 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11462 * Reloads the Record cache from the configured Proxy using the configured Reader and
11463 * the options from the last load operation performed.
11464 * @param {Object} options (optional) An object containing properties which may override the options
11465 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11466 * the most recently used options are reused).
11468 reload : function(options){
11469 this.load(Roo.applyIf(options||{}, this.lastOptions));
11473 // Called as a callback by the Reader during a load operation.
11474 loadRecords : function(o, options, success){
11475 if(!o || success === false){
11476 if(success !== false){
11477 this.fireEvent("load", this, [], options, o);
11479 if(options.callback){
11480 options.callback.call(options.scope || this, [], options, false);
11484 // if data returned failure - throw an exception.
11485 if (o.success === false) {
11486 // show a message if no listener is registered.
11487 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11488 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11490 // loadmask wil be hooked into this..
11491 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11494 var r = o.records, t = o.totalRecords || r.length;
11496 this.fireEvent("beforeloadadd", this, r, options, o);
11498 if(!options || options.add !== true){
11499 if(this.pruneModifiedRecords){
11500 this.modified = [];
11502 for(var i = 0, len = r.length; i < len; i++){
11506 this.data = this.snapshot;
11507 delete this.snapshot;
11510 this.data.addAll(r);
11511 this.totalLength = t;
11513 this.fireEvent("datachanged", this);
11515 this.totalLength = Math.max(t, this.data.length+r.length);
11519 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11521 var e = new Roo.data.Record({});
11523 e.set(this.parent.displayField, this.parent.emptyTitle);
11524 e.set(this.parent.valueField, '');
11529 this.fireEvent("load", this, r, options, o);
11530 if(options.callback){
11531 options.callback.call(options.scope || this, r, options, true);
11537 * Loads data from a passed data block. A Reader which understands the format of the data
11538 * must have been configured in the constructor.
11539 * @param {Object} data The data block from which to read the Records. The format of the data expected
11540 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11541 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11543 loadData : function(o, append){
11544 var r = this.reader.readRecords(o);
11545 this.loadRecords(r, {add: append}, true);
11549 * Gets the number of cached records.
11551 * <em>If using paging, this may not be the total size of the dataset. If the data object
11552 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11553 * the data set size</em>
11555 getCount : function(){
11556 return this.data.length || 0;
11560 * Gets the total number of records in the dataset as returned by the server.
11562 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11563 * the dataset size</em>
11565 getTotalCount : function(){
11566 return this.totalLength || 0;
11570 * Returns the sort state of the Store as an object with two properties:
11572 field {String} The name of the field by which the Records are sorted
11573 direction {String} The sort order, "ASC" or "DESC"
11576 getSortState : function(){
11577 return this.sortInfo;
11581 applySort : function(){
11582 if(this.sortInfo && !this.remoteSort){
11583 var s = this.sortInfo, f = s.field;
11584 var st = this.fields.get(f).sortType;
11585 var fn = function(r1, r2){
11586 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11587 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11589 this.data.sort(s.direction, fn);
11590 if(this.snapshot && this.snapshot != this.data){
11591 this.snapshot.sort(s.direction, fn);
11597 * Sets the default sort column and order to be used by the next load operation.
11598 * @param {String} fieldName The name of the field to sort by.
11599 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11601 setDefaultSort : function(field, dir){
11602 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11606 * Sort the Records.
11607 * If remote sorting is used, the sort is performed on the server, and the cache is
11608 * reloaded. If local sorting is used, the cache is sorted internally.
11609 * @param {String} fieldName The name of the field to sort by.
11610 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11612 sort : function(fieldName, dir){
11613 var f = this.fields.get(fieldName);
11615 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11617 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11618 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11623 this.sortToggle[f.name] = dir;
11624 this.sortInfo = {field: f.name, direction: dir};
11625 if(!this.remoteSort){
11627 this.fireEvent("datachanged", this);
11629 this.load(this.lastOptions);
11634 * Calls the specified function for each of the Records in the cache.
11635 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11636 * Returning <em>false</em> aborts and exits the iteration.
11637 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11639 each : function(fn, scope){
11640 this.data.each(fn, scope);
11644 * Gets all records modified since the last commit. Modified records are persisted across load operations
11645 * (e.g., during paging).
11646 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11648 getModifiedRecords : function(){
11649 return this.modified;
11653 createFilterFn : function(property, value, anyMatch){
11654 if(!value.exec){ // not a regex
11655 value = String(value);
11656 if(value.length == 0){
11659 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11661 return function(r){
11662 return value.test(r.data[property]);
11667 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11668 * @param {String} property A field on your records
11669 * @param {Number} start The record index to start at (defaults to 0)
11670 * @param {Number} end The last record index to include (defaults to length - 1)
11671 * @return {Number} The sum
11673 sum : function(property, start, end){
11674 var rs = this.data.items, v = 0;
11675 start = start || 0;
11676 end = (end || end === 0) ? end : rs.length-1;
11678 for(var i = start; i <= end; i++){
11679 v += (rs[i].data[property] || 0);
11685 * Filter the records by a specified property.
11686 * @param {String} field A field on your records
11687 * @param {String/RegExp} value Either a string that the field
11688 * should start with or a RegExp to test against the field
11689 * @param {Boolean} anyMatch True to match any part not just the beginning
11691 filter : function(property, value, anyMatch){
11692 var fn = this.createFilterFn(property, value, anyMatch);
11693 return fn ? this.filterBy(fn) : this.clearFilter();
11697 * Filter by a function. The specified function will be called with each
11698 * record in this data source. If the function returns true the record is included,
11699 * otherwise it is filtered.
11700 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11701 * @param {Object} scope (optional) The scope of the function (defaults to this)
11703 filterBy : function(fn, scope){
11704 this.snapshot = this.snapshot || this.data;
11705 this.data = this.queryBy(fn, scope||this);
11706 this.fireEvent("datachanged", this);
11710 * Query the records by a specified property.
11711 * @param {String} field A field on your records
11712 * @param {String/RegExp} value Either a string that the field
11713 * should start with or a RegExp to test against the field
11714 * @param {Boolean} anyMatch True to match any part not just the beginning
11715 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11717 query : function(property, value, anyMatch){
11718 var fn = this.createFilterFn(property, value, anyMatch);
11719 return fn ? this.queryBy(fn) : this.data.clone();
11723 * Query by a function. The specified function will be called with each
11724 * record in this data source. If the function returns true the record is included
11726 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11727 * @param {Object} scope (optional) The scope of the function (defaults to this)
11728 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11730 queryBy : function(fn, scope){
11731 var data = this.snapshot || this.data;
11732 return data.filterBy(fn, scope||this);
11736 * Collects unique values for a particular dataIndex from this store.
11737 * @param {String} dataIndex The property to collect
11738 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11739 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11740 * @return {Array} An array of the unique values
11742 collect : function(dataIndex, allowNull, bypassFilter){
11743 var d = (bypassFilter === true && this.snapshot) ?
11744 this.snapshot.items : this.data.items;
11745 var v, sv, r = [], l = {};
11746 for(var i = 0, len = d.length; i < len; i++){
11747 v = d[i].data[dataIndex];
11749 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11758 * Revert to a view of the Record cache with no filtering applied.
11759 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11761 clearFilter : function(suppressEvent){
11762 if(this.snapshot && this.snapshot != this.data){
11763 this.data = this.snapshot;
11764 delete this.snapshot;
11765 if(suppressEvent !== true){
11766 this.fireEvent("datachanged", this);
11772 afterEdit : function(record){
11773 if(this.modified.indexOf(record) == -1){
11774 this.modified.push(record);
11776 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11780 afterReject : function(record){
11781 this.modified.remove(record);
11782 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11786 afterCommit : function(record){
11787 this.modified.remove(record);
11788 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11792 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11793 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11795 commitChanges : function(){
11796 var m = this.modified.slice(0);
11797 this.modified = [];
11798 for(var i = 0, len = m.length; i < len; i++){
11804 * Cancel outstanding changes on all changed records.
11806 rejectChanges : function(){
11807 var m = this.modified.slice(0);
11808 this.modified = [];
11809 for(var i = 0, len = m.length; i < len; i++){
11814 onMetaChange : function(meta, rtype, o){
11815 this.recordType = rtype;
11816 this.fields = rtype.prototype.fields;
11817 delete this.snapshot;
11818 this.sortInfo = meta.sortInfo || this.sortInfo;
11819 this.modified = [];
11820 this.fireEvent('metachange', this, this.reader.meta);
11823 moveIndex : function(data, type)
11825 var index = this.indexOf(data);
11827 var newIndex = index + type;
11831 this.insert(newIndex, data);
11836 * Ext JS Library 1.1.1
11837 * Copyright(c) 2006-2007, Ext JS, LLC.
11839 * Originally Released Under LGPL - original licence link has changed is not relivant.
11842 * <script type="text/javascript">
11846 * @class Roo.data.SimpleStore
11847 * @extends Roo.data.Store
11848 * Small helper class to make creating Stores from Array data easier.
11849 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11850 * @cfg {Array} fields An array of field definition objects, or field name strings.
11851 * @cfg {Array} data The multi-dimensional array of data
11853 * @param {Object} config
11855 Roo.data.SimpleStore = function(config){
11856 Roo.data.SimpleStore.superclass.constructor.call(this, {
11858 reader: new Roo.data.ArrayReader({
11861 Roo.data.Record.create(config.fields)
11863 proxy : new Roo.data.MemoryProxy(config.data)
11867 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11869 * Ext JS Library 1.1.1
11870 * Copyright(c) 2006-2007, Ext JS, LLC.
11872 * Originally Released Under LGPL - original licence link has changed is not relivant.
11875 * <script type="text/javascript">
11880 * @extends Roo.data.Store
11881 * @class Roo.data.JsonStore
11882 * Small helper class to make creating Stores for JSON data easier. <br/>
11884 var store = new Roo.data.JsonStore({
11885 url: 'get-images.php',
11887 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11890 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11891 * JsonReader and HttpProxy (unless inline data is provided).</b>
11892 * @cfg {Array} fields An array of field definition objects, or field name strings.
11894 * @param {Object} config
11896 Roo.data.JsonStore = function(c){
11897 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11898 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11899 reader: new Roo.data.JsonReader(c, c.fields)
11902 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11904 * Ext JS Library 1.1.1
11905 * Copyright(c) 2006-2007, Ext JS, LLC.
11907 * Originally Released Under LGPL - original licence link has changed is not relivant.
11910 * <script type="text/javascript">
11914 Roo.data.Field = function(config){
11915 if(typeof config == "string"){
11916 config = {name: config};
11918 Roo.apply(this, config);
11921 this.type = "auto";
11924 var st = Roo.data.SortTypes;
11925 // named sortTypes are supported, here we look them up
11926 if(typeof this.sortType == "string"){
11927 this.sortType = st[this.sortType];
11930 // set default sortType for strings and dates
11931 if(!this.sortType){
11934 this.sortType = st.asUCString;
11937 this.sortType = st.asDate;
11940 this.sortType = st.none;
11945 var stripRe = /[\$,%]/g;
11947 // prebuilt conversion function for this field, instead of
11948 // switching every time we're reading a value
11950 var cv, dateFormat = this.dateFormat;
11955 cv = function(v){ return v; };
11958 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11962 return v !== undefined && v !== null && v !== '' ?
11963 parseInt(String(v).replace(stripRe, ""), 10) : '';
11968 return v !== undefined && v !== null && v !== '' ?
11969 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11974 cv = function(v){ return v === true || v === "true" || v == 1; };
11981 if(v instanceof Date){
11985 if(dateFormat == "timestamp"){
11986 return new Date(v*1000);
11988 return Date.parseDate(v, dateFormat);
11990 var parsed = Date.parse(v);
11991 return parsed ? new Date(parsed) : null;
12000 Roo.data.Field.prototype = {
12008 * Ext JS Library 1.1.1
12009 * Copyright(c) 2006-2007, Ext JS, LLC.
12011 * Originally Released Under LGPL - original licence link has changed is not relivant.
12014 * <script type="text/javascript">
12017 // Base class for reading structured data from a data source. This class is intended to be
12018 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12021 * @class Roo.data.DataReader
12022 * Base class for reading structured data from a data source. This class is intended to be
12023 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12026 Roo.data.DataReader = function(meta, recordType){
12030 this.recordType = recordType instanceof Array ?
12031 Roo.data.Record.create(recordType) : recordType;
12034 Roo.data.DataReader.prototype = {
12036 * Create an empty record
12037 * @param {Object} data (optional) - overlay some values
12038 * @return {Roo.data.Record} record created.
12040 newRow : function(d) {
12042 this.recordType.prototype.fields.each(function(c) {
12044 case 'int' : da[c.name] = 0; break;
12045 case 'date' : da[c.name] = new Date(); break;
12046 case 'float' : da[c.name] = 0.0; break;
12047 case 'boolean' : da[c.name] = false; break;
12048 default : da[c.name] = ""; break;
12052 return new this.recordType(Roo.apply(da, d));
12057 * Ext JS Library 1.1.1
12058 * Copyright(c) 2006-2007, Ext JS, LLC.
12060 * Originally Released Under LGPL - original licence link has changed is not relivant.
12063 * <script type="text/javascript">
12067 * @class Roo.data.DataProxy
12068 * @extends Roo.data.Observable
12069 * This class is an abstract base class for implementations which provide retrieval of
12070 * unformatted data objects.<br>
12072 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12073 * (of the appropriate type which knows how to parse the data object) to provide a block of
12074 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12076 * Custom implementations must implement the load method as described in
12077 * {@link Roo.data.HttpProxy#load}.
12079 Roo.data.DataProxy = function(){
12082 * @event beforeload
12083 * Fires before a network request is made to retrieve a data object.
12084 * @param {Object} This DataProxy object.
12085 * @param {Object} params The params parameter to the load function.
12090 * Fires before the load method's callback is called.
12091 * @param {Object} This DataProxy object.
12092 * @param {Object} o The data object.
12093 * @param {Object} arg The callback argument object passed to the load function.
12097 * @event loadexception
12098 * Fires if an Exception occurs during data retrieval.
12099 * @param {Object} This DataProxy object.
12100 * @param {Object} o The data object.
12101 * @param {Object} arg The callback argument object passed to the load function.
12102 * @param {Object} e The Exception.
12104 loadexception : true
12106 Roo.data.DataProxy.superclass.constructor.call(this);
12109 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12112 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12116 * Ext JS Library 1.1.1
12117 * Copyright(c) 2006-2007, Ext JS, LLC.
12119 * Originally Released Under LGPL - original licence link has changed is not relivant.
12122 * <script type="text/javascript">
12125 * @class Roo.data.MemoryProxy
12126 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12127 * to the Reader when its load method is called.
12129 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12131 Roo.data.MemoryProxy = function(data){
12135 Roo.data.MemoryProxy.superclass.constructor.call(this);
12139 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12142 * Load data from the requested source (in this case an in-memory
12143 * data object passed to the constructor), read the data object into
12144 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12145 * process that block using the passed callback.
12146 * @param {Object} params This parameter is not used by the MemoryProxy class.
12147 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12148 * object into a block of Roo.data.Records.
12149 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12150 * The function must be passed <ul>
12151 * <li>The Record block object</li>
12152 * <li>The "arg" argument from the load function</li>
12153 * <li>A boolean success indicator</li>
12155 * @param {Object} scope The scope in which to call the callback
12156 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12158 load : function(params, reader, callback, scope, arg){
12159 params = params || {};
12162 result = reader.readRecords(this.data);
12164 this.fireEvent("loadexception", this, arg, null, e);
12165 callback.call(scope, null, arg, false);
12168 callback.call(scope, result, arg, true);
12172 update : function(params, records){
12177 * Ext JS Library 1.1.1
12178 * Copyright(c) 2006-2007, Ext JS, LLC.
12180 * Originally Released Under LGPL - original licence link has changed is not relivant.
12183 * <script type="text/javascript">
12186 * @class Roo.data.HttpProxy
12187 * @extends Roo.data.DataProxy
12188 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12189 * configured to reference a certain URL.<br><br>
12191 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12192 * from which the running page was served.<br><br>
12194 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12196 * Be aware that to enable the browser to parse an XML document, the server must set
12197 * the Content-Type header in the HTTP response to "text/xml".
12199 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12200 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12201 * will be used to make the request.
12203 Roo.data.HttpProxy = function(conn){
12204 Roo.data.HttpProxy.superclass.constructor.call(this);
12205 // is conn a conn config or a real conn?
12207 this.useAjax = !conn || !conn.events;
12211 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12212 // thse are take from connection...
12215 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12218 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12219 * extra parameters to each request made by this object. (defaults to undefined)
12222 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12223 * to each request made by this object. (defaults to undefined)
12226 * @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)
12229 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12232 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12238 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12242 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12243 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12244 * a finer-grained basis than the DataProxy events.
12246 getConnection : function(){
12247 return this.useAjax ? Roo.Ajax : this.conn;
12251 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12252 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12253 * process that block using the passed callback.
12254 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12255 * for the request to the remote server.
12256 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12257 * object into a block of Roo.data.Records.
12258 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12259 * The function must be passed <ul>
12260 * <li>The Record block object</li>
12261 * <li>The "arg" argument from the load function</li>
12262 * <li>A boolean success indicator</li>
12264 * @param {Object} scope The scope in which to call the callback
12265 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12267 load : function(params, reader, callback, scope, arg){
12268 if(this.fireEvent("beforeload", this, params) !== false){
12270 params : params || {},
12272 callback : callback,
12277 callback : this.loadResponse,
12281 Roo.applyIf(o, this.conn);
12282 if(this.activeRequest){
12283 Roo.Ajax.abort(this.activeRequest);
12285 this.activeRequest = Roo.Ajax.request(o);
12287 this.conn.request(o);
12290 callback.call(scope||this, null, arg, false);
12295 loadResponse : function(o, success, response){
12296 delete this.activeRequest;
12298 this.fireEvent("loadexception", this, o, response);
12299 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12304 result = o.reader.read(response);
12306 this.fireEvent("loadexception", this, o, response, e);
12307 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12311 this.fireEvent("load", this, o, o.request.arg);
12312 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12316 update : function(dataSet){
12321 updateResponse : function(dataSet){
12326 * Ext JS Library 1.1.1
12327 * Copyright(c) 2006-2007, Ext JS, LLC.
12329 * Originally Released Under LGPL - original licence link has changed is not relivant.
12332 * <script type="text/javascript">
12336 * @class Roo.data.ScriptTagProxy
12337 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12338 * other than the originating domain of the running page.<br><br>
12340 * <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
12341 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12343 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12344 * source code that is used as the source inside a <script> tag.<br><br>
12346 * In order for the browser to process the returned data, the server must wrap the data object
12347 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12348 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12349 * depending on whether the callback name was passed:
12352 boolean scriptTag = false;
12353 String cb = request.getParameter("callback");
12356 response.setContentType("text/javascript");
12358 response.setContentType("application/x-json");
12360 Writer out = response.getWriter();
12362 out.write(cb + "(");
12364 out.print(dataBlock.toJsonString());
12371 * @param {Object} config A configuration object.
12373 Roo.data.ScriptTagProxy = function(config){
12374 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12375 Roo.apply(this, config);
12376 this.head = document.getElementsByTagName("head")[0];
12379 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12381 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12383 * @cfg {String} url The URL from which to request the data object.
12386 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12390 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12391 * the server the name of the callback function set up by the load call to process the returned data object.
12392 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12393 * javascript output which calls this named function passing the data object as its only parameter.
12395 callbackParam : "callback",
12397 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12398 * name to the request.
12403 * Load data from the configured URL, read the data object into
12404 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12405 * process that block using the passed callback.
12406 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12407 * for the request to the remote server.
12408 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12409 * object into a block of Roo.data.Records.
12410 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12411 * The function must be passed <ul>
12412 * <li>The Record block object</li>
12413 * <li>The "arg" argument from the load function</li>
12414 * <li>A boolean success indicator</li>
12416 * @param {Object} scope The scope in which to call the callback
12417 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12419 load : function(params, reader, callback, scope, arg){
12420 if(this.fireEvent("beforeload", this, params) !== false){
12422 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12424 var url = this.url;
12425 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12427 url += "&_dc=" + (new Date().getTime());
12429 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12432 cb : "stcCallback"+transId,
12433 scriptId : "stcScript"+transId,
12437 callback : callback,
12443 window[trans.cb] = function(o){
12444 conn.handleResponse(o, trans);
12447 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12449 if(this.autoAbort !== false){
12453 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12455 var script = document.createElement("script");
12456 script.setAttribute("src", url);
12457 script.setAttribute("type", "text/javascript");
12458 script.setAttribute("id", trans.scriptId);
12459 this.head.appendChild(script);
12461 this.trans = trans;
12463 callback.call(scope||this, null, arg, false);
12468 isLoading : function(){
12469 return this.trans ? true : false;
12473 * Abort the current server request.
12475 abort : function(){
12476 if(this.isLoading()){
12477 this.destroyTrans(this.trans);
12482 destroyTrans : function(trans, isLoaded){
12483 this.head.removeChild(document.getElementById(trans.scriptId));
12484 clearTimeout(trans.timeoutId);
12486 window[trans.cb] = undefined;
12488 delete window[trans.cb];
12491 // if hasn't been loaded, wait for load to remove it to prevent script error
12492 window[trans.cb] = function(){
12493 window[trans.cb] = undefined;
12495 delete window[trans.cb];
12502 handleResponse : function(o, trans){
12503 this.trans = false;
12504 this.destroyTrans(trans, true);
12507 result = trans.reader.readRecords(o);
12509 this.fireEvent("loadexception", this, o, trans.arg, e);
12510 trans.callback.call(trans.scope||window, null, trans.arg, false);
12513 this.fireEvent("load", this, o, trans.arg);
12514 trans.callback.call(trans.scope||window, result, trans.arg, true);
12518 handleFailure : function(trans){
12519 this.trans = false;
12520 this.destroyTrans(trans, false);
12521 this.fireEvent("loadexception", this, null, trans.arg);
12522 trans.callback.call(trans.scope||window, null, trans.arg, false);
12526 * Ext JS Library 1.1.1
12527 * Copyright(c) 2006-2007, Ext JS, LLC.
12529 * Originally Released Under LGPL - original licence link has changed is not relivant.
12532 * <script type="text/javascript">
12536 * @class Roo.data.JsonReader
12537 * @extends Roo.data.DataReader
12538 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12539 * based on mappings in a provided Roo.data.Record constructor.
12541 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12542 * in the reply previously.
12547 var RecordDef = Roo.data.Record.create([
12548 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12549 {name: 'occupation'} // This field will use "occupation" as the mapping.
12551 var myReader = new Roo.data.JsonReader({
12552 totalProperty: "results", // The property which contains the total dataset size (optional)
12553 root: "rows", // The property which contains an Array of row objects
12554 id: "id" // The property within each row object that provides an ID for the record (optional)
12558 * This would consume a JSON file like this:
12560 { 'results': 2, 'rows': [
12561 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12562 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12565 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12566 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12567 * paged from the remote server.
12568 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12569 * @cfg {String} root name of the property which contains the Array of row objects.
12570 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12571 * @cfg {Array} fields Array of field definition objects
12573 * Create a new JsonReader
12574 * @param {Object} meta Metadata configuration options
12575 * @param {Object} recordType Either an Array of field definition objects,
12576 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12578 Roo.data.JsonReader = function(meta, recordType){
12581 // set some defaults:
12582 Roo.applyIf(meta, {
12583 totalProperty: 'total',
12584 successProperty : 'success',
12589 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12591 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12594 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12595 * Used by Store query builder to append _requestMeta to params.
12598 metaFromRemote : false,
12600 * This method is only used by a DataProxy which has retrieved data from a remote server.
12601 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12602 * @return {Object} data A data block which is used by an Roo.data.Store object as
12603 * a cache of Roo.data.Records.
12605 read : function(response){
12606 var json = response.responseText;
12608 var o = /* eval:var:o */ eval("("+json+")");
12610 throw {message: "JsonReader.read: Json object not found"};
12616 this.metaFromRemote = true;
12617 this.meta = o.metaData;
12618 this.recordType = Roo.data.Record.create(o.metaData.fields);
12619 this.onMetaChange(this.meta, this.recordType, o);
12621 return this.readRecords(o);
12624 // private function a store will implement
12625 onMetaChange : function(meta, recordType, o){
12632 simpleAccess: function(obj, subsc) {
12639 getJsonAccessor: function(){
12641 return function(expr) {
12643 return(re.test(expr))
12644 ? new Function("obj", "return obj." + expr)
12649 return Roo.emptyFn;
12654 * Create a data block containing Roo.data.Records from an XML document.
12655 * @param {Object} o An object which contains an Array of row objects in the property specified
12656 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12657 * which contains the total size of the dataset.
12658 * @return {Object} data A data block which is used by an Roo.data.Store object as
12659 * a cache of Roo.data.Records.
12661 readRecords : function(o){
12663 * After any data loads, the raw JSON data is available for further custom processing.
12667 var s = this.meta, Record = this.recordType,
12668 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12670 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12672 if(s.totalProperty) {
12673 this.getTotal = this.getJsonAccessor(s.totalProperty);
12675 if(s.successProperty) {
12676 this.getSuccess = this.getJsonAccessor(s.successProperty);
12678 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12680 var g = this.getJsonAccessor(s.id);
12681 this.getId = function(rec) {
12683 return (r === undefined || r === "") ? null : r;
12686 this.getId = function(){return null;};
12689 for(var jj = 0; jj < fl; jj++){
12691 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12692 this.ef[jj] = this.getJsonAccessor(map);
12696 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12697 if(s.totalProperty){
12698 var vt = parseInt(this.getTotal(o), 10);
12703 if(s.successProperty){
12704 var vs = this.getSuccess(o);
12705 if(vs === false || vs === 'false'){
12710 for(var i = 0; i < c; i++){
12713 var id = this.getId(n);
12714 for(var j = 0; j < fl; j++){
12716 var v = this.ef[j](n);
12718 Roo.log('missing convert for ' + f.name);
12722 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12724 var record = new Record(values, id);
12726 records[i] = record;
12732 totalRecords : totalRecords
12737 * Ext JS Library 1.1.1
12738 * Copyright(c) 2006-2007, Ext JS, LLC.
12740 * Originally Released Under LGPL - original licence link has changed is not relivant.
12743 * <script type="text/javascript">
12747 * @class Roo.data.ArrayReader
12748 * @extends Roo.data.DataReader
12749 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12750 * Each element of that Array represents a row of data fields. The
12751 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12752 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12756 var RecordDef = Roo.data.Record.create([
12757 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12758 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12760 var myReader = new Roo.data.ArrayReader({
12761 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12765 * This would consume an Array like this:
12767 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12769 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12771 * Create a new JsonReader
12772 * @param {Object} meta Metadata configuration options.
12773 * @param {Object} recordType Either an Array of field definition objects
12774 * as specified to {@link Roo.data.Record#create},
12775 * or an {@link Roo.data.Record} object
12776 * created using {@link Roo.data.Record#create}.
12778 Roo.data.ArrayReader = function(meta, recordType){
12779 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12782 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12784 * Create a data block containing Roo.data.Records from an XML document.
12785 * @param {Object} o An Array of row objects which represents the dataset.
12786 * @return {Object} data A data block which is used by an Roo.data.Store object as
12787 * a cache of Roo.data.Records.
12789 readRecords : function(o){
12790 var sid = this.meta ? this.meta.id : null;
12791 var recordType = this.recordType, fields = recordType.prototype.fields;
12794 for(var i = 0; i < root.length; i++){
12797 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12798 for(var j = 0, jlen = fields.length; j < jlen; j++){
12799 var f = fields.items[j];
12800 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12801 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12803 values[f.name] = v;
12805 var record = new recordType(values, id);
12807 records[records.length] = record;
12811 totalRecords : records.length
12820 * @class Roo.bootstrap.ComboBox
12821 * @extends Roo.bootstrap.TriggerField
12822 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12823 * @cfg {Boolean} append (true|false) default false
12824 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12825 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12826 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12827 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12828 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12829 * @cfg {Boolean} animate default true
12830 * @cfg {Boolean} emptyResultText only for touch device
12831 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12832 * @cfg {String} emptyTitle default ''
12834 * Create a new ComboBox.
12835 * @param {Object} config Configuration options
12837 Roo.bootstrap.ComboBox = function(config){
12838 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12842 * Fires when the dropdown list is expanded
12843 * @param {Roo.bootstrap.ComboBox} combo This combo box
12848 * Fires when the dropdown list is collapsed
12849 * @param {Roo.bootstrap.ComboBox} combo This combo box
12853 * @event beforeselect
12854 * Fires before a list item is selected. Return false to cancel the selection.
12855 * @param {Roo.bootstrap.ComboBox} combo This combo box
12856 * @param {Roo.data.Record} record The data record returned from the underlying store
12857 * @param {Number} index The index of the selected item in the dropdown list
12859 'beforeselect' : true,
12862 * Fires when a list item is selected
12863 * @param {Roo.bootstrap.ComboBox} combo This combo box
12864 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12865 * @param {Number} index The index of the selected item in the dropdown list
12869 * @event beforequery
12870 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12871 * The event object passed has these properties:
12872 * @param {Roo.bootstrap.ComboBox} combo This combo box
12873 * @param {String} query The query
12874 * @param {Boolean} forceAll true to force "all" query
12875 * @param {Boolean} cancel true to cancel the query
12876 * @param {Object} e The query event object
12878 'beforequery': true,
12881 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12882 * @param {Roo.bootstrap.ComboBox} combo This combo box
12887 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12888 * @param {Roo.bootstrap.ComboBox} combo This combo box
12889 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12894 * Fires when the remove value from the combobox array
12895 * @param {Roo.bootstrap.ComboBox} combo This combo box
12899 * @event afterremove
12900 * Fires when the remove value from the combobox array
12901 * @param {Roo.bootstrap.ComboBox} combo This combo box
12903 'afterremove' : true,
12905 * @event specialfilter
12906 * Fires when specialfilter
12907 * @param {Roo.bootstrap.ComboBox} combo This combo box
12909 'specialfilter' : true,
12912 * Fires when tick the element
12913 * @param {Roo.bootstrap.ComboBox} combo This combo box
12917 * @event touchviewdisplay
12918 * Fires when touch view require special display (default is using displayField)
12919 * @param {Roo.bootstrap.ComboBox} combo This combo box
12920 * @param {Object} cfg set html .
12922 'touchviewdisplay' : true
12927 this.tickItems = [];
12929 this.selectedIndex = -1;
12930 if(this.mode == 'local'){
12931 if(config.queryDelay === undefined){
12932 this.queryDelay = 10;
12934 if(config.minChars === undefined){
12940 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12943 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12944 * rendering into an Roo.Editor, defaults to false)
12947 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12948 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12951 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12954 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12955 * the dropdown list (defaults to undefined, with no header element)
12959 * @cfg {String/Roo.Template} tpl The template to use to render the output
12963 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12965 listWidth: undefined,
12967 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12968 * mode = 'remote' or 'text' if mode = 'local')
12970 displayField: undefined,
12973 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12974 * mode = 'remote' or 'value' if mode = 'local').
12975 * Note: use of a valueField requires the user make a selection
12976 * in order for a value to be mapped.
12978 valueField: undefined,
12980 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12985 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12986 * field's data value (defaults to the underlying DOM element's name)
12988 hiddenName: undefined,
12990 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12994 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12996 selectedClass: 'active',
12999 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13003 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13004 * anchor positions (defaults to 'tl-bl')
13006 listAlign: 'tl-bl?',
13008 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13012 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13013 * query specified by the allQuery config option (defaults to 'query')
13015 triggerAction: 'query',
13017 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13018 * (defaults to 4, does not apply if editable = false)
13022 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13023 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13027 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13028 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13032 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13033 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13037 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13038 * when editable = true (defaults to false)
13040 selectOnFocus:false,
13042 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13044 queryParam: 'query',
13046 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13047 * when mode = 'remote' (defaults to 'Loading...')
13049 loadingText: 'Loading...',
13051 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13055 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13059 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13060 * traditional select (defaults to true)
13064 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13068 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13072 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13073 * listWidth has a higher value)
13077 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13078 * allow the user to set arbitrary text into the field (defaults to false)
13080 forceSelection:false,
13082 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13083 * if typeAhead = true (defaults to 250)
13085 typeAheadDelay : 250,
13087 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13088 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13090 valueNotFoundText : undefined,
13092 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13094 blockFocus : false,
13097 * @cfg {Boolean} disableClear Disable showing of clear button.
13099 disableClear : false,
13101 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13103 alwaysQuery : false,
13106 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13111 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13113 invalidClass : "has-warning",
13116 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13118 validClass : "has-success",
13121 * @cfg {Boolean} specialFilter (true|false) special filter default false
13123 specialFilter : false,
13126 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13128 mobileTouchView : true,
13131 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13133 useNativeIOS : false,
13136 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13138 mobile_restrict_height : false,
13140 ios_options : false,
13152 btnPosition : 'right',
13153 triggerList : true,
13154 showToggleBtn : true,
13156 emptyResultText: 'Empty',
13157 triggerText : 'Select',
13160 // element that contains real text value.. (when hidden is used..)
13162 getAutoCreate : function()
13167 * Render classic select for iso
13170 if(Roo.isIOS && this.useNativeIOS){
13171 cfg = this.getAutoCreateNativeIOS();
13179 if(Roo.isTouch && this.mobileTouchView){
13180 cfg = this.getAutoCreateTouchView();
13187 if(!this.tickable){
13188 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13193 * ComboBox with tickable selections
13196 var align = this.labelAlign || this.parentLabelAlign();
13199 cls : 'form-group roo-combobox-tickable' //input-group
13202 var btn_text_select = '';
13203 var btn_text_done = '';
13204 var btn_text_cancel = '';
13206 if (this.btn_text_show) {
13207 btn_text_select = 'Select';
13208 btn_text_done = 'Done';
13209 btn_text_cancel = 'Cancel';
13214 cls : 'tickable-buttons',
13219 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13220 //html : this.triggerText
13221 html: btn_text_select
13227 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13229 html: btn_text_done
13235 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13237 html: btn_text_cancel
13243 buttons.cn.unshift({
13245 cls: 'roo-select2-search-field-input'
13251 Roo.each(buttons.cn, function(c){
13253 c.cls += ' btn-' + _this.size;
13256 if (_this.disabled) {
13267 cls: 'form-hidden-field'
13271 cls: 'roo-select2-choices',
13275 cls: 'roo-select2-search-field',
13286 cls: 'roo-select2-container input-group roo-select2-container-multi',
13291 // cls: 'typeahead typeahead-long dropdown-menu',
13292 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13297 if(this.hasFeedback && !this.allowBlank){
13301 cls: 'glyphicon form-control-feedback'
13304 combobox.cn.push(feedback);
13308 if (align ==='left' && this.fieldLabel.length) {
13310 cfg.cls += ' roo-form-group-label-left';
13315 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13316 tooltip : 'This field is required'
13321 cls : 'control-label',
13322 html : this.fieldLabel
13334 var labelCfg = cfg.cn[1];
13335 var contentCfg = cfg.cn[2];
13338 if(this.indicatorpos == 'right'){
13344 cls : 'control-label',
13348 html : this.fieldLabel
13352 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13353 tooltip : 'This field is required'
13368 labelCfg = cfg.cn[0];
13369 contentCfg = cfg.cn[1];
13373 if(this.labelWidth > 12){
13374 labelCfg.style = "width: " + this.labelWidth + 'px';
13377 if(this.labelWidth < 13 && this.labelmd == 0){
13378 this.labelmd = this.labelWidth;
13381 if(this.labellg > 0){
13382 labelCfg.cls += ' col-lg-' + this.labellg;
13383 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13386 if(this.labelmd > 0){
13387 labelCfg.cls += ' col-md-' + this.labelmd;
13388 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13391 if(this.labelsm > 0){
13392 labelCfg.cls += ' col-sm-' + this.labelsm;
13393 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13396 if(this.labelxs > 0){
13397 labelCfg.cls += ' col-xs-' + this.labelxs;
13398 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13402 } else if ( this.fieldLabel.length) {
13403 // Roo.log(" label");
13407 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13408 tooltip : 'This field is required'
13412 //cls : 'input-group-addon',
13413 html : this.fieldLabel
13418 if(this.indicatorpos == 'right'){
13422 //cls : 'input-group-addon',
13423 html : this.fieldLabel
13427 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13428 tooltip : 'This field is required'
13437 // Roo.log(" no label && no align");
13444 ['xs','sm','md','lg'].map(function(size){
13445 if (settings[size]) {
13446 cfg.cls += ' col-' + size + '-' + settings[size];
13454 _initEventsCalled : false,
13457 initEvents: function()
13459 if (this._initEventsCalled) { // as we call render... prevent looping...
13462 this._initEventsCalled = true;
13465 throw "can not find store for combo";
13468 this.indicator = this.indicatorEl();
13470 this.store = Roo.factory(this.store, Roo.data);
13471 this.store.parent = this;
13473 // if we are building from html. then this element is so complex, that we can not really
13474 // use the rendered HTML.
13475 // so we have to trash and replace the previous code.
13476 if (Roo.XComponent.build_from_html) {
13477 // remove this element....
13478 var e = this.el.dom, k=0;
13479 while (e ) { e = e.previousSibling; ++k;}
13484 this.rendered = false;
13486 this.render(this.parent().getChildContainer(true), k);
13489 if(Roo.isIOS && this.useNativeIOS){
13490 this.initIOSView();
13498 if(Roo.isTouch && this.mobileTouchView){
13499 this.initTouchView();
13504 this.initTickableEvents();
13508 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13510 if(this.hiddenName){
13512 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13514 this.hiddenField.dom.value =
13515 this.hiddenValue !== undefined ? this.hiddenValue :
13516 this.value !== undefined ? this.value : '';
13518 // prevent input submission
13519 this.el.dom.removeAttribute('name');
13520 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13525 // this.el.dom.setAttribute('autocomplete', 'off');
13528 var cls = 'x-combo-list';
13530 //this.list = new Roo.Layer({
13531 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13537 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13538 _this.list.setWidth(lw);
13541 this.list.on('mouseover', this.onViewOver, this);
13542 this.list.on('mousemove', this.onViewMove, this);
13543 this.list.on('scroll', this.onViewScroll, this);
13546 this.list.swallowEvent('mousewheel');
13547 this.assetHeight = 0;
13550 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13551 this.assetHeight += this.header.getHeight();
13554 this.innerList = this.list.createChild({cls:cls+'-inner'});
13555 this.innerList.on('mouseover', this.onViewOver, this);
13556 this.innerList.on('mousemove', this.onViewMove, this);
13557 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13559 if(this.allowBlank && !this.pageSize && !this.disableClear){
13560 this.footer = this.list.createChild({cls:cls+'-ft'});
13561 this.pageTb = new Roo.Toolbar(this.footer);
13565 this.footer = this.list.createChild({cls:cls+'-ft'});
13566 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13567 {pageSize: this.pageSize});
13571 if (this.pageTb && this.allowBlank && !this.disableClear) {
13573 this.pageTb.add(new Roo.Toolbar.Fill(), {
13574 cls: 'x-btn-icon x-btn-clear',
13576 handler: function()
13579 _this.clearValue();
13580 _this.onSelect(false, -1);
13585 this.assetHeight += this.footer.getHeight();
13590 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13593 this.view = new Roo.View(this.list, this.tpl, {
13594 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13596 //this.view.wrapEl.setDisplayed(false);
13597 this.view.on('click', this.onViewClick, this);
13600 this.store.on('beforeload', this.onBeforeLoad, this);
13601 this.store.on('load', this.onLoad, this);
13602 this.store.on('loadexception', this.onLoadException, this);
13604 if(this.resizable){
13605 this.resizer = new Roo.Resizable(this.list, {
13606 pinned:true, handles:'se'
13608 this.resizer.on('resize', function(r, w, h){
13609 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13610 this.listWidth = w;
13611 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13612 this.restrictHeight();
13614 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13617 if(!this.editable){
13618 this.editable = true;
13619 this.setEditable(false);
13624 if (typeof(this.events.add.listeners) != 'undefined') {
13626 this.addicon = this.wrap.createChild(
13627 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13629 this.addicon.on('click', function(e) {
13630 this.fireEvent('add', this);
13633 if (typeof(this.events.edit.listeners) != 'undefined') {
13635 this.editicon = this.wrap.createChild(
13636 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13637 if (this.addicon) {
13638 this.editicon.setStyle('margin-left', '40px');
13640 this.editicon.on('click', function(e) {
13642 // we fire even if inothing is selected..
13643 this.fireEvent('edit', this, this.lastData );
13649 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13650 "up" : function(e){
13651 this.inKeyMode = true;
13655 "down" : function(e){
13656 if(!this.isExpanded()){
13657 this.onTriggerClick();
13659 this.inKeyMode = true;
13664 "enter" : function(e){
13665 // this.onViewClick();
13669 if(this.fireEvent("specialkey", this, e)){
13670 this.onViewClick(false);
13676 "esc" : function(e){
13680 "tab" : function(e){
13683 if(this.fireEvent("specialkey", this, e)){
13684 this.onViewClick(false);
13692 doRelay : function(foo, bar, hname){
13693 if(hname == 'down' || this.scope.isExpanded()){
13694 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13703 this.queryDelay = Math.max(this.queryDelay || 10,
13704 this.mode == 'local' ? 10 : 250);
13707 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13709 if(this.typeAhead){
13710 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13712 if(this.editable !== false){
13713 this.inputEl().on("keyup", this.onKeyUp, this);
13715 if(this.forceSelection){
13716 this.inputEl().on('blur', this.doForce, this);
13720 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13721 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13725 initTickableEvents: function()
13729 if(this.hiddenName){
13731 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13733 this.hiddenField.dom.value =
13734 this.hiddenValue !== undefined ? this.hiddenValue :
13735 this.value !== undefined ? this.value : '';
13737 // prevent input submission
13738 this.el.dom.removeAttribute('name');
13739 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13744 // this.list = this.el.select('ul.dropdown-menu',true).first();
13746 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13747 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13748 if(this.triggerList){
13749 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13752 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13753 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13755 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13756 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13758 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13759 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13761 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13762 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13763 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13766 this.cancelBtn.hide();
13771 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13772 _this.list.setWidth(lw);
13775 this.list.on('mouseover', this.onViewOver, this);
13776 this.list.on('mousemove', this.onViewMove, this);
13778 this.list.on('scroll', this.onViewScroll, this);
13781 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13782 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13785 this.view = new Roo.View(this.list, this.tpl, {
13790 selectedClass: this.selectedClass
13793 //this.view.wrapEl.setDisplayed(false);
13794 this.view.on('click', this.onViewClick, this);
13798 this.store.on('beforeload', this.onBeforeLoad, this);
13799 this.store.on('load', this.onLoad, this);
13800 this.store.on('loadexception', this.onLoadException, this);
13803 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13804 "up" : function(e){
13805 this.inKeyMode = true;
13809 "down" : function(e){
13810 this.inKeyMode = true;
13814 "enter" : function(e){
13815 if(this.fireEvent("specialkey", this, e)){
13816 this.onViewClick(false);
13822 "esc" : function(e){
13823 this.onTickableFooterButtonClick(e, false, false);
13826 "tab" : function(e){
13827 this.fireEvent("specialkey", this, e);
13829 this.onTickableFooterButtonClick(e, false, false);
13836 doRelay : function(e, fn, key){
13837 if(this.scope.isExpanded()){
13838 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13847 this.queryDelay = Math.max(this.queryDelay || 10,
13848 this.mode == 'local' ? 10 : 250);
13851 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13853 if(this.typeAhead){
13854 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13857 if(this.editable !== false){
13858 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13861 this.indicator = this.indicatorEl();
13863 if(this.indicator){
13864 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13865 this.indicator.hide();
13870 onDestroy : function(){
13872 this.view.setStore(null);
13873 this.view.el.removeAllListeners();
13874 this.view.el.remove();
13875 this.view.purgeListeners();
13878 this.list.dom.innerHTML = '';
13882 this.store.un('beforeload', this.onBeforeLoad, this);
13883 this.store.un('load', this.onLoad, this);
13884 this.store.un('loadexception', this.onLoadException, this);
13886 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13890 fireKey : function(e){
13891 if(e.isNavKeyPress() && !this.list.isVisible()){
13892 this.fireEvent("specialkey", this, e);
13897 onResize: function(w, h){
13898 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13900 // if(typeof w != 'number'){
13901 // // we do not handle it!?!?
13904 // var tw = this.trigger.getWidth();
13905 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13906 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13908 // this.inputEl().setWidth( this.adjustWidth('input', x));
13910 // //this.trigger.setStyle('left', x+'px');
13912 // if(this.list && this.listWidth === undefined){
13913 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13914 // this.list.setWidth(lw);
13915 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13923 * Allow or prevent the user from directly editing the field text. If false is passed,
13924 * the user will only be able to select from the items defined in the dropdown list. This method
13925 * is the runtime equivalent of setting the 'editable' config option at config time.
13926 * @param {Boolean} value True to allow the user to directly edit the field text
13928 setEditable : function(value){
13929 if(value == this.editable){
13932 this.editable = value;
13934 this.inputEl().dom.setAttribute('readOnly', true);
13935 this.inputEl().on('mousedown', this.onTriggerClick, this);
13936 this.inputEl().addClass('x-combo-noedit');
13938 this.inputEl().dom.setAttribute('readOnly', false);
13939 this.inputEl().un('mousedown', this.onTriggerClick, this);
13940 this.inputEl().removeClass('x-combo-noedit');
13946 onBeforeLoad : function(combo,opts){
13947 if(!this.hasFocus){
13951 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13953 this.restrictHeight();
13954 this.selectedIndex = -1;
13958 onLoad : function(){
13960 this.hasQuery = false;
13962 if(!this.hasFocus){
13966 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13967 this.loading.hide();
13970 if(this.store.getCount() > 0){
13973 this.restrictHeight();
13974 if(this.lastQuery == this.allQuery){
13975 if(this.editable && !this.tickable){
13976 this.inputEl().dom.select();
13980 !this.selectByValue(this.value, true) &&
13983 !this.store.lastOptions ||
13984 typeof(this.store.lastOptions.add) == 'undefined' ||
13985 this.store.lastOptions.add != true
13988 this.select(0, true);
13991 if(this.autoFocus){
13994 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13995 this.taTask.delay(this.typeAheadDelay);
13999 this.onEmptyResults();
14005 onLoadException : function()
14007 this.hasQuery = false;
14009 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14010 this.loading.hide();
14013 if(this.tickable && this.editable){
14018 // only causes errors at present
14019 //Roo.log(this.store.reader.jsonData);
14020 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14022 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14028 onTypeAhead : function(){
14029 if(this.store.getCount() > 0){
14030 var r = this.store.getAt(0);
14031 var newValue = r.data[this.displayField];
14032 var len = newValue.length;
14033 var selStart = this.getRawValue().length;
14035 if(selStart != len){
14036 this.setRawValue(newValue);
14037 this.selectText(selStart, newValue.length);
14043 onSelect : function(record, index){
14045 if(this.fireEvent('beforeselect', this, record, index) !== false){
14047 this.setFromData(index > -1 ? record.data : false);
14050 this.fireEvent('select', this, record, index);
14055 * Returns the currently selected field value or empty string if no value is set.
14056 * @return {String} value The selected value
14058 getValue : function()
14060 if(Roo.isIOS && this.useNativeIOS){
14061 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14065 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14068 if(this.valueField){
14069 return typeof this.value != 'undefined' ? this.value : '';
14071 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14075 getRawValue : function()
14077 if(Roo.isIOS && this.useNativeIOS){
14078 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14081 var v = this.inputEl().getValue();
14087 * Clears any text/value currently set in the field
14089 clearValue : function(){
14091 if(this.hiddenField){
14092 this.hiddenField.dom.value = '';
14095 this.setRawValue('');
14096 this.lastSelectionText = '';
14097 this.lastData = false;
14099 var close = this.closeTriggerEl();
14110 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14111 * will be displayed in the field. If the value does not match the data value of an existing item,
14112 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14113 * Otherwise the field will be blank (although the value will still be set).
14114 * @param {String} value The value to match
14116 setValue : function(v)
14118 if(Roo.isIOS && this.useNativeIOS){
14119 this.setIOSValue(v);
14129 if(this.valueField){
14130 var r = this.findRecord(this.valueField, v);
14132 text = r.data[this.displayField];
14133 }else if(this.valueNotFoundText !== undefined){
14134 text = this.valueNotFoundText;
14137 this.lastSelectionText = text;
14138 if(this.hiddenField){
14139 this.hiddenField.dom.value = v;
14141 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14144 var close = this.closeTriggerEl();
14147 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14153 * @property {Object} the last set data for the element
14158 * Sets the value of the field based on a object which is related to the record format for the store.
14159 * @param {Object} value the value to set as. or false on reset?
14161 setFromData : function(o){
14168 var dv = ''; // display value
14169 var vv = ''; // value value..
14171 if (this.displayField) {
14172 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14174 // this is an error condition!!!
14175 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14178 if(this.valueField){
14179 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14182 var close = this.closeTriggerEl();
14185 if(dv.length || vv * 1 > 0){
14187 this.blockFocus=true;
14193 if(this.hiddenField){
14194 this.hiddenField.dom.value = vv;
14196 this.lastSelectionText = dv;
14197 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14201 // no hidden field.. - we store the value in 'value', but still display
14202 // display field!!!!
14203 this.lastSelectionText = dv;
14204 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14211 reset : function(){
14212 // overridden so that last data is reset..
14219 this.setValue(this.originalValue);
14220 //this.clearInvalid();
14221 this.lastData = false;
14223 this.view.clearSelections();
14229 findRecord : function(prop, value){
14231 if(this.store.getCount() > 0){
14232 this.store.each(function(r){
14233 if(r.data[prop] == value){
14243 getName: function()
14245 // returns hidden if it's set..
14246 if (!this.rendered) {return ''};
14247 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14251 onViewMove : function(e, t){
14252 this.inKeyMode = false;
14256 onViewOver : function(e, t){
14257 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14260 var item = this.view.findItemFromChild(t);
14263 var index = this.view.indexOf(item);
14264 this.select(index, false);
14269 onViewClick : function(view, doFocus, el, e)
14271 var index = this.view.getSelectedIndexes()[0];
14273 var r = this.store.getAt(index);
14277 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14284 Roo.each(this.tickItems, function(v,k){
14286 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14288 _this.tickItems.splice(k, 1);
14290 if(typeof(e) == 'undefined' && view == false){
14291 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14303 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14304 this.tickItems.push(r.data);
14307 if(typeof(e) == 'undefined' && view == false){
14308 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14315 this.onSelect(r, index);
14317 if(doFocus !== false && !this.blockFocus){
14318 this.inputEl().focus();
14323 restrictHeight : function(){
14324 //this.innerList.dom.style.height = '';
14325 //var inner = this.innerList.dom;
14326 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14327 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14328 //this.list.beginUpdate();
14329 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14330 this.list.alignTo(this.inputEl(), this.listAlign);
14331 this.list.alignTo(this.inputEl(), this.listAlign);
14332 //this.list.endUpdate();
14336 onEmptyResults : function(){
14338 if(this.tickable && this.editable){
14339 this.hasFocus = false;
14340 this.restrictHeight();
14348 * Returns true if the dropdown list is expanded, else false.
14350 isExpanded : function(){
14351 return this.list.isVisible();
14355 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14356 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14357 * @param {String} value The data value of the item to select
14358 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14359 * selected item if it is not currently in view (defaults to true)
14360 * @return {Boolean} True if the value matched an item in the list, else false
14362 selectByValue : function(v, scrollIntoView){
14363 if(v !== undefined && v !== null){
14364 var r = this.findRecord(this.valueField || this.displayField, v);
14366 this.select(this.store.indexOf(r), scrollIntoView);
14374 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14375 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14376 * @param {Number} index The zero-based index of the list item to select
14377 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14378 * selected item if it is not currently in view (defaults to true)
14380 select : function(index, scrollIntoView){
14381 this.selectedIndex = index;
14382 this.view.select(index);
14383 if(scrollIntoView !== false){
14384 var el = this.view.getNode(index);
14386 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14389 this.list.scrollChildIntoView(el, false);
14395 selectNext : function(){
14396 var ct = this.store.getCount();
14398 if(this.selectedIndex == -1){
14400 }else if(this.selectedIndex < ct-1){
14401 this.select(this.selectedIndex+1);
14407 selectPrev : function(){
14408 var ct = this.store.getCount();
14410 if(this.selectedIndex == -1){
14412 }else if(this.selectedIndex != 0){
14413 this.select(this.selectedIndex-1);
14419 onKeyUp : function(e){
14420 if(this.editable !== false && !e.isSpecialKey()){
14421 this.lastKey = e.getKey();
14422 this.dqTask.delay(this.queryDelay);
14427 validateBlur : function(){
14428 return !this.list || !this.list.isVisible();
14432 initQuery : function(){
14434 var v = this.getRawValue();
14436 if(this.tickable && this.editable){
14437 v = this.tickableInputEl().getValue();
14444 doForce : function(){
14445 if(this.inputEl().dom.value.length > 0){
14446 this.inputEl().dom.value =
14447 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14453 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14454 * query allowing the query action to be canceled if needed.
14455 * @param {String} query The SQL query to execute
14456 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14457 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14458 * saved in the current store (defaults to false)
14460 doQuery : function(q, forceAll){
14462 if(q === undefined || q === null){
14467 forceAll: forceAll,
14471 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14476 forceAll = qe.forceAll;
14477 if(forceAll === true || (q.length >= this.minChars)){
14479 this.hasQuery = true;
14481 if(this.lastQuery != q || this.alwaysQuery){
14482 this.lastQuery = q;
14483 if(this.mode == 'local'){
14484 this.selectedIndex = -1;
14486 this.store.clearFilter();
14489 if(this.specialFilter){
14490 this.fireEvent('specialfilter', this);
14495 this.store.filter(this.displayField, q);
14498 this.store.fireEvent("datachanged", this.store);
14505 this.store.baseParams[this.queryParam] = q;
14507 var options = {params : this.getParams(q)};
14510 options.add = true;
14511 options.params.start = this.page * this.pageSize;
14514 this.store.load(options);
14517 * this code will make the page width larger, at the beginning, the list not align correctly,
14518 * we should expand the list on onLoad
14519 * so command out it
14524 this.selectedIndex = -1;
14529 this.loadNext = false;
14533 getParams : function(q){
14535 //p[this.queryParam] = q;
14539 p.limit = this.pageSize;
14545 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14547 collapse : function(){
14548 if(!this.isExpanded()){
14554 this.hasFocus = false;
14558 this.cancelBtn.hide();
14559 this.trigger.show();
14562 this.tickableInputEl().dom.value = '';
14563 this.tickableInputEl().blur();
14568 Roo.get(document).un('mousedown', this.collapseIf, this);
14569 Roo.get(document).un('mousewheel', this.collapseIf, this);
14570 if (!this.editable) {
14571 Roo.get(document).un('keydown', this.listKeyPress, this);
14573 this.fireEvent('collapse', this);
14579 collapseIf : function(e){
14580 var in_combo = e.within(this.el);
14581 var in_list = e.within(this.list);
14582 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14584 if (in_combo || in_list || is_list) {
14585 //e.stopPropagation();
14590 this.onTickableFooterButtonClick(e, false, false);
14598 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14600 expand : function(){
14602 if(this.isExpanded() || !this.hasFocus){
14606 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14607 this.list.setWidth(lw);
14613 this.restrictHeight();
14617 this.tickItems = Roo.apply([], this.item);
14620 this.cancelBtn.show();
14621 this.trigger.hide();
14624 this.tickableInputEl().focus();
14629 Roo.get(document).on('mousedown', this.collapseIf, this);
14630 Roo.get(document).on('mousewheel', this.collapseIf, this);
14631 if (!this.editable) {
14632 Roo.get(document).on('keydown', this.listKeyPress, this);
14635 this.fireEvent('expand', this);
14639 // Implements the default empty TriggerField.onTriggerClick function
14640 onTriggerClick : function(e)
14642 Roo.log('trigger click');
14644 if(this.disabled || !this.triggerList){
14649 this.loadNext = false;
14651 if(this.isExpanded()){
14653 if (!this.blockFocus) {
14654 this.inputEl().focus();
14658 this.hasFocus = true;
14659 if(this.triggerAction == 'all') {
14660 this.doQuery(this.allQuery, true);
14662 this.doQuery(this.getRawValue());
14664 if (!this.blockFocus) {
14665 this.inputEl().focus();
14670 onTickableTriggerClick : function(e)
14677 this.loadNext = false;
14678 this.hasFocus = true;
14680 if(this.triggerAction == 'all') {
14681 this.doQuery(this.allQuery, true);
14683 this.doQuery(this.getRawValue());
14687 onSearchFieldClick : function(e)
14689 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14690 this.onTickableFooterButtonClick(e, false, false);
14694 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14699 this.loadNext = false;
14700 this.hasFocus = true;
14702 if(this.triggerAction == 'all') {
14703 this.doQuery(this.allQuery, true);
14705 this.doQuery(this.getRawValue());
14709 listKeyPress : function(e)
14711 //Roo.log('listkeypress');
14712 // scroll to first matching element based on key pres..
14713 if (e.isSpecialKey()) {
14716 var k = String.fromCharCode(e.getKey()).toUpperCase();
14719 var csel = this.view.getSelectedNodes();
14720 var cselitem = false;
14722 var ix = this.view.indexOf(csel[0]);
14723 cselitem = this.store.getAt(ix);
14724 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14730 this.store.each(function(v) {
14732 // start at existing selection.
14733 if (cselitem.id == v.id) {
14739 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14740 match = this.store.indexOf(v);
14746 if (match === false) {
14747 return true; // no more action?
14750 this.view.select(match);
14751 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14752 sn.scrollIntoView(sn.dom.parentNode, false);
14755 onViewScroll : function(e, t){
14757 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){
14761 this.hasQuery = true;
14763 this.loading = this.list.select('.loading', true).first();
14765 if(this.loading === null){
14766 this.list.createChild({
14768 cls: 'loading roo-select2-more-results roo-select2-active',
14769 html: 'Loading more results...'
14772 this.loading = this.list.select('.loading', true).first();
14774 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14776 this.loading.hide();
14779 this.loading.show();
14784 this.loadNext = true;
14786 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14791 addItem : function(o)
14793 var dv = ''; // display value
14795 if (this.displayField) {
14796 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14798 // this is an error condition!!!
14799 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14806 var choice = this.choices.createChild({
14808 cls: 'roo-select2-search-choice',
14817 cls: 'roo-select2-search-choice-close fa fa-times',
14822 }, this.searchField);
14824 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14826 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14834 this.inputEl().dom.value = '';
14839 onRemoveItem : function(e, _self, o)
14841 e.preventDefault();
14843 this.lastItem = Roo.apply([], this.item);
14845 var index = this.item.indexOf(o.data) * 1;
14848 Roo.log('not this item?!');
14852 this.item.splice(index, 1);
14857 this.fireEvent('remove', this, e);
14863 syncValue : function()
14865 if(!this.item.length){
14872 Roo.each(this.item, function(i){
14873 if(_this.valueField){
14874 value.push(i[_this.valueField]);
14881 this.value = value.join(',');
14883 if(this.hiddenField){
14884 this.hiddenField.dom.value = this.value;
14887 this.store.fireEvent("datachanged", this.store);
14892 clearItem : function()
14894 if(!this.multiple){
14900 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14908 if(this.tickable && !Roo.isTouch){
14909 this.view.refresh();
14913 inputEl: function ()
14915 if(Roo.isIOS && this.useNativeIOS){
14916 return this.el.select('select.roo-ios-select', true).first();
14919 if(Roo.isTouch && this.mobileTouchView){
14920 return this.el.select('input.form-control',true).first();
14924 return this.searchField;
14927 return this.el.select('input.form-control',true).first();
14930 onTickableFooterButtonClick : function(e, btn, el)
14932 e.preventDefault();
14934 this.lastItem = Roo.apply([], this.item);
14936 if(btn && btn.name == 'cancel'){
14937 this.tickItems = Roo.apply([], this.item);
14946 Roo.each(this.tickItems, function(o){
14954 validate : function()
14956 if(this.getVisibilityEl().hasClass('hidden')){
14960 var v = this.getRawValue();
14963 v = this.getValue();
14966 if(this.disabled || this.allowBlank || v.length){
14971 this.markInvalid();
14975 tickableInputEl : function()
14977 if(!this.tickable || !this.editable){
14978 return this.inputEl();
14981 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14985 getAutoCreateTouchView : function()
14990 cls: 'form-group' //input-group
14996 type : this.inputType,
14997 cls : 'form-control x-combo-noedit',
14998 autocomplete: 'new-password',
14999 placeholder : this.placeholder || '',
15004 input.name = this.name;
15008 input.cls += ' input-' + this.size;
15011 if (this.disabled) {
15012 input.disabled = true;
15023 inputblock.cls += ' input-group';
15025 inputblock.cn.unshift({
15027 cls : 'input-group-addon',
15032 if(this.removable && !this.multiple){
15033 inputblock.cls += ' roo-removable';
15035 inputblock.cn.push({
15038 cls : 'roo-combo-removable-btn close'
15042 if(this.hasFeedback && !this.allowBlank){
15044 inputblock.cls += ' has-feedback';
15046 inputblock.cn.push({
15048 cls: 'glyphicon form-control-feedback'
15055 inputblock.cls += (this.before) ? '' : ' input-group';
15057 inputblock.cn.push({
15059 cls : 'input-group-addon',
15070 cls: 'form-hidden-field'
15084 cls: 'form-hidden-field'
15088 cls: 'roo-select2-choices',
15092 cls: 'roo-select2-search-field',
15105 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15111 if(!this.multiple && this.showToggleBtn){
15118 if (this.caret != false) {
15121 cls: 'fa fa-' + this.caret
15128 cls : 'input-group-addon btn dropdown-toggle',
15133 cls: 'combobox-clear',
15147 combobox.cls += ' roo-select2-container-multi';
15150 var align = this.labelAlign || this.parentLabelAlign();
15152 if (align ==='left' && this.fieldLabel.length) {
15157 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15158 tooltip : 'This field is required'
15162 cls : 'control-label',
15163 html : this.fieldLabel
15174 var labelCfg = cfg.cn[1];
15175 var contentCfg = cfg.cn[2];
15178 if(this.indicatorpos == 'right'){
15183 cls : 'control-label',
15187 html : this.fieldLabel
15191 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15192 tooltip : 'This field is required'
15205 labelCfg = cfg.cn[0];
15206 contentCfg = cfg.cn[1];
15211 if(this.labelWidth > 12){
15212 labelCfg.style = "width: " + this.labelWidth + 'px';
15215 if(this.labelWidth < 13 && this.labelmd == 0){
15216 this.labelmd = this.labelWidth;
15219 if(this.labellg > 0){
15220 labelCfg.cls += ' col-lg-' + this.labellg;
15221 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15224 if(this.labelmd > 0){
15225 labelCfg.cls += ' col-md-' + this.labelmd;
15226 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15229 if(this.labelsm > 0){
15230 labelCfg.cls += ' col-sm-' + this.labelsm;
15231 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15234 if(this.labelxs > 0){
15235 labelCfg.cls += ' col-xs-' + this.labelxs;
15236 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15240 } else if ( this.fieldLabel.length) {
15244 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15245 tooltip : 'This field is required'
15249 cls : 'control-label',
15250 html : this.fieldLabel
15261 if(this.indicatorpos == 'right'){
15265 cls : 'control-label',
15266 html : this.fieldLabel,
15270 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15271 tooltip : 'This field is required'
15288 var settings = this;
15290 ['xs','sm','md','lg'].map(function(size){
15291 if (settings[size]) {
15292 cfg.cls += ' col-' + size + '-' + settings[size];
15299 initTouchView : function()
15301 this.renderTouchView();
15303 this.touchViewEl.on('scroll', function(){
15304 this.el.dom.scrollTop = 0;
15307 this.originalValue = this.getValue();
15309 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15311 this.inputEl().on("click", this.showTouchView, this);
15312 if (this.triggerEl) {
15313 this.triggerEl.on("click", this.showTouchView, this);
15317 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15318 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15320 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15322 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15323 this.store.on('load', this.onTouchViewLoad, this);
15324 this.store.on('loadexception', this.onTouchViewLoadException, this);
15326 if(this.hiddenName){
15328 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15330 this.hiddenField.dom.value =
15331 this.hiddenValue !== undefined ? this.hiddenValue :
15332 this.value !== undefined ? this.value : '';
15334 this.el.dom.removeAttribute('name');
15335 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15339 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15340 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15343 if(this.removable && !this.multiple){
15344 var close = this.closeTriggerEl();
15346 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15347 close.on('click', this.removeBtnClick, this, close);
15351 * fix the bug in Safari iOS8
15353 this.inputEl().on("focus", function(e){
15354 document.activeElement.blur();
15357 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15364 renderTouchView : function()
15366 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15367 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15369 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15370 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15372 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15373 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15374 this.touchViewBodyEl.setStyle('overflow', 'auto');
15376 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15377 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15379 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15380 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15384 showTouchView : function()
15390 this.touchViewHeaderEl.hide();
15392 if(this.modalTitle.length){
15393 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15394 this.touchViewHeaderEl.show();
15397 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15398 this.touchViewEl.show();
15400 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15402 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15403 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15405 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15407 if(this.modalTitle.length){
15408 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15411 this.touchViewBodyEl.setHeight(bodyHeight);
15415 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15417 this.touchViewEl.addClass('in');
15420 if(this._touchViewMask){
15421 Roo.get(document.body).addClass("x-body-masked");
15422 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15423 this._touchViewMask.setStyle('z-index', 10000);
15424 this._touchViewMask.addClass('show');
15427 this.doTouchViewQuery();
15431 hideTouchView : function()
15433 this.touchViewEl.removeClass('in');
15437 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15439 this.touchViewEl.setStyle('display', 'none');
15442 if(this._touchViewMask){
15443 this._touchViewMask.removeClass('show');
15444 Roo.get(document.body).removeClass("x-body-masked");
15448 setTouchViewValue : function()
15455 Roo.each(this.tickItems, function(o){
15460 this.hideTouchView();
15463 doTouchViewQuery : function()
15472 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15476 if(!this.alwaysQuery || this.mode == 'local'){
15477 this.onTouchViewLoad();
15484 onTouchViewBeforeLoad : function(combo,opts)
15490 onTouchViewLoad : function()
15492 if(this.store.getCount() < 1){
15493 this.onTouchViewEmptyResults();
15497 this.clearTouchView();
15499 var rawValue = this.getRawValue();
15501 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15503 this.tickItems = [];
15505 this.store.data.each(function(d, rowIndex){
15506 var row = this.touchViewListGroup.createChild(template);
15508 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15509 row.addClass(d.data.cls);
15512 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15515 html : d.data[this.displayField]
15518 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15519 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15522 row.removeClass('selected');
15523 if(!this.multiple && this.valueField &&
15524 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15527 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15528 row.addClass('selected');
15531 if(this.multiple && this.valueField &&
15532 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15536 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15537 this.tickItems.push(d.data);
15540 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15544 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15546 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15548 if(this.modalTitle.length){
15549 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15552 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15554 if(this.mobile_restrict_height && listHeight < bodyHeight){
15555 this.touchViewBodyEl.setHeight(listHeight);
15560 if(firstChecked && listHeight > bodyHeight){
15561 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15566 onTouchViewLoadException : function()
15568 this.hideTouchView();
15571 onTouchViewEmptyResults : function()
15573 this.clearTouchView();
15575 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15577 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15581 clearTouchView : function()
15583 this.touchViewListGroup.dom.innerHTML = '';
15586 onTouchViewClick : function(e, el, o)
15588 e.preventDefault();
15591 var rowIndex = o.rowIndex;
15593 var r = this.store.getAt(rowIndex);
15595 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15597 if(!this.multiple){
15598 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15599 c.dom.removeAttribute('checked');
15602 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15604 this.setFromData(r.data);
15606 var close = this.closeTriggerEl();
15612 this.hideTouchView();
15614 this.fireEvent('select', this, r, rowIndex);
15619 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15620 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15621 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15625 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15626 this.addItem(r.data);
15627 this.tickItems.push(r.data);
15631 getAutoCreateNativeIOS : function()
15634 cls: 'form-group' //input-group,
15639 cls : 'roo-ios-select'
15643 combobox.name = this.name;
15646 if (this.disabled) {
15647 combobox.disabled = true;
15650 var settings = this;
15652 ['xs','sm','md','lg'].map(function(size){
15653 if (settings[size]) {
15654 cfg.cls += ' col-' + size + '-' + settings[size];
15664 initIOSView : function()
15666 this.store.on('load', this.onIOSViewLoad, this);
15671 onIOSViewLoad : function()
15673 if(this.store.getCount() < 1){
15677 this.clearIOSView();
15679 if(this.allowBlank) {
15681 var default_text = '-- SELECT --';
15683 if(this.placeholder.length){
15684 default_text = this.placeholder;
15687 if(this.emptyTitle.length){
15688 default_text += ' - ' + this.emptyTitle + ' -';
15691 var opt = this.inputEl().createChild({
15694 html : default_text
15698 o[this.valueField] = 0;
15699 o[this.displayField] = default_text;
15701 this.ios_options.push({
15708 this.store.data.each(function(d, rowIndex){
15712 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15713 html = d.data[this.displayField];
15718 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15719 value = d.data[this.valueField];
15728 if(this.value == d.data[this.valueField]){
15729 option['selected'] = true;
15732 var opt = this.inputEl().createChild(option);
15734 this.ios_options.push({
15741 this.inputEl().on('change', function(){
15742 this.fireEvent('select', this);
15747 clearIOSView: function()
15749 this.inputEl().dom.innerHTML = '';
15751 this.ios_options = [];
15754 setIOSValue: function(v)
15758 if(!this.ios_options){
15762 Roo.each(this.ios_options, function(opts){
15764 opts.el.dom.removeAttribute('selected');
15766 if(opts.data[this.valueField] != v){
15770 opts.el.dom.setAttribute('selected', true);
15776 * @cfg {Boolean} grow
15780 * @cfg {Number} growMin
15784 * @cfg {Number} growMax
15793 Roo.apply(Roo.bootstrap.ComboBox, {
15797 cls: 'modal-header',
15819 cls: 'list-group-item',
15823 cls: 'roo-combobox-list-group-item-value'
15827 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15841 listItemCheckbox : {
15843 cls: 'list-group-item',
15847 cls: 'roo-combobox-list-group-item-value'
15851 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15867 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15872 cls: 'modal-footer',
15880 cls: 'col-xs-6 text-left',
15883 cls: 'btn btn-danger roo-touch-view-cancel',
15889 cls: 'col-xs-6 text-right',
15892 cls: 'btn btn-success roo-touch-view-ok',
15903 Roo.apply(Roo.bootstrap.ComboBox, {
15905 touchViewTemplate : {
15907 cls: 'modal fade roo-combobox-touch-view',
15911 cls: 'modal-dialog',
15912 style : 'position:fixed', // we have to fix position....
15916 cls: 'modal-content',
15918 Roo.bootstrap.ComboBox.header,
15919 Roo.bootstrap.ComboBox.body,
15920 Roo.bootstrap.ComboBox.footer
15929 * Ext JS Library 1.1.1
15930 * Copyright(c) 2006-2007, Ext JS, LLC.
15932 * Originally Released Under LGPL - original licence link has changed is not relivant.
15935 * <script type="text/javascript">
15940 * @extends Roo.util.Observable
15941 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15942 * This class also supports single and multi selection modes. <br>
15943 * Create a data model bound view:
15945 var store = new Roo.data.Store(...);
15947 var view = new Roo.View({
15949 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15951 singleSelect: true,
15952 selectedClass: "ydataview-selected",
15956 // listen for node click?
15957 view.on("click", function(vw, index, node, e){
15958 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15962 dataModel.load("foobar.xml");
15964 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15966 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15967 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15969 * Note: old style constructor is still suported (container, template, config)
15972 * Create a new View
15973 * @param {Object} config The config object
15976 Roo.View = function(config, depreciated_tpl, depreciated_config){
15978 this.parent = false;
15980 if (typeof(depreciated_tpl) == 'undefined') {
15981 // new way.. - universal constructor.
15982 Roo.apply(this, config);
15983 this.el = Roo.get(this.el);
15986 this.el = Roo.get(config);
15987 this.tpl = depreciated_tpl;
15988 Roo.apply(this, depreciated_config);
15990 this.wrapEl = this.el.wrap().wrap();
15991 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15994 if(typeof(this.tpl) == "string"){
15995 this.tpl = new Roo.Template(this.tpl);
15997 // support xtype ctors..
15998 this.tpl = new Roo.factory(this.tpl, Roo);
16002 this.tpl.compile();
16007 * @event beforeclick
16008 * Fires before a click is processed. Returns false to cancel the default action.
16009 * @param {Roo.View} this
16010 * @param {Number} index The index of the target node
16011 * @param {HTMLElement} node The target node
16012 * @param {Roo.EventObject} e The raw event object
16014 "beforeclick" : true,
16017 * Fires when a template node is clicked.
16018 * @param {Roo.View} this
16019 * @param {Number} index The index of the target node
16020 * @param {HTMLElement} node The target node
16021 * @param {Roo.EventObject} e The raw event object
16026 * Fires when a template node is double clicked.
16027 * @param {Roo.View} this
16028 * @param {Number} index The index of the target node
16029 * @param {HTMLElement} node The target node
16030 * @param {Roo.EventObject} e The raw event object
16034 * @event contextmenu
16035 * Fires when a template node is right clicked.
16036 * @param {Roo.View} this
16037 * @param {Number} index The index of the target node
16038 * @param {HTMLElement} node The target node
16039 * @param {Roo.EventObject} e The raw event object
16041 "contextmenu" : true,
16043 * @event selectionchange
16044 * Fires when the selected nodes change.
16045 * @param {Roo.View} this
16046 * @param {Array} selections Array of the selected nodes
16048 "selectionchange" : true,
16051 * @event beforeselect
16052 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16053 * @param {Roo.View} this
16054 * @param {HTMLElement} node The node to be selected
16055 * @param {Array} selections Array of currently selected nodes
16057 "beforeselect" : true,
16059 * @event preparedata
16060 * Fires on every row to render, to allow you to change the data.
16061 * @param {Roo.View} this
16062 * @param {Object} data to be rendered (change this)
16064 "preparedata" : true
16072 "click": this.onClick,
16073 "dblclick": this.onDblClick,
16074 "contextmenu": this.onContextMenu,
16078 this.selections = [];
16080 this.cmp = new Roo.CompositeElementLite([]);
16082 this.store = Roo.factory(this.store, Roo.data);
16083 this.setStore(this.store, true);
16086 if ( this.footer && this.footer.xtype) {
16088 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16090 this.footer.dataSource = this.store;
16091 this.footer.container = fctr;
16092 this.footer = Roo.factory(this.footer, Roo);
16093 fctr.insertFirst(this.el);
16095 // this is a bit insane - as the paging toolbar seems to detach the el..
16096 // dom.parentNode.parentNode.parentNode
16097 // they get detached?
16101 Roo.View.superclass.constructor.call(this);
16106 Roo.extend(Roo.View, Roo.util.Observable, {
16109 * @cfg {Roo.data.Store} store Data store to load data from.
16114 * @cfg {String|Roo.Element} el The container element.
16119 * @cfg {String|Roo.Template} tpl The template used by this View
16123 * @cfg {String} dataName the named area of the template to use as the data area
16124 * Works with domtemplates roo-name="name"
16128 * @cfg {String} selectedClass The css class to add to selected nodes
16130 selectedClass : "x-view-selected",
16132 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16137 * @cfg {String} text to display on mask (default Loading)
16141 * @cfg {Boolean} multiSelect Allow multiple selection
16143 multiSelect : false,
16145 * @cfg {Boolean} singleSelect Allow single selection
16147 singleSelect: false,
16150 * @cfg {Boolean} toggleSelect - selecting
16152 toggleSelect : false,
16155 * @cfg {Boolean} tickable - selecting
16160 * Returns the element this view is bound to.
16161 * @return {Roo.Element}
16163 getEl : function(){
16164 return this.wrapEl;
16170 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16172 refresh : function(){
16173 //Roo.log('refresh');
16176 // if we are using something like 'domtemplate', then
16177 // the what gets used is:
16178 // t.applySubtemplate(NAME, data, wrapping data..)
16179 // the outer template then get' applied with
16180 // the store 'extra data'
16181 // and the body get's added to the
16182 // roo-name="data" node?
16183 // <span class='roo-tpl-{name}'></span> ?????
16187 this.clearSelections();
16188 this.el.update("");
16190 var records = this.store.getRange();
16191 if(records.length < 1) {
16193 // is this valid?? = should it render a template??
16195 this.el.update(this.emptyText);
16199 if (this.dataName) {
16200 this.el.update(t.apply(this.store.meta)); //????
16201 el = this.el.child('.roo-tpl-' + this.dataName);
16204 for(var i = 0, len = records.length; i < len; i++){
16205 var data = this.prepareData(records[i].data, i, records[i]);
16206 this.fireEvent("preparedata", this, data, i, records[i]);
16208 var d = Roo.apply({}, data);
16211 Roo.apply(d, {'roo-id' : Roo.id()});
16215 Roo.each(this.parent.item, function(item){
16216 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16219 Roo.apply(d, {'roo-data-checked' : 'checked'});
16223 html[html.length] = Roo.util.Format.trim(
16225 t.applySubtemplate(this.dataName, d, this.store.meta) :
16232 el.update(html.join(""));
16233 this.nodes = el.dom.childNodes;
16234 this.updateIndexes(0);
16239 * Function to override to reformat the data that is sent to
16240 * the template for each node.
16241 * DEPRICATED - use the preparedata event handler.
16242 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16243 * a JSON object for an UpdateManager bound view).
16245 prepareData : function(data, index, record)
16247 this.fireEvent("preparedata", this, data, index, record);
16251 onUpdate : function(ds, record){
16252 // Roo.log('on update');
16253 this.clearSelections();
16254 var index = this.store.indexOf(record);
16255 var n = this.nodes[index];
16256 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16257 n.parentNode.removeChild(n);
16258 this.updateIndexes(index, index);
16264 onAdd : function(ds, records, index)
16266 //Roo.log(['on Add', ds, records, index] );
16267 this.clearSelections();
16268 if(this.nodes.length == 0){
16272 var n = this.nodes[index];
16273 for(var i = 0, len = records.length; i < len; i++){
16274 var d = this.prepareData(records[i].data, i, records[i]);
16276 this.tpl.insertBefore(n, d);
16279 this.tpl.append(this.el, d);
16282 this.updateIndexes(index);
16285 onRemove : function(ds, record, index){
16286 // Roo.log('onRemove');
16287 this.clearSelections();
16288 var el = this.dataName ?
16289 this.el.child('.roo-tpl-' + this.dataName) :
16292 el.dom.removeChild(this.nodes[index]);
16293 this.updateIndexes(index);
16297 * Refresh an individual node.
16298 * @param {Number} index
16300 refreshNode : function(index){
16301 this.onUpdate(this.store, this.store.getAt(index));
16304 updateIndexes : function(startIndex, endIndex){
16305 var ns = this.nodes;
16306 startIndex = startIndex || 0;
16307 endIndex = endIndex || ns.length - 1;
16308 for(var i = startIndex; i <= endIndex; i++){
16309 ns[i].nodeIndex = i;
16314 * Changes the data store this view uses and refresh the view.
16315 * @param {Store} store
16317 setStore : function(store, initial){
16318 if(!initial && this.store){
16319 this.store.un("datachanged", this.refresh);
16320 this.store.un("add", this.onAdd);
16321 this.store.un("remove", this.onRemove);
16322 this.store.un("update", this.onUpdate);
16323 this.store.un("clear", this.refresh);
16324 this.store.un("beforeload", this.onBeforeLoad);
16325 this.store.un("load", this.onLoad);
16326 this.store.un("loadexception", this.onLoad);
16330 store.on("datachanged", this.refresh, this);
16331 store.on("add", this.onAdd, this);
16332 store.on("remove", this.onRemove, this);
16333 store.on("update", this.onUpdate, this);
16334 store.on("clear", this.refresh, this);
16335 store.on("beforeload", this.onBeforeLoad, this);
16336 store.on("load", this.onLoad, this);
16337 store.on("loadexception", this.onLoad, this);
16345 * onbeforeLoad - masks the loading area.
16348 onBeforeLoad : function(store,opts)
16350 //Roo.log('onBeforeLoad');
16352 this.el.update("");
16354 this.el.mask(this.mask ? this.mask : "Loading" );
16356 onLoad : function ()
16363 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16364 * @param {HTMLElement} node
16365 * @return {HTMLElement} The template node
16367 findItemFromChild : function(node){
16368 var el = this.dataName ?
16369 this.el.child('.roo-tpl-' + this.dataName,true) :
16372 if(!node || node.parentNode == el){
16375 var p = node.parentNode;
16376 while(p && p != el){
16377 if(p.parentNode == el){
16386 onClick : function(e){
16387 var item = this.findItemFromChild(e.getTarget());
16389 var index = this.indexOf(item);
16390 if(this.onItemClick(item, index, e) !== false){
16391 this.fireEvent("click", this, index, item, e);
16394 this.clearSelections();
16399 onContextMenu : function(e){
16400 var item = this.findItemFromChild(e.getTarget());
16402 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16407 onDblClick : function(e){
16408 var item = this.findItemFromChild(e.getTarget());
16410 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16414 onItemClick : function(item, index, e)
16416 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16419 if (this.toggleSelect) {
16420 var m = this.isSelected(item) ? 'unselect' : 'select';
16423 _t[m](item, true, false);
16426 if(this.multiSelect || this.singleSelect){
16427 if(this.multiSelect && e.shiftKey && this.lastSelection){
16428 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16430 this.select(item, this.multiSelect && e.ctrlKey);
16431 this.lastSelection = item;
16434 if(!this.tickable){
16435 e.preventDefault();
16443 * Get the number of selected nodes.
16446 getSelectionCount : function(){
16447 return this.selections.length;
16451 * Get the currently selected nodes.
16452 * @return {Array} An array of HTMLElements
16454 getSelectedNodes : function(){
16455 return this.selections;
16459 * Get the indexes of the selected nodes.
16462 getSelectedIndexes : function(){
16463 var indexes = [], s = this.selections;
16464 for(var i = 0, len = s.length; i < len; i++){
16465 indexes.push(s[i].nodeIndex);
16471 * Clear all selections
16472 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16474 clearSelections : function(suppressEvent){
16475 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16476 this.cmp.elements = this.selections;
16477 this.cmp.removeClass(this.selectedClass);
16478 this.selections = [];
16479 if(!suppressEvent){
16480 this.fireEvent("selectionchange", this, this.selections);
16486 * Returns true if the passed node is selected
16487 * @param {HTMLElement/Number} node The node or node index
16488 * @return {Boolean}
16490 isSelected : function(node){
16491 var s = this.selections;
16495 node = this.getNode(node);
16496 return s.indexOf(node) !== -1;
16501 * @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
16502 * @param {Boolean} keepExisting (optional) true to keep existing selections
16503 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16505 select : function(nodeInfo, keepExisting, suppressEvent){
16506 if(nodeInfo instanceof Array){
16508 this.clearSelections(true);
16510 for(var i = 0, len = nodeInfo.length; i < len; i++){
16511 this.select(nodeInfo[i], true, true);
16515 var node = this.getNode(nodeInfo);
16516 if(!node || this.isSelected(node)){
16517 return; // already selected.
16520 this.clearSelections(true);
16523 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16524 Roo.fly(node).addClass(this.selectedClass);
16525 this.selections.push(node);
16526 if(!suppressEvent){
16527 this.fireEvent("selectionchange", this, this.selections);
16535 * @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
16536 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16537 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16539 unselect : function(nodeInfo, keepExisting, suppressEvent)
16541 if(nodeInfo instanceof Array){
16542 Roo.each(this.selections, function(s) {
16543 this.unselect(s, nodeInfo);
16547 var node = this.getNode(nodeInfo);
16548 if(!node || !this.isSelected(node)){
16549 //Roo.log("not selected");
16550 return; // not selected.
16554 Roo.each(this.selections, function(s) {
16556 Roo.fly(node).removeClass(this.selectedClass);
16563 this.selections= ns;
16564 this.fireEvent("selectionchange", this, this.selections);
16568 * Gets a template node.
16569 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16570 * @return {HTMLElement} The node or null if it wasn't found
16572 getNode : function(nodeInfo){
16573 if(typeof nodeInfo == "string"){
16574 return document.getElementById(nodeInfo);
16575 }else if(typeof nodeInfo == "number"){
16576 return this.nodes[nodeInfo];
16582 * Gets a range template nodes.
16583 * @param {Number} startIndex
16584 * @param {Number} endIndex
16585 * @return {Array} An array of nodes
16587 getNodes : function(start, end){
16588 var ns = this.nodes;
16589 start = start || 0;
16590 end = typeof end == "undefined" ? ns.length - 1 : end;
16593 for(var i = start; i <= end; i++){
16597 for(var i = start; i >= end; i--){
16605 * Finds the index of the passed node
16606 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16607 * @return {Number} The index of the node or -1
16609 indexOf : function(node){
16610 node = this.getNode(node);
16611 if(typeof node.nodeIndex == "number"){
16612 return node.nodeIndex;
16614 var ns = this.nodes;
16615 for(var i = 0, len = ns.length; i < len; i++){
16626 * based on jquery fullcalendar
16630 Roo.bootstrap = Roo.bootstrap || {};
16632 * @class Roo.bootstrap.Calendar
16633 * @extends Roo.bootstrap.Component
16634 * Bootstrap Calendar class
16635 * @cfg {Boolean} loadMask (true|false) default false
16636 * @cfg {Object} header generate the user specific header of the calendar, default false
16639 * Create a new Container
16640 * @param {Object} config The config object
16645 Roo.bootstrap.Calendar = function(config){
16646 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16650 * Fires when a date is selected
16651 * @param {DatePicker} this
16652 * @param {Date} date The selected date
16656 * @event monthchange
16657 * Fires when the displayed month changes
16658 * @param {DatePicker} this
16659 * @param {Date} date The selected month
16661 'monthchange': true,
16663 * @event evententer
16664 * Fires when mouse over an event
16665 * @param {Calendar} this
16666 * @param {event} Event
16668 'evententer': true,
16670 * @event eventleave
16671 * Fires when the mouse leaves an
16672 * @param {Calendar} this
16675 'eventleave': true,
16677 * @event eventclick
16678 * Fires when the mouse click an
16679 * @param {Calendar} this
16688 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16691 * @cfg {Number} startDay
16692 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16700 getAutoCreate : function(){
16703 var fc_button = function(name, corner, style, content ) {
16704 return Roo.apply({},{
16706 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16708 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16711 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16722 style : 'width:100%',
16729 cls : 'fc-header-left',
16731 fc_button('prev', 'left', 'arrow', '‹' ),
16732 fc_button('next', 'right', 'arrow', '›' ),
16733 { tag: 'span', cls: 'fc-header-space' },
16734 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16742 cls : 'fc-header-center',
16746 cls: 'fc-header-title',
16749 html : 'month / year'
16757 cls : 'fc-header-right',
16759 /* fc_button('month', 'left', '', 'month' ),
16760 fc_button('week', '', '', 'week' ),
16761 fc_button('day', 'right', '', 'day' )
16773 header = this.header;
16776 var cal_heads = function() {
16778 // fixme - handle this.
16780 for (var i =0; i < Date.dayNames.length; i++) {
16781 var d = Date.dayNames[i];
16784 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16785 html : d.substring(0,3)
16789 ret[0].cls += ' fc-first';
16790 ret[6].cls += ' fc-last';
16793 var cal_cell = function(n) {
16796 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16801 cls: 'fc-day-number',
16805 cls: 'fc-day-content',
16809 style: 'position: relative;' // height: 17px;
16821 var cal_rows = function() {
16824 for (var r = 0; r < 6; r++) {
16831 for (var i =0; i < Date.dayNames.length; i++) {
16832 var d = Date.dayNames[i];
16833 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16836 row.cn[0].cls+=' fc-first';
16837 row.cn[0].cn[0].style = 'min-height:90px';
16838 row.cn[6].cls+=' fc-last';
16842 ret[0].cls += ' fc-first';
16843 ret[4].cls += ' fc-prev-last';
16844 ret[5].cls += ' fc-last';
16851 cls: 'fc-border-separate',
16852 style : 'width:100%',
16860 cls : 'fc-first fc-last',
16878 cls : 'fc-content',
16879 style : "position: relative;",
16882 cls : 'fc-view fc-view-month fc-grid',
16883 style : 'position: relative',
16884 unselectable : 'on',
16887 cls : 'fc-event-container',
16888 style : 'position:absolute;z-index:8;top:0;left:0;'
16906 initEvents : function()
16909 throw "can not find store for calendar";
16915 style: "text-align:center",
16919 style: "background-color:white;width:50%;margin:250 auto",
16923 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16934 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16936 var size = this.el.select('.fc-content', true).first().getSize();
16937 this.maskEl.setSize(size.width, size.height);
16938 this.maskEl.enableDisplayMode("block");
16939 if(!this.loadMask){
16940 this.maskEl.hide();
16943 this.store = Roo.factory(this.store, Roo.data);
16944 this.store.on('load', this.onLoad, this);
16945 this.store.on('beforeload', this.onBeforeLoad, this);
16949 this.cells = this.el.select('.fc-day',true);
16950 //Roo.log(this.cells);
16951 this.textNodes = this.el.query('.fc-day-number');
16952 this.cells.addClassOnOver('fc-state-hover');
16954 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16955 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16956 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16957 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16959 this.on('monthchange', this.onMonthChange, this);
16961 this.update(new Date().clearTime());
16964 resize : function() {
16965 var sz = this.el.getSize();
16967 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16968 this.el.select('.fc-day-content div',true).setHeight(34);
16973 showPrevMonth : function(e){
16974 this.update(this.activeDate.add("mo", -1));
16976 showToday : function(e){
16977 this.update(new Date().clearTime());
16980 showNextMonth : function(e){
16981 this.update(this.activeDate.add("mo", 1));
16985 showPrevYear : function(){
16986 this.update(this.activeDate.add("y", -1));
16990 showNextYear : function(){
16991 this.update(this.activeDate.add("y", 1));
16996 update : function(date)
16998 var vd = this.activeDate;
16999 this.activeDate = date;
17000 // if(vd && this.el){
17001 // var t = date.getTime();
17002 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17003 // Roo.log('using add remove');
17005 // this.fireEvent('monthchange', this, date);
17007 // this.cells.removeClass("fc-state-highlight");
17008 // this.cells.each(function(c){
17009 // if(c.dateValue == t){
17010 // c.addClass("fc-state-highlight");
17011 // setTimeout(function(){
17012 // try{c.dom.firstChild.focus();}catch(e){}
17022 var days = date.getDaysInMonth();
17024 var firstOfMonth = date.getFirstDateOfMonth();
17025 var startingPos = firstOfMonth.getDay()-this.startDay;
17027 if(startingPos < this.startDay){
17031 var pm = date.add(Date.MONTH, -1);
17032 var prevStart = pm.getDaysInMonth()-startingPos;
17034 this.cells = this.el.select('.fc-day',true);
17035 this.textNodes = this.el.query('.fc-day-number');
17036 this.cells.addClassOnOver('fc-state-hover');
17038 var cells = this.cells.elements;
17039 var textEls = this.textNodes;
17041 Roo.each(cells, function(cell){
17042 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17045 days += startingPos;
17047 // convert everything to numbers so it's fast
17048 var day = 86400000;
17049 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17052 //Roo.log(prevStart);
17054 var today = new Date().clearTime().getTime();
17055 var sel = date.clearTime().getTime();
17056 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17057 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17058 var ddMatch = this.disabledDatesRE;
17059 var ddText = this.disabledDatesText;
17060 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17061 var ddaysText = this.disabledDaysText;
17062 var format = this.format;
17064 var setCellClass = function(cal, cell){
17068 //Roo.log('set Cell Class');
17070 var t = d.getTime();
17074 cell.dateValue = t;
17076 cell.className += " fc-today";
17077 cell.className += " fc-state-highlight";
17078 cell.title = cal.todayText;
17081 // disable highlight in other month..
17082 //cell.className += " fc-state-highlight";
17087 cell.className = " fc-state-disabled";
17088 cell.title = cal.minText;
17092 cell.className = " fc-state-disabled";
17093 cell.title = cal.maxText;
17097 if(ddays.indexOf(d.getDay()) != -1){
17098 cell.title = ddaysText;
17099 cell.className = " fc-state-disabled";
17102 if(ddMatch && format){
17103 var fvalue = d.dateFormat(format);
17104 if(ddMatch.test(fvalue)){
17105 cell.title = ddText.replace("%0", fvalue);
17106 cell.className = " fc-state-disabled";
17110 if (!cell.initialClassName) {
17111 cell.initialClassName = cell.dom.className;
17114 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17119 for(; i < startingPos; i++) {
17120 textEls[i].innerHTML = (++prevStart);
17121 d.setDate(d.getDate()+1);
17123 cells[i].className = "fc-past fc-other-month";
17124 setCellClass(this, cells[i]);
17129 for(; i < days; i++){
17130 intDay = i - startingPos + 1;
17131 textEls[i].innerHTML = (intDay);
17132 d.setDate(d.getDate()+1);
17134 cells[i].className = ''; // "x-date-active";
17135 setCellClass(this, cells[i]);
17139 for(; i < 42; i++) {
17140 textEls[i].innerHTML = (++extraDays);
17141 d.setDate(d.getDate()+1);
17143 cells[i].className = "fc-future fc-other-month";
17144 setCellClass(this, cells[i]);
17147 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17149 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17151 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17152 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17154 if(totalRows != 6){
17155 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17156 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17159 this.fireEvent('monthchange', this, date);
17163 if(!this.internalRender){
17164 var main = this.el.dom.firstChild;
17165 var w = main.offsetWidth;
17166 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17167 Roo.fly(main).setWidth(w);
17168 this.internalRender = true;
17169 // opera does not respect the auto grow header center column
17170 // then, after it gets a width opera refuses to recalculate
17171 // without a second pass
17172 if(Roo.isOpera && !this.secondPass){
17173 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17174 this.secondPass = true;
17175 this.update.defer(10, this, [date]);
17182 findCell : function(dt) {
17183 dt = dt.clearTime().getTime();
17185 this.cells.each(function(c){
17186 //Roo.log("check " +c.dateValue + '?=' + dt);
17187 if(c.dateValue == dt){
17197 findCells : function(ev) {
17198 var s = ev.start.clone().clearTime().getTime();
17200 var e= ev.end.clone().clearTime().getTime();
17203 this.cells.each(function(c){
17204 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17206 if(c.dateValue > e){
17209 if(c.dateValue < s){
17218 // findBestRow: function(cells)
17222 // for (var i =0 ; i < cells.length;i++) {
17223 // ret = Math.max(cells[i].rows || 0,ret);
17230 addItem : function(ev)
17232 // look for vertical location slot in
17233 var cells = this.findCells(ev);
17235 // ev.row = this.findBestRow(cells);
17237 // work out the location.
17241 for(var i =0; i < cells.length; i++) {
17243 cells[i].row = cells[0].row;
17246 cells[i].row = cells[i].row + 1;
17256 if (crow.start.getY() == cells[i].getY()) {
17258 crow.end = cells[i];
17275 cells[0].events.push(ev);
17277 this.calevents.push(ev);
17280 clearEvents: function() {
17282 if(!this.calevents){
17286 Roo.each(this.cells.elements, function(c){
17292 Roo.each(this.calevents, function(e) {
17293 Roo.each(e.els, function(el) {
17294 el.un('mouseenter' ,this.onEventEnter, this);
17295 el.un('mouseleave' ,this.onEventLeave, this);
17300 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17306 renderEvents: function()
17310 this.cells.each(function(c) {
17319 if(c.row != c.events.length){
17320 r = 4 - (4 - (c.row - c.events.length));
17323 c.events = ev.slice(0, r);
17324 c.more = ev.slice(r);
17326 if(c.more.length && c.more.length == 1){
17327 c.events.push(c.more.pop());
17330 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17334 this.cells.each(function(c) {
17336 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17339 for (var e = 0; e < c.events.length; e++){
17340 var ev = c.events[e];
17341 var rows = ev.rows;
17343 for(var i = 0; i < rows.length; i++) {
17345 // how many rows should it span..
17348 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17349 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17351 unselectable : "on",
17354 cls: 'fc-event-inner',
17358 // cls: 'fc-event-time',
17359 // html : cells.length > 1 ? '' : ev.time
17363 cls: 'fc-event-title',
17364 html : String.format('{0}', ev.title)
17371 cls: 'ui-resizable-handle ui-resizable-e',
17372 html : '  '
17379 cfg.cls += ' fc-event-start';
17381 if ((i+1) == rows.length) {
17382 cfg.cls += ' fc-event-end';
17385 var ctr = _this.el.select('.fc-event-container',true).first();
17386 var cg = ctr.createChild(cfg);
17388 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17389 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17391 var r = (c.more.length) ? 1 : 0;
17392 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17393 cg.setWidth(ebox.right - sbox.x -2);
17395 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17396 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17397 cg.on('click', _this.onEventClick, _this, ev);
17408 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17409 style : 'position: absolute',
17410 unselectable : "on",
17413 cls: 'fc-event-inner',
17417 cls: 'fc-event-title',
17425 cls: 'ui-resizable-handle ui-resizable-e',
17426 html : '  '
17432 var ctr = _this.el.select('.fc-event-container',true).first();
17433 var cg = ctr.createChild(cfg);
17435 var sbox = c.select('.fc-day-content',true).first().getBox();
17436 var ebox = c.select('.fc-day-content',true).first().getBox();
17438 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17439 cg.setWidth(ebox.right - sbox.x -2);
17441 cg.on('click', _this.onMoreEventClick, _this, c.more);
17451 onEventEnter: function (e, el,event,d) {
17452 this.fireEvent('evententer', this, el, event);
17455 onEventLeave: function (e, el,event,d) {
17456 this.fireEvent('eventleave', this, el, event);
17459 onEventClick: function (e, el,event,d) {
17460 this.fireEvent('eventclick', this, el, event);
17463 onMonthChange: function () {
17467 onMoreEventClick: function(e, el, more)
17471 this.calpopover.placement = 'right';
17472 this.calpopover.setTitle('More');
17474 this.calpopover.setContent('');
17476 var ctr = this.calpopover.el.select('.popover-content', true).first();
17478 Roo.each(more, function(m){
17480 cls : 'fc-event-hori fc-event-draggable',
17483 var cg = ctr.createChild(cfg);
17485 cg.on('click', _this.onEventClick, _this, m);
17488 this.calpopover.show(el);
17493 onLoad: function ()
17495 this.calevents = [];
17498 if(this.store.getCount() > 0){
17499 this.store.data.each(function(d){
17502 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17503 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17504 time : d.data.start_time,
17505 title : d.data.title,
17506 description : d.data.description,
17507 venue : d.data.venue
17512 this.renderEvents();
17514 if(this.calevents.length && this.loadMask){
17515 this.maskEl.hide();
17519 onBeforeLoad: function()
17521 this.clearEvents();
17523 this.maskEl.show();
17537 * @class Roo.bootstrap.Popover
17538 * @extends Roo.bootstrap.Component
17539 * Bootstrap Popover class
17540 * @cfg {String} html contents of the popover (or false to use children..)
17541 * @cfg {String} title of popover (or false to hide)
17542 * @cfg {String} placement how it is placed
17543 * @cfg {String} trigger click || hover (or false to trigger manually)
17544 * @cfg {String} over what (parent or false to trigger manually.)
17545 * @cfg {Number} delay - delay before showing
17548 * Create a new Popover
17549 * @param {Object} config The config object
17552 Roo.bootstrap.Popover = function(config){
17553 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17559 * After the popover show
17561 * @param {Roo.bootstrap.Popover} this
17566 * After the popover hide
17568 * @param {Roo.bootstrap.Popover} this
17574 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17576 title: 'Fill in a title',
17579 placement : 'right',
17580 trigger : 'hover', // hover
17586 can_build_overlaid : false,
17588 getChildContainer : function()
17590 return this.el.select('.popover-content',true).first();
17593 getAutoCreate : function(){
17596 cls : 'popover roo-dynamic',
17597 style: 'display:block',
17603 cls : 'popover-inner',
17607 cls: 'popover-title',
17611 cls : 'popover-content',
17622 setTitle: function(str)
17625 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17627 setContent: function(str)
17630 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17632 // as it get's added to the bottom of the page.
17633 onRender : function(ct, position)
17635 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17637 var cfg = Roo.apply({}, this.getAutoCreate());
17641 cfg.cls += ' ' + this.cls;
17644 cfg.style = this.style;
17646 //Roo.log("adding to ");
17647 this.el = Roo.get(document.body).createChild(cfg, position);
17648 // Roo.log(this.el);
17653 initEvents : function()
17655 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17656 this.el.enableDisplayMode('block');
17658 if (this.over === false) {
17661 if (this.triggers === false) {
17664 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17665 var triggers = this.trigger ? this.trigger.split(' ') : [];
17666 Roo.each(triggers, function(trigger) {
17668 if (trigger == 'click') {
17669 on_el.on('click', this.toggle, this);
17670 } else if (trigger != 'manual') {
17671 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17672 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17674 on_el.on(eventIn ,this.enter, this);
17675 on_el.on(eventOut, this.leave, this);
17686 toggle : function () {
17687 this.hoverState == 'in' ? this.leave() : this.enter();
17690 enter : function () {
17692 clearTimeout(this.timeout);
17694 this.hoverState = 'in';
17696 if (!this.delay || !this.delay.show) {
17701 this.timeout = setTimeout(function () {
17702 if (_t.hoverState == 'in') {
17705 }, this.delay.show)
17708 leave : function() {
17709 clearTimeout(this.timeout);
17711 this.hoverState = 'out';
17713 if (!this.delay || !this.delay.hide) {
17718 this.timeout = setTimeout(function () {
17719 if (_t.hoverState == 'out') {
17722 }, this.delay.hide)
17725 show : function (on_el)
17728 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17732 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17733 if (this.html !== false) {
17734 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17736 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17737 if (!this.title.length) {
17738 this.el.select('.popover-title',true).hide();
17741 var placement = typeof this.placement == 'function' ?
17742 this.placement.call(this, this.el, on_el) :
17745 var autoToken = /\s?auto?\s?/i;
17746 var autoPlace = autoToken.test(placement);
17748 placement = placement.replace(autoToken, '') || 'top';
17752 //this.el.setXY([0,0]);
17754 this.el.dom.style.display='block';
17755 this.el.addClass(placement);
17757 //this.el.appendTo(on_el);
17759 var p = this.getPosition();
17760 var box = this.el.getBox();
17765 var align = Roo.bootstrap.Popover.alignment[placement];
17768 this.el.alignTo(on_el, align[0],align[1]);
17769 //var arrow = this.el.select('.arrow',true).first();
17770 //arrow.set(align[2],
17772 this.el.addClass('in');
17775 if (this.el.hasClass('fade')) {
17779 this.hoverState = 'in';
17781 this.fireEvent('show', this);
17786 this.el.setXY([0,0]);
17787 this.el.removeClass('in');
17789 this.hoverState = null;
17791 this.fireEvent('hide', this);
17796 Roo.bootstrap.Popover.alignment = {
17797 'left' : ['r-l', [-10,0], 'right'],
17798 'right' : ['l-r', [10,0], 'left'],
17799 'bottom' : ['t-b', [0,10], 'top'],
17800 'top' : [ 'b-t', [0,-10], 'bottom']
17811 * @class Roo.bootstrap.Progress
17812 * @extends Roo.bootstrap.Component
17813 * Bootstrap Progress class
17814 * @cfg {Boolean} striped striped of the progress bar
17815 * @cfg {Boolean} active animated of the progress bar
17819 * Create a new Progress
17820 * @param {Object} config The config object
17823 Roo.bootstrap.Progress = function(config){
17824 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17827 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17832 getAutoCreate : function(){
17840 cfg.cls += ' progress-striped';
17844 cfg.cls += ' active';
17863 * @class Roo.bootstrap.ProgressBar
17864 * @extends Roo.bootstrap.Component
17865 * Bootstrap ProgressBar class
17866 * @cfg {Number} aria_valuenow aria-value now
17867 * @cfg {Number} aria_valuemin aria-value min
17868 * @cfg {Number} aria_valuemax aria-value max
17869 * @cfg {String} label label for the progress bar
17870 * @cfg {String} panel (success | info | warning | danger )
17871 * @cfg {String} role role of the progress bar
17872 * @cfg {String} sr_only text
17876 * Create a new ProgressBar
17877 * @param {Object} config The config object
17880 Roo.bootstrap.ProgressBar = function(config){
17881 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17884 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17888 aria_valuemax : 100,
17894 getAutoCreate : function()
17899 cls: 'progress-bar',
17900 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17912 cfg.role = this.role;
17915 if(this.aria_valuenow){
17916 cfg['aria-valuenow'] = this.aria_valuenow;
17919 if(this.aria_valuemin){
17920 cfg['aria-valuemin'] = this.aria_valuemin;
17923 if(this.aria_valuemax){
17924 cfg['aria-valuemax'] = this.aria_valuemax;
17927 if(this.label && !this.sr_only){
17928 cfg.html = this.label;
17932 cfg.cls += ' progress-bar-' + this.panel;
17938 update : function(aria_valuenow)
17940 this.aria_valuenow = aria_valuenow;
17942 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17957 * @class Roo.bootstrap.TabGroup
17958 * @extends Roo.bootstrap.Column
17959 * Bootstrap Column class
17960 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17961 * @cfg {Boolean} carousel true to make the group behave like a carousel
17962 * @cfg {Boolean} bullets show bullets for the panels
17963 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17964 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17965 * @cfg {Boolean} showarrow (true|false) show arrow default true
17968 * Create a new TabGroup
17969 * @param {Object} config The config object
17972 Roo.bootstrap.TabGroup = function(config){
17973 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17975 this.navId = Roo.id();
17978 Roo.bootstrap.TabGroup.register(this);
17982 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17985 transition : false,
17990 slideOnTouch : false,
17993 getAutoCreate : function()
17995 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17997 cfg.cls += ' tab-content';
17999 if (this.carousel) {
18000 cfg.cls += ' carousel slide';
18003 cls : 'carousel-inner',
18007 if(this.bullets && !Roo.isTouch){
18010 cls : 'carousel-bullets',
18014 if(this.bullets_cls){
18015 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18022 cfg.cn[0].cn.push(bullets);
18025 if(this.showarrow){
18026 cfg.cn[0].cn.push({
18028 class : 'carousel-arrow',
18032 class : 'carousel-prev',
18036 class : 'fa fa-chevron-left'
18042 class : 'carousel-next',
18046 class : 'fa fa-chevron-right'
18059 initEvents: function()
18061 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18062 // this.el.on("touchstart", this.onTouchStart, this);
18065 if(this.autoslide){
18068 this.slideFn = window.setInterval(function() {
18069 _this.showPanelNext();
18073 if(this.showarrow){
18074 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18075 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18081 // onTouchStart : function(e, el, o)
18083 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18087 // this.showPanelNext();
18091 getChildContainer : function()
18093 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18097 * register a Navigation item
18098 * @param {Roo.bootstrap.NavItem} the navitem to add
18100 register : function(item)
18102 this.tabs.push( item);
18103 item.navId = this.navId; // not really needed..
18108 getActivePanel : function()
18111 Roo.each(this.tabs, function(t) {
18121 getPanelByName : function(n)
18124 Roo.each(this.tabs, function(t) {
18125 if (t.tabId == n) {
18133 indexOfPanel : function(p)
18136 Roo.each(this.tabs, function(t,i) {
18137 if (t.tabId == p.tabId) {
18146 * show a specific panel
18147 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18148 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18150 showPanel : function (pan)
18152 if(this.transition || typeof(pan) == 'undefined'){
18153 Roo.log("waiting for the transitionend");
18157 if (typeof(pan) == 'number') {
18158 pan = this.tabs[pan];
18161 if (typeof(pan) == 'string') {
18162 pan = this.getPanelByName(pan);
18165 var cur = this.getActivePanel();
18168 Roo.log('pan or acitve pan is undefined');
18172 if (pan.tabId == this.getActivePanel().tabId) {
18176 if (false === cur.fireEvent('beforedeactivate')) {
18180 if(this.bullets > 0 && !Roo.isTouch){
18181 this.setActiveBullet(this.indexOfPanel(pan));
18184 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18186 this.transition = true;
18187 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18188 var lr = dir == 'next' ? 'left' : 'right';
18189 pan.el.addClass(dir); // or prev
18190 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18191 cur.el.addClass(lr); // or right
18192 pan.el.addClass(lr);
18195 cur.el.on('transitionend', function() {
18196 Roo.log("trans end?");
18198 pan.el.removeClass([lr,dir]);
18199 pan.setActive(true);
18201 cur.el.removeClass([lr]);
18202 cur.setActive(false);
18204 _this.transition = false;
18206 }, this, { single: true } );
18211 cur.setActive(false);
18212 pan.setActive(true);
18217 showPanelNext : function()
18219 var i = this.indexOfPanel(this.getActivePanel());
18221 if (i >= this.tabs.length - 1 && !this.autoslide) {
18225 if (i >= this.tabs.length - 1 && this.autoslide) {
18229 this.showPanel(this.tabs[i+1]);
18232 showPanelPrev : function()
18234 var i = this.indexOfPanel(this.getActivePanel());
18236 if (i < 1 && !this.autoslide) {
18240 if (i < 1 && this.autoslide) {
18241 i = this.tabs.length;
18244 this.showPanel(this.tabs[i-1]);
18248 addBullet: function()
18250 if(!this.bullets || Roo.isTouch){
18253 var ctr = this.el.select('.carousel-bullets',true).first();
18254 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18255 var bullet = ctr.createChild({
18256 cls : 'bullet bullet-' + i
18257 },ctr.dom.lastChild);
18262 bullet.on('click', (function(e, el, o, ii, t){
18264 e.preventDefault();
18266 this.showPanel(ii);
18268 if(this.autoslide && this.slideFn){
18269 clearInterval(this.slideFn);
18270 this.slideFn = window.setInterval(function() {
18271 _this.showPanelNext();
18275 }).createDelegate(this, [i, bullet], true));
18280 setActiveBullet : function(i)
18286 Roo.each(this.el.select('.bullet', true).elements, function(el){
18287 el.removeClass('selected');
18290 var bullet = this.el.select('.bullet-' + i, true).first();
18296 bullet.addClass('selected');
18307 Roo.apply(Roo.bootstrap.TabGroup, {
18311 * register a Navigation Group
18312 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18314 register : function(navgrp)
18316 this.groups[navgrp.navId] = navgrp;
18320 * fetch a Navigation Group based on the navigation ID
18321 * if one does not exist , it will get created.
18322 * @param {string} the navgroup to add
18323 * @returns {Roo.bootstrap.NavGroup} the navgroup
18325 get: function(navId) {
18326 if (typeof(this.groups[navId]) == 'undefined') {
18327 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18329 return this.groups[navId] ;
18344 * @class Roo.bootstrap.TabPanel
18345 * @extends Roo.bootstrap.Component
18346 * Bootstrap TabPanel class
18347 * @cfg {Boolean} active panel active
18348 * @cfg {String} html panel content
18349 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18350 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18351 * @cfg {String} href click to link..
18355 * Create a new TabPanel
18356 * @param {Object} config The config object
18359 Roo.bootstrap.TabPanel = function(config){
18360 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18364 * Fires when the active status changes
18365 * @param {Roo.bootstrap.TabPanel} this
18366 * @param {Boolean} state the new state
18371 * @event beforedeactivate
18372 * Fires before a tab is de-activated - can be used to do validation on a form.
18373 * @param {Roo.bootstrap.TabPanel} this
18374 * @return {Boolean} false if there is an error
18377 'beforedeactivate': true
18380 this.tabId = this.tabId || Roo.id();
18384 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18392 getAutoCreate : function(){
18395 // item is needed for carousel - not sure if it has any effect otherwise
18396 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18397 html: this.html || ''
18401 cfg.cls += ' active';
18405 cfg.tabId = this.tabId;
18412 initEvents: function()
18414 var p = this.parent();
18416 this.navId = this.navId || p.navId;
18418 if (typeof(this.navId) != 'undefined') {
18419 // not really needed.. but just in case.. parent should be a NavGroup.
18420 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18424 var i = tg.tabs.length - 1;
18426 if(this.active && tg.bullets > 0 && i < tg.bullets){
18427 tg.setActiveBullet(i);
18431 this.el.on('click', this.onClick, this);
18434 this.el.on("touchstart", this.onTouchStart, this);
18435 this.el.on("touchmove", this.onTouchMove, this);
18436 this.el.on("touchend", this.onTouchEnd, this);
18441 onRender : function(ct, position)
18443 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18446 setActive : function(state)
18448 Roo.log("panel - set active " + this.tabId + "=" + state);
18450 this.active = state;
18452 this.el.removeClass('active');
18454 } else if (!this.el.hasClass('active')) {
18455 this.el.addClass('active');
18458 this.fireEvent('changed', this, state);
18461 onClick : function(e)
18463 e.preventDefault();
18465 if(!this.href.length){
18469 window.location.href = this.href;
18478 onTouchStart : function(e)
18480 this.swiping = false;
18482 this.startX = e.browserEvent.touches[0].clientX;
18483 this.startY = e.browserEvent.touches[0].clientY;
18486 onTouchMove : function(e)
18488 this.swiping = true;
18490 this.endX = e.browserEvent.touches[0].clientX;
18491 this.endY = e.browserEvent.touches[0].clientY;
18494 onTouchEnd : function(e)
18501 var tabGroup = this.parent();
18503 if(this.endX > this.startX){ // swiping right
18504 tabGroup.showPanelPrev();
18508 if(this.startX > this.endX){ // swiping left
18509 tabGroup.showPanelNext();
18528 * @class Roo.bootstrap.DateField
18529 * @extends Roo.bootstrap.Input
18530 * Bootstrap DateField class
18531 * @cfg {Number} weekStart default 0
18532 * @cfg {String} viewMode default empty, (months|years)
18533 * @cfg {String} minViewMode default empty, (months|years)
18534 * @cfg {Number} startDate default -Infinity
18535 * @cfg {Number} endDate default Infinity
18536 * @cfg {Boolean} todayHighlight default false
18537 * @cfg {Boolean} todayBtn default false
18538 * @cfg {Boolean} calendarWeeks default false
18539 * @cfg {Object} daysOfWeekDisabled default empty
18540 * @cfg {Boolean} singleMode default false (true | false)
18542 * @cfg {Boolean} keyboardNavigation default true
18543 * @cfg {String} language default en
18546 * Create a new DateField
18547 * @param {Object} config The config object
18550 Roo.bootstrap.DateField = function(config){
18551 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18555 * Fires when this field show.
18556 * @param {Roo.bootstrap.DateField} this
18557 * @param {Mixed} date The date value
18562 * Fires when this field hide.
18563 * @param {Roo.bootstrap.DateField} this
18564 * @param {Mixed} date The date value
18569 * Fires when select a date.
18570 * @param {Roo.bootstrap.DateField} this
18571 * @param {Mixed} date The date value
18575 * @event beforeselect
18576 * Fires when before select a date.
18577 * @param {Roo.bootstrap.DateField} this
18578 * @param {Mixed} date The date value
18580 beforeselect : true
18584 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18587 * @cfg {String} format
18588 * The default date format string which can be overriden for localization support. The format must be
18589 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18593 * @cfg {String} altFormats
18594 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18595 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18597 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18605 todayHighlight : false,
18611 keyboardNavigation: true,
18613 calendarWeeks: false,
18615 startDate: -Infinity,
18619 daysOfWeekDisabled: [],
18623 singleMode : false,
18625 UTCDate: function()
18627 return new Date(Date.UTC.apply(Date, arguments));
18630 UTCToday: function()
18632 var today = new Date();
18633 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18636 getDate: function() {
18637 var d = this.getUTCDate();
18638 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18641 getUTCDate: function() {
18645 setDate: function(d) {
18646 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18649 setUTCDate: function(d) {
18651 this.setValue(this.formatDate(this.date));
18654 onRender: function(ct, position)
18657 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18659 this.language = this.language || 'en';
18660 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18661 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18663 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18664 this.format = this.format || 'm/d/y';
18665 this.isInline = false;
18666 this.isInput = true;
18667 this.component = this.el.select('.add-on', true).first() || false;
18668 this.component = (this.component && this.component.length === 0) ? false : this.component;
18669 this.hasInput = this.component && this.inputEl().length;
18671 if (typeof(this.minViewMode === 'string')) {
18672 switch (this.minViewMode) {
18674 this.minViewMode = 1;
18677 this.minViewMode = 2;
18680 this.minViewMode = 0;
18685 if (typeof(this.viewMode === 'string')) {
18686 switch (this.viewMode) {
18699 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18701 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18703 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18705 this.picker().on('mousedown', this.onMousedown, this);
18706 this.picker().on('click', this.onClick, this);
18708 this.picker().addClass('datepicker-dropdown');
18710 this.startViewMode = this.viewMode;
18712 if(this.singleMode){
18713 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18714 v.setVisibilityMode(Roo.Element.DISPLAY);
18718 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18719 v.setStyle('width', '189px');
18723 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18724 if(!this.calendarWeeks){
18729 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18730 v.attr('colspan', function(i, val){
18731 return parseInt(val) + 1;
18736 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18738 this.setStartDate(this.startDate);
18739 this.setEndDate(this.endDate);
18741 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18748 if(this.isInline) {
18753 picker : function()
18755 return this.pickerEl;
18756 // return this.el.select('.datepicker', true).first();
18759 fillDow: function()
18761 var dowCnt = this.weekStart;
18770 if(this.calendarWeeks){
18778 while (dowCnt < this.weekStart + 7) {
18782 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18786 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18789 fillMonths: function()
18792 var months = this.picker().select('>.datepicker-months td', true).first();
18794 months.dom.innerHTML = '';
18800 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18803 months.createChild(month);
18810 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;
18812 if (this.date < this.startDate) {
18813 this.viewDate = new Date(this.startDate);
18814 } else if (this.date > this.endDate) {
18815 this.viewDate = new Date(this.endDate);
18817 this.viewDate = new Date(this.date);
18825 var d = new Date(this.viewDate),
18826 year = d.getUTCFullYear(),
18827 month = d.getUTCMonth(),
18828 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18829 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18830 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18831 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18832 currentDate = this.date && this.date.valueOf(),
18833 today = this.UTCToday();
18835 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18837 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18839 // this.picker.select('>tfoot th.today').
18840 // .text(dates[this.language].today)
18841 // .toggle(this.todayBtn !== false);
18843 this.updateNavArrows();
18846 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18848 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18850 prevMonth.setUTCDate(day);
18852 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18854 var nextMonth = new Date(prevMonth);
18856 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18858 nextMonth = nextMonth.valueOf();
18860 var fillMonths = false;
18862 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18864 while(prevMonth.valueOf() <= nextMonth) {
18867 if (prevMonth.getUTCDay() === this.weekStart) {
18869 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18877 if(this.calendarWeeks){
18878 // ISO 8601: First week contains first thursday.
18879 // ISO also states week starts on Monday, but we can be more abstract here.
18881 // Start of current week: based on weekstart/current date
18882 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18883 // Thursday of this week
18884 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18885 // First Thursday of year, year from thursday
18886 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18887 // Calendar week: ms between thursdays, div ms per day, div 7 days
18888 calWeek = (th - yth) / 864e5 / 7 + 1;
18890 fillMonths.cn.push({
18898 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18900 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18903 if (this.todayHighlight &&
18904 prevMonth.getUTCFullYear() == today.getFullYear() &&
18905 prevMonth.getUTCMonth() == today.getMonth() &&
18906 prevMonth.getUTCDate() == today.getDate()) {
18907 clsName += ' today';
18910 if (currentDate && prevMonth.valueOf() === currentDate) {
18911 clsName += ' active';
18914 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18915 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18916 clsName += ' disabled';
18919 fillMonths.cn.push({
18921 cls: 'day ' + clsName,
18922 html: prevMonth.getDate()
18925 prevMonth.setDate(prevMonth.getDate()+1);
18928 var currentYear = this.date && this.date.getUTCFullYear();
18929 var currentMonth = this.date && this.date.getUTCMonth();
18931 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18933 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18934 v.removeClass('active');
18936 if(currentYear === year && k === currentMonth){
18937 v.addClass('active');
18940 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18941 v.addClass('disabled');
18947 year = parseInt(year/10, 10) * 10;
18949 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18951 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18954 for (var i = -1; i < 11; i++) {
18955 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18957 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18965 showMode: function(dir)
18968 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18971 Roo.each(this.picker().select('>div',true).elements, function(v){
18972 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18975 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18980 if(this.isInline) {
18984 this.picker().removeClass(['bottom', 'top']);
18986 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18988 * place to the top of element!
18992 this.picker().addClass('top');
18993 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18998 this.picker().addClass('bottom');
19000 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19003 parseDate : function(value)
19005 if(!value || value instanceof Date){
19008 var v = Date.parseDate(value, this.format);
19009 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19010 v = Date.parseDate(value, 'Y-m-d');
19012 if(!v && this.altFormats){
19013 if(!this.altFormatsArray){
19014 this.altFormatsArray = this.altFormats.split("|");
19016 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19017 v = Date.parseDate(value, this.altFormatsArray[i]);
19023 formatDate : function(date, fmt)
19025 return (!date || !(date instanceof Date)) ?
19026 date : date.dateFormat(fmt || this.format);
19029 onFocus : function()
19031 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19035 onBlur : function()
19037 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19039 var d = this.inputEl().getValue();
19046 showPopup : function()
19048 this.picker().show();
19052 this.fireEvent('showpopup', this, this.date);
19055 hidePopup : function()
19057 if(this.isInline) {
19060 this.picker().hide();
19061 this.viewMode = this.startViewMode;
19064 this.fireEvent('hidepopup', this, this.date);
19068 onMousedown: function(e)
19070 e.stopPropagation();
19071 e.preventDefault();
19076 Roo.bootstrap.DateField.superclass.keyup.call(this);
19080 setValue: function(v)
19082 if(this.fireEvent('beforeselect', this, v) !== false){
19083 var d = new Date(this.parseDate(v) ).clearTime();
19085 if(isNaN(d.getTime())){
19086 this.date = this.viewDate = '';
19087 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19091 v = this.formatDate(d);
19093 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19095 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19099 this.fireEvent('select', this, this.date);
19103 getValue: function()
19105 return this.formatDate(this.date);
19108 fireKey: function(e)
19110 if (!this.picker().isVisible()){
19111 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19117 var dateChanged = false,
19119 newDate, newViewDate;
19124 e.preventDefault();
19128 if (!this.keyboardNavigation) {
19131 dir = e.keyCode == 37 ? -1 : 1;
19134 newDate = this.moveYear(this.date, dir);
19135 newViewDate = this.moveYear(this.viewDate, dir);
19136 } else if (e.shiftKey){
19137 newDate = this.moveMonth(this.date, dir);
19138 newViewDate = this.moveMonth(this.viewDate, dir);
19140 newDate = new Date(this.date);
19141 newDate.setUTCDate(this.date.getUTCDate() + dir);
19142 newViewDate = new Date(this.viewDate);
19143 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19145 if (this.dateWithinRange(newDate)){
19146 this.date = newDate;
19147 this.viewDate = newViewDate;
19148 this.setValue(this.formatDate(this.date));
19150 e.preventDefault();
19151 dateChanged = true;
19156 if (!this.keyboardNavigation) {
19159 dir = e.keyCode == 38 ? -1 : 1;
19161 newDate = this.moveYear(this.date, dir);
19162 newViewDate = this.moveYear(this.viewDate, dir);
19163 } else if (e.shiftKey){
19164 newDate = this.moveMonth(this.date, dir);
19165 newViewDate = this.moveMonth(this.viewDate, dir);
19167 newDate = new Date(this.date);
19168 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19169 newViewDate = new Date(this.viewDate);
19170 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19172 if (this.dateWithinRange(newDate)){
19173 this.date = newDate;
19174 this.viewDate = newViewDate;
19175 this.setValue(this.formatDate(this.date));
19177 e.preventDefault();
19178 dateChanged = true;
19182 this.setValue(this.formatDate(this.date));
19184 e.preventDefault();
19187 this.setValue(this.formatDate(this.date));
19201 onClick: function(e)
19203 e.stopPropagation();
19204 e.preventDefault();
19206 var target = e.getTarget();
19208 if(target.nodeName.toLowerCase() === 'i'){
19209 target = Roo.get(target).dom.parentNode;
19212 var nodeName = target.nodeName;
19213 var className = target.className;
19214 var html = target.innerHTML;
19215 //Roo.log(nodeName);
19217 switch(nodeName.toLowerCase()) {
19219 switch(className) {
19225 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19226 switch(this.viewMode){
19228 this.viewDate = this.moveMonth(this.viewDate, dir);
19232 this.viewDate = this.moveYear(this.viewDate, dir);
19238 var date = new Date();
19239 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19241 this.setValue(this.formatDate(this.date));
19248 if (className.indexOf('disabled') < 0) {
19249 this.viewDate.setUTCDate(1);
19250 if (className.indexOf('month') > -1) {
19251 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19253 var year = parseInt(html, 10) || 0;
19254 this.viewDate.setUTCFullYear(year);
19258 if(this.singleMode){
19259 this.setValue(this.formatDate(this.viewDate));
19270 //Roo.log(className);
19271 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19272 var day = parseInt(html, 10) || 1;
19273 var year = this.viewDate.getUTCFullYear(),
19274 month = this.viewDate.getUTCMonth();
19276 if (className.indexOf('old') > -1) {
19283 } else if (className.indexOf('new') > -1) {
19291 //Roo.log([year,month,day]);
19292 this.date = this.UTCDate(year, month, day,0,0,0,0);
19293 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19295 //Roo.log(this.formatDate(this.date));
19296 this.setValue(this.formatDate(this.date));
19303 setStartDate: function(startDate)
19305 this.startDate = startDate || -Infinity;
19306 if (this.startDate !== -Infinity) {
19307 this.startDate = this.parseDate(this.startDate);
19310 this.updateNavArrows();
19313 setEndDate: function(endDate)
19315 this.endDate = endDate || Infinity;
19316 if (this.endDate !== Infinity) {
19317 this.endDate = this.parseDate(this.endDate);
19320 this.updateNavArrows();
19323 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19325 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19326 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19327 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19329 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19330 return parseInt(d, 10);
19333 this.updateNavArrows();
19336 updateNavArrows: function()
19338 if(this.singleMode){
19342 var d = new Date(this.viewDate),
19343 year = d.getUTCFullYear(),
19344 month = d.getUTCMonth();
19346 Roo.each(this.picker().select('.prev', true).elements, function(v){
19348 switch (this.viewMode) {
19351 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19357 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19364 Roo.each(this.picker().select('.next', true).elements, function(v){
19366 switch (this.viewMode) {
19369 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19375 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19383 moveMonth: function(date, dir)
19388 var new_date = new Date(date.valueOf()),
19389 day = new_date.getUTCDate(),
19390 month = new_date.getUTCMonth(),
19391 mag = Math.abs(dir),
19393 dir = dir > 0 ? 1 : -1;
19396 // If going back one month, make sure month is not current month
19397 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19399 return new_date.getUTCMonth() == month;
19401 // If going forward one month, make sure month is as expected
19402 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19404 return new_date.getUTCMonth() != new_month;
19406 new_month = month + dir;
19407 new_date.setUTCMonth(new_month);
19408 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19409 if (new_month < 0 || new_month > 11) {
19410 new_month = (new_month + 12) % 12;
19413 // For magnitudes >1, move one month at a time...
19414 for (var i=0; i<mag; i++) {
19415 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19416 new_date = this.moveMonth(new_date, dir);
19418 // ...then reset the day, keeping it in the new month
19419 new_month = new_date.getUTCMonth();
19420 new_date.setUTCDate(day);
19422 return new_month != new_date.getUTCMonth();
19425 // Common date-resetting loop -- if date is beyond end of month, make it
19428 new_date.setUTCDate(--day);
19429 new_date.setUTCMonth(new_month);
19434 moveYear: function(date, dir)
19436 return this.moveMonth(date, dir*12);
19439 dateWithinRange: function(date)
19441 return date >= this.startDate && date <= this.endDate;
19447 this.picker().remove();
19450 validateValue : function(value)
19452 if(this.getVisibilityEl().hasClass('hidden')){
19456 if(value.length < 1) {
19457 if(this.allowBlank){
19463 if(value.length < this.minLength){
19466 if(value.length > this.maxLength){
19470 var vt = Roo.form.VTypes;
19471 if(!vt[this.vtype](value, this)){
19475 if(typeof this.validator == "function"){
19476 var msg = this.validator(value);
19482 if(this.regex && !this.regex.test(value)){
19486 if(typeof(this.parseDate(value)) == 'undefined'){
19490 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19494 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19504 this.date = this.viewDate = '';
19506 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19511 Roo.apply(Roo.bootstrap.DateField, {
19522 html: '<i class="fa fa-arrow-left"/>'
19532 html: '<i class="fa fa-arrow-right"/>'
19574 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19575 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19576 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19577 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19578 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19591 navFnc: 'FullYear',
19596 navFnc: 'FullYear',
19601 Roo.apply(Roo.bootstrap.DateField, {
19605 cls: 'datepicker dropdown-menu roo-dynamic',
19609 cls: 'datepicker-days',
19613 cls: 'table-condensed',
19615 Roo.bootstrap.DateField.head,
19619 Roo.bootstrap.DateField.footer
19626 cls: 'datepicker-months',
19630 cls: 'table-condensed',
19632 Roo.bootstrap.DateField.head,
19633 Roo.bootstrap.DateField.content,
19634 Roo.bootstrap.DateField.footer
19641 cls: 'datepicker-years',
19645 cls: 'table-condensed',
19647 Roo.bootstrap.DateField.head,
19648 Roo.bootstrap.DateField.content,
19649 Roo.bootstrap.DateField.footer
19668 * @class Roo.bootstrap.TimeField
19669 * @extends Roo.bootstrap.Input
19670 * Bootstrap DateField class
19674 * Create a new TimeField
19675 * @param {Object} config The config object
19678 Roo.bootstrap.TimeField = function(config){
19679 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19683 * Fires when this field show.
19684 * @param {Roo.bootstrap.DateField} thisthis
19685 * @param {Mixed} date The date value
19690 * Fires when this field hide.
19691 * @param {Roo.bootstrap.DateField} this
19692 * @param {Mixed} date The date value
19697 * Fires when select a date.
19698 * @param {Roo.bootstrap.DateField} this
19699 * @param {Mixed} date The date value
19705 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19708 * @cfg {String} format
19709 * The default time format string which can be overriden for localization support. The format must be
19710 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19714 onRender: function(ct, position)
19717 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19719 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19721 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19723 this.pop = this.picker().select('>.datepicker-time',true).first();
19724 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19726 this.picker().on('mousedown', this.onMousedown, this);
19727 this.picker().on('click', this.onClick, this);
19729 this.picker().addClass('datepicker-dropdown');
19734 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19735 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19736 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19737 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19738 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19739 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19743 fireKey: function(e){
19744 if (!this.picker().isVisible()){
19745 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19751 e.preventDefault();
19759 this.onTogglePeriod();
19762 this.onIncrementMinutes();
19765 this.onDecrementMinutes();
19774 onClick: function(e) {
19775 e.stopPropagation();
19776 e.preventDefault();
19779 picker : function()
19781 return this.el.select('.datepicker', true).first();
19784 fillTime: function()
19786 var time = this.pop.select('tbody', true).first();
19788 time.dom.innerHTML = '';
19803 cls: 'hours-up glyphicon glyphicon-chevron-up'
19823 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19844 cls: 'timepicker-hour',
19859 cls: 'timepicker-minute',
19874 cls: 'btn btn-primary period',
19896 cls: 'hours-down glyphicon glyphicon-chevron-down'
19916 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19934 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19941 var hours = this.time.getHours();
19942 var minutes = this.time.getMinutes();
19955 hours = hours - 12;
19959 hours = '0' + hours;
19963 minutes = '0' + minutes;
19966 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19967 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19968 this.pop.select('button', true).first().dom.innerHTML = period;
19974 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19976 var cls = ['bottom'];
19978 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19985 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19990 this.picker().addClass(cls.join('-'));
19994 Roo.each(cls, function(c){
19996 _this.picker().setTop(_this.inputEl().getHeight());
20000 _this.picker().setTop(0 - _this.picker().getHeight());
20005 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20009 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20016 onFocus : function()
20018 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20022 onBlur : function()
20024 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20030 this.picker().show();
20035 this.fireEvent('show', this, this.date);
20040 this.picker().hide();
20043 this.fireEvent('hide', this, this.date);
20046 setTime : function()
20049 this.setValue(this.time.format(this.format));
20051 this.fireEvent('select', this, this.date);
20056 onMousedown: function(e){
20057 e.stopPropagation();
20058 e.preventDefault();
20061 onIncrementHours: function()
20063 Roo.log('onIncrementHours');
20064 this.time = this.time.add(Date.HOUR, 1);
20069 onDecrementHours: function()
20071 Roo.log('onDecrementHours');
20072 this.time = this.time.add(Date.HOUR, -1);
20076 onIncrementMinutes: function()
20078 Roo.log('onIncrementMinutes');
20079 this.time = this.time.add(Date.MINUTE, 1);
20083 onDecrementMinutes: function()
20085 Roo.log('onDecrementMinutes');
20086 this.time = this.time.add(Date.MINUTE, -1);
20090 onTogglePeriod: function()
20092 Roo.log('onTogglePeriod');
20093 this.time = this.time.add(Date.HOUR, 12);
20100 Roo.apply(Roo.bootstrap.TimeField, {
20130 cls: 'btn btn-info ok',
20142 Roo.apply(Roo.bootstrap.TimeField, {
20146 cls: 'datepicker dropdown-menu',
20150 cls: 'datepicker-time',
20154 cls: 'table-condensed',
20156 Roo.bootstrap.TimeField.content,
20157 Roo.bootstrap.TimeField.footer
20176 * @class Roo.bootstrap.MonthField
20177 * @extends Roo.bootstrap.Input
20178 * Bootstrap MonthField class
20180 * @cfg {String} language default en
20183 * Create a new MonthField
20184 * @param {Object} config The config object
20187 Roo.bootstrap.MonthField = function(config){
20188 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20193 * Fires when this field show.
20194 * @param {Roo.bootstrap.MonthField} this
20195 * @param {Mixed} date The date value
20200 * Fires when this field hide.
20201 * @param {Roo.bootstrap.MonthField} this
20202 * @param {Mixed} date The date value
20207 * Fires when select a date.
20208 * @param {Roo.bootstrap.MonthField} this
20209 * @param {String} oldvalue The old value
20210 * @param {String} newvalue The new value
20216 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20218 onRender: function(ct, position)
20221 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20223 this.language = this.language || 'en';
20224 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20225 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20227 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20228 this.isInline = false;
20229 this.isInput = true;
20230 this.component = this.el.select('.add-on', true).first() || false;
20231 this.component = (this.component && this.component.length === 0) ? false : this.component;
20232 this.hasInput = this.component && this.inputEL().length;
20234 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20236 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20238 this.picker().on('mousedown', this.onMousedown, this);
20239 this.picker().on('click', this.onClick, this);
20241 this.picker().addClass('datepicker-dropdown');
20243 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20244 v.setStyle('width', '189px');
20251 if(this.isInline) {
20257 setValue: function(v, suppressEvent)
20259 var o = this.getValue();
20261 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20265 if(suppressEvent !== true){
20266 this.fireEvent('select', this, o, v);
20271 getValue: function()
20276 onClick: function(e)
20278 e.stopPropagation();
20279 e.preventDefault();
20281 var target = e.getTarget();
20283 if(target.nodeName.toLowerCase() === 'i'){
20284 target = Roo.get(target).dom.parentNode;
20287 var nodeName = target.nodeName;
20288 var className = target.className;
20289 var html = target.innerHTML;
20291 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20295 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20297 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20303 picker : function()
20305 return this.pickerEl;
20308 fillMonths: function()
20311 var months = this.picker().select('>.datepicker-months td', true).first();
20313 months.dom.innerHTML = '';
20319 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20322 months.createChild(month);
20331 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20332 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20335 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20336 e.removeClass('active');
20338 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20339 e.addClass('active');
20346 if(this.isInline) {
20350 this.picker().removeClass(['bottom', 'top']);
20352 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20354 * place to the top of element!
20358 this.picker().addClass('top');
20359 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20364 this.picker().addClass('bottom');
20366 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20369 onFocus : function()
20371 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20375 onBlur : function()
20377 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20379 var d = this.inputEl().getValue();
20388 this.picker().show();
20389 this.picker().select('>.datepicker-months', true).first().show();
20393 this.fireEvent('show', this, this.date);
20398 if(this.isInline) {
20401 this.picker().hide();
20402 this.fireEvent('hide', this, this.date);
20406 onMousedown: function(e)
20408 e.stopPropagation();
20409 e.preventDefault();
20414 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20418 fireKey: function(e)
20420 if (!this.picker().isVisible()){
20421 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20432 e.preventDefault();
20436 dir = e.keyCode == 37 ? -1 : 1;
20438 this.vIndex = this.vIndex + dir;
20440 if(this.vIndex < 0){
20444 if(this.vIndex > 11){
20448 if(isNaN(this.vIndex)){
20452 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20458 dir = e.keyCode == 38 ? -1 : 1;
20460 this.vIndex = this.vIndex + dir * 4;
20462 if(this.vIndex < 0){
20466 if(this.vIndex > 11){
20470 if(isNaN(this.vIndex)){
20474 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20479 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20480 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20484 e.preventDefault();
20487 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20488 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20504 this.picker().remove();
20509 Roo.apply(Roo.bootstrap.MonthField, {
20528 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20529 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20534 Roo.apply(Roo.bootstrap.MonthField, {
20538 cls: 'datepicker dropdown-menu roo-dynamic',
20542 cls: 'datepicker-months',
20546 cls: 'table-condensed',
20548 Roo.bootstrap.DateField.content
20568 * @class Roo.bootstrap.CheckBox
20569 * @extends Roo.bootstrap.Input
20570 * Bootstrap CheckBox class
20572 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20573 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20574 * @cfg {String} boxLabel The text that appears beside the checkbox
20575 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20576 * @cfg {Boolean} checked initnal the element
20577 * @cfg {Boolean} inline inline the element (default false)
20578 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20579 * @cfg {String} tooltip label tooltip
20582 * Create a new CheckBox
20583 * @param {Object} config The config object
20586 Roo.bootstrap.CheckBox = function(config){
20587 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20592 * Fires when the element is checked or unchecked.
20593 * @param {Roo.bootstrap.CheckBox} this This input
20594 * @param {Boolean} checked The new checked value
20599 * Fires when the element is click.
20600 * @param {Roo.bootstrap.CheckBox} this This input
20607 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20609 inputType: 'checkbox',
20618 getAutoCreate : function()
20620 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20626 cfg.cls = 'form-group ' + this.inputType; //input-group
20629 cfg.cls += ' ' + this.inputType + '-inline';
20635 type : this.inputType,
20636 value : this.inputValue,
20637 cls : 'roo-' + this.inputType, //'form-box',
20638 placeholder : this.placeholder || ''
20642 if(this.inputType != 'radio'){
20646 cls : 'roo-hidden-value',
20647 value : this.checked ? this.inputValue : this.valueOff
20652 if (this.weight) { // Validity check?
20653 cfg.cls += " " + this.inputType + "-" + this.weight;
20656 if (this.disabled) {
20657 input.disabled=true;
20661 input.checked = this.checked;
20666 input.name = this.name;
20668 if(this.inputType != 'radio'){
20669 hidden.name = this.name;
20670 input.name = '_hidden_' + this.name;
20675 input.cls += ' input-' + this.size;
20680 ['xs','sm','md','lg'].map(function(size){
20681 if (settings[size]) {
20682 cfg.cls += ' col-' + size + '-' + settings[size];
20686 var inputblock = input;
20688 if (this.before || this.after) {
20691 cls : 'input-group',
20696 inputblock.cn.push({
20698 cls : 'input-group-addon',
20703 inputblock.cn.push(input);
20705 if(this.inputType != 'radio'){
20706 inputblock.cn.push(hidden);
20710 inputblock.cn.push({
20712 cls : 'input-group-addon',
20719 if (align ==='left' && this.fieldLabel.length) {
20720 // Roo.log("left and has label");
20725 cls : 'control-label',
20726 html : this.fieldLabel
20736 if(this.labelWidth > 12){
20737 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20740 if(this.labelWidth < 13 && this.labelmd == 0){
20741 this.labelmd = this.labelWidth;
20744 if(this.labellg > 0){
20745 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20746 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20749 if(this.labelmd > 0){
20750 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20751 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20754 if(this.labelsm > 0){
20755 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20756 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20759 if(this.labelxs > 0){
20760 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20761 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20764 } else if ( this.fieldLabel.length) {
20765 // Roo.log(" label");
20769 tag: this.boxLabel ? 'span' : 'label',
20771 cls: 'control-label box-input-label',
20772 //cls : 'input-group-addon',
20773 html : this.fieldLabel
20782 // Roo.log(" no label && no align");
20783 cfg.cn = [ inputblock ] ;
20789 var boxLabelCfg = {
20791 //'for': id, // box label is handled by onclick - so no for...
20793 html: this.boxLabel
20797 boxLabelCfg.tooltip = this.tooltip;
20800 cfg.cn.push(boxLabelCfg);
20803 if(this.inputType != 'radio'){
20804 cfg.cn.push(hidden);
20812 * return the real input element.
20814 inputEl: function ()
20816 return this.el.select('input.roo-' + this.inputType,true).first();
20818 hiddenEl: function ()
20820 return this.el.select('input.roo-hidden-value',true).first();
20823 labelEl: function()
20825 return this.el.select('label.control-label',true).first();
20827 /* depricated... */
20831 return this.labelEl();
20834 boxLabelEl: function()
20836 return this.el.select('label.box-label',true).first();
20839 initEvents : function()
20841 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20843 this.inputEl().on('click', this.onClick, this);
20845 if (this.boxLabel) {
20846 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20849 this.startValue = this.getValue();
20852 Roo.bootstrap.CheckBox.register(this);
20856 onClick : function(e)
20858 if(this.fireEvent('click', this, e) !== false){
20859 this.setChecked(!this.checked);
20864 setChecked : function(state,suppressEvent)
20866 this.startValue = this.getValue();
20868 if(this.inputType == 'radio'){
20870 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20871 e.dom.checked = false;
20874 this.inputEl().dom.checked = true;
20876 this.inputEl().dom.value = this.inputValue;
20878 if(suppressEvent !== true){
20879 this.fireEvent('check', this, true);
20887 this.checked = state;
20889 this.inputEl().dom.checked = state;
20892 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20894 if(suppressEvent !== true){
20895 this.fireEvent('check', this, state);
20901 getValue : function()
20903 if(this.inputType == 'radio'){
20904 return this.getGroupValue();
20907 return this.hiddenEl().dom.value;
20911 getGroupValue : function()
20913 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20917 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20920 setValue : function(v,suppressEvent)
20922 if(this.inputType == 'radio'){
20923 this.setGroupValue(v, suppressEvent);
20927 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20932 setGroupValue : function(v, suppressEvent)
20934 this.startValue = this.getValue();
20936 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20937 e.dom.checked = false;
20939 if(e.dom.value == v){
20940 e.dom.checked = true;
20944 if(suppressEvent !== true){
20945 this.fireEvent('check', this, true);
20953 validate : function()
20955 if(this.getVisibilityEl().hasClass('hidden')){
20961 (this.inputType == 'radio' && this.validateRadio()) ||
20962 (this.inputType == 'checkbox' && this.validateCheckbox())
20968 this.markInvalid();
20972 validateRadio : function()
20974 if(this.getVisibilityEl().hasClass('hidden')){
20978 if(this.allowBlank){
20984 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20985 if(!e.dom.checked){
20997 validateCheckbox : function()
21000 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21001 //return (this.getValue() == this.inputValue) ? true : false;
21004 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21012 for(var i in group){
21013 if(group[i].el.isVisible(true)){
21021 for(var i in group){
21026 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21033 * Mark this field as valid
21035 markValid : function()
21039 this.fireEvent('valid', this);
21041 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21044 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21051 if(this.inputType == 'radio'){
21052 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21053 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21054 e.findParent('.form-group', false, true).addClass(_this.validClass);
21061 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21062 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21066 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21072 for(var i in group){
21073 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21074 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21079 * Mark this field as invalid
21080 * @param {String} msg The validation message
21082 markInvalid : function(msg)
21084 if(this.allowBlank){
21090 this.fireEvent('invalid', this, msg);
21092 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21095 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21099 label.markInvalid();
21102 if(this.inputType == 'radio'){
21103 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21104 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21105 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21112 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21113 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21117 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21123 for(var i in group){
21124 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21125 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21130 clearInvalid : function()
21132 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21134 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21136 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21138 if (label && label.iconEl) {
21139 label.iconEl.removeClass(label.validClass);
21140 label.iconEl.removeClass(label.invalidClass);
21144 disable : function()
21146 if(this.inputType != 'radio'){
21147 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21154 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21155 _this.getActionEl().addClass(this.disabledClass);
21156 e.dom.disabled = true;
21160 this.disabled = true;
21161 this.fireEvent("disable", this);
21165 enable : function()
21167 if(this.inputType != 'radio'){
21168 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21175 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21176 _this.getActionEl().removeClass(this.disabledClass);
21177 e.dom.disabled = false;
21181 this.disabled = false;
21182 this.fireEvent("enable", this);
21186 setBoxLabel : function(v)
21191 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21197 Roo.apply(Roo.bootstrap.CheckBox, {
21202 * register a CheckBox Group
21203 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21205 register : function(checkbox)
21207 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21208 this.groups[checkbox.groupId] = {};
21211 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21215 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21219 * fetch a CheckBox Group based on the group ID
21220 * @param {string} the group ID
21221 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21223 get: function(groupId) {
21224 if (typeof(this.groups[groupId]) == 'undefined') {
21228 return this.groups[groupId] ;
21241 * @class Roo.bootstrap.Radio
21242 * @extends Roo.bootstrap.Component
21243 * Bootstrap Radio class
21244 * @cfg {String} boxLabel - the label associated
21245 * @cfg {String} value - the value of radio
21248 * Create a new Radio
21249 * @param {Object} config The config object
21251 Roo.bootstrap.Radio = function(config){
21252 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21256 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21262 getAutoCreate : function()
21266 cls : 'form-group radio',
21271 html : this.boxLabel
21279 initEvents : function()
21281 this.parent().register(this);
21283 this.el.on('click', this.onClick, this);
21287 onClick : function(e)
21289 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21290 this.setChecked(true);
21294 setChecked : function(state, suppressEvent)
21296 this.parent().setValue(this.value, suppressEvent);
21300 setBoxLabel : function(v)
21305 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21320 * @class Roo.bootstrap.SecurePass
21321 * @extends Roo.bootstrap.Input
21322 * Bootstrap SecurePass class
21326 * Create a new SecurePass
21327 * @param {Object} config The config object
21330 Roo.bootstrap.SecurePass = function (config) {
21331 // these go here, so the translation tool can replace them..
21333 PwdEmpty: "Please type a password, and then retype it to confirm.",
21334 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21335 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21336 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21337 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21338 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21339 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21340 TooWeak: "Your password is Too Weak."
21342 this.meterLabel = "Password strength:";
21343 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21344 this.meterClass = [
21345 "roo-password-meter-tooweak",
21346 "roo-password-meter-weak",
21347 "roo-password-meter-medium",
21348 "roo-password-meter-strong",
21349 "roo-password-meter-grey"
21354 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21357 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21359 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21361 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21362 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21363 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21364 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21365 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21366 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21367 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21377 * @cfg {String/Object} Label for the strength meter (defaults to
21378 * 'Password strength:')
21383 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21384 * ['Weak', 'Medium', 'Strong'])
21387 pwdStrengths: false,
21400 initEvents: function ()
21402 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21404 if (this.el.is('input[type=password]') && Roo.isSafari) {
21405 this.el.on('keydown', this.SafariOnKeyDown, this);
21408 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21411 onRender: function (ct, position)
21413 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21414 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21415 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21417 this.trigger.createChild({
21422 cls: 'roo-password-meter-grey col-xs-12',
21425 //width: this.meterWidth + 'px'
21429 cls: 'roo-password-meter-text'
21435 if (this.hideTrigger) {
21436 this.trigger.setDisplayed(false);
21438 this.setSize(this.width || '', this.height || '');
21441 onDestroy: function ()
21443 if (this.trigger) {
21444 this.trigger.removeAllListeners();
21445 this.trigger.remove();
21448 this.wrap.remove();
21450 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21453 checkStrength: function ()
21455 var pwd = this.inputEl().getValue();
21456 if (pwd == this._lastPwd) {
21461 if (this.ClientSideStrongPassword(pwd)) {
21463 } else if (this.ClientSideMediumPassword(pwd)) {
21465 } else if (this.ClientSideWeakPassword(pwd)) {
21471 Roo.log('strength1: ' + strength);
21473 //var pm = this.trigger.child('div/div/div').dom;
21474 var pm = this.trigger.child('div/div');
21475 pm.removeClass(this.meterClass);
21476 pm.addClass(this.meterClass[strength]);
21479 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21481 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21483 this._lastPwd = pwd;
21487 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21489 this._lastPwd = '';
21491 var pm = this.trigger.child('div/div');
21492 pm.removeClass(this.meterClass);
21493 pm.addClass('roo-password-meter-grey');
21496 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21499 this.inputEl().dom.type='password';
21502 validateValue: function (value)
21505 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21508 if (value.length == 0) {
21509 if (this.allowBlank) {
21510 this.clearInvalid();
21514 this.markInvalid(this.errors.PwdEmpty);
21515 this.errorMsg = this.errors.PwdEmpty;
21523 if ('[\x21-\x7e]*'.match(value)) {
21524 this.markInvalid(this.errors.PwdBadChar);
21525 this.errorMsg = this.errors.PwdBadChar;
21528 if (value.length < 6) {
21529 this.markInvalid(this.errors.PwdShort);
21530 this.errorMsg = this.errors.PwdShort;
21533 if (value.length > 16) {
21534 this.markInvalid(this.errors.PwdLong);
21535 this.errorMsg = this.errors.PwdLong;
21539 if (this.ClientSideStrongPassword(value)) {
21541 } else if (this.ClientSideMediumPassword(value)) {
21543 } else if (this.ClientSideWeakPassword(value)) {
21550 if (strength < 2) {
21551 //this.markInvalid(this.errors.TooWeak);
21552 this.errorMsg = this.errors.TooWeak;
21557 console.log('strength2: ' + strength);
21559 //var pm = this.trigger.child('div/div/div').dom;
21561 var pm = this.trigger.child('div/div');
21562 pm.removeClass(this.meterClass);
21563 pm.addClass(this.meterClass[strength]);
21565 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21567 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21569 this.errorMsg = '';
21573 CharacterSetChecks: function (type)
21576 this.fResult = false;
21579 isctype: function (character, type)
21582 case this.kCapitalLetter:
21583 if (character >= 'A' && character <= 'Z') {
21588 case this.kSmallLetter:
21589 if (character >= 'a' && character <= 'z') {
21595 if (character >= '0' && character <= '9') {
21600 case this.kPunctuation:
21601 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21612 IsLongEnough: function (pwd, size)
21614 return !(pwd == null || isNaN(size) || pwd.length < size);
21617 SpansEnoughCharacterSets: function (word, nb)
21619 if (!this.IsLongEnough(word, nb))
21624 var characterSetChecks = new Array(
21625 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21626 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21629 for (var index = 0; index < word.length; ++index) {
21630 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21631 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21632 characterSetChecks[nCharSet].fResult = true;
21639 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21640 if (characterSetChecks[nCharSet].fResult) {
21645 if (nCharSets < nb) {
21651 ClientSideStrongPassword: function (pwd)
21653 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21656 ClientSideMediumPassword: function (pwd)
21658 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21661 ClientSideWeakPassword: function (pwd)
21663 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21666 })//<script type="text/javascript">
21669 * Based Ext JS Library 1.1.1
21670 * Copyright(c) 2006-2007, Ext JS, LLC.
21676 * @class Roo.HtmlEditorCore
21677 * @extends Roo.Component
21678 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21680 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21683 Roo.HtmlEditorCore = function(config){
21686 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21691 * @event initialize
21692 * Fires when the editor is fully initialized (including the iframe)
21693 * @param {Roo.HtmlEditorCore} this
21698 * Fires when the editor is first receives the focus. Any insertion must wait
21699 * until after this event.
21700 * @param {Roo.HtmlEditorCore} this
21704 * @event beforesync
21705 * Fires before the textarea is updated with content from the editor iframe. Return false
21706 * to cancel the sync.
21707 * @param {Roo.HtmlEditorCore} this
21708 * @param {String} html
21712 * @event beforepush
21713 * Fires before the iframe editor is updated with content from the textarea. Return false
21714 * to cancel the push.
21715 * @param {Roo.HtmlEditorCore} this
21716 * @param {String} html
21721 * Fires when the textarea is updated with content from the editor iframe.
21722 * @param {Roo.HtmlEditorCore} this
21723 * @param {String} html
21728 * Fires when the iframe editor is updated with content from the textarea.
21729 * @param {Roo.HtmlEditorCore} this
21730 * @param {String} html
21735 * @event editorevent
21736 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21737 * @param {Roo.HtmlEditorCore} this
21743 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21745 // defaults : white / black...
21746 this.applyBlacklists();
21753 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21757 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21763 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21768 * @cfg {Number} height (in pixels)
21772 * @cfg {Number} width (in pixels)
21777 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21780 stylesheets: false,
21785 // private properties
21786 validationEvent : false,
21788 initialized : false,
21790 sourceEditMode : false,
21791 onFocus : Roo.emptyFn,
21793 hideMode:'offsets',
21797 // blacklist + whitelisted elements..
21804 * Protected method that will not generally be called directly. It
21805 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21806 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21808 getDocMarkup : function(){
21812 // inherit styels from page...??
21813 if (this.stylesheets === false) {
21815 Roo.get(document.head).select('style').each(function(node) {
21816 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21819 Roo.get(document.head).select('link').each(function(node) {
21820 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21823 } else if (!this.stylesheets.length) {
21825 st = '<style type="text/css">' +
21826 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21829 st = '<style type="text/css">' +
21834 st += '<style type="text/css">' +
21835 'IMG { cursor: pointer } ' +
21838 var cls = 'roo-htmleditor-body';
21840 if(this.bodyCls.length){
21841 cls += ' ' + this.bodyCls;
21844 return '<html><head>' + st +
21845 //<style type="text/css">' +
21846 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21848 ' </head><body class="' + cls + '"></body></html>';
21852 onRender : function(ct, position)
21855 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21856 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21859 this.el.dom.style.border = '0 none';
21860 this.el.dom.setAttribute('tabIndex', -1);
21861 this.el.addClass('x-hidden hide');
21865 if(Roo.isIE){ // fix IE 1px bogus margin
21866 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21870 this.frameId = Roo.id();
21874 var iframe = this.owner.wrap.createChild({
21876 cls: 'form-control', // bootstrap..
21878 name: this.frameId,
21879 frameBorder : 'no',
21880 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21885 this.iframe = iframe.dom;
21887 this.assignDocWin();
21889 this.doc.designMode = 'on';
21892 this.doc.write(this.getDocMarkup());
21896 var task = { // must defer to wait for browser to be ready
21898 //console.log("run task?" + this.doc.readyState);
21899 this.assignDocWin();
21900 if(this.doc.body || this.doc.readyState == 'complete'){
21902 this.doc.designMode="on";
21906 Roo.TaskMgr.stop(task);
21907 this.initEditor.defer(10, this);
21914 Roo.TaskMgr.start(task);
21919 onResize : function(w, h)
21921 Roo.log('resize: ' +w + ',' + h );
21922 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21926 if(typeof w == 'number'){
21928 this.iframe.style.width = w + 'px';
21930 if(typeof h == 'number'){
21932 this.iframe.style.height = h + 'px';
21934 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21941 * Toggles the editor between standard and source edit mode.
21942 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21944 toggleSourceEdit : function(sourceEditMode){
21946 this.sourceEditMode = sourceEditMode === true;
21948 if(this.sourceEditMode){
21950 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21953 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21954 //this.iframe.className = '';
21957 //this.setSize(this.owner.wrap.getSize());
21958 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21965 * Protected method that will not generally be called directly. If you need/want
21966 * custom HTML cleanup, this is the method you should override.
21967 * @param {String} html The HTML to be cleaned
21968 * return {String} The cleaned HTML
21970 cleanHtml : function(html){
21971 html = String(html);
21972 if(html.length > 5){
21973 if(Roo.isSafari){ // strip safari nonsense
21974 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21977 if(html == ' '){
21984 * HTML Editor -> Textarea
21985 * Protected method that will not generally be called directly. Syncs the contents
21986 * of the editor iframe with the textarea.
21988 syncValue : function(){
21989 if(this.initialized){
21990 var bd = (this.doc.body || this.doc.documentElement);
21991 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21992 var html = bd.innerHTML;
21994 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21995 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21997 html = '<div style="'+m[0]+'">' + html + '</div>';
22000 html = this.cleanHtml(html);
22001 // fix up the special chars.. normaly like back quotes in word...
22002 // however we do not want to do this with chinese..
22003 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22004 var cc = b.charCodeAt();
22006 (cc >= 0x4E00 && cc < 0xA000 ) ||
22007 (cc >= 0x3400 && cc < 0x4E00 ) ||
22008 (cc >= 0xf900 && cc < 0xfb00 )
22014 if(this.owner.fireEvent('beforesync', this, html) !== false){
22015 this.el.dom.value = html;
22016 this.owner.fireEvent('sync', this, html);
22022 * Protected method that will not generally be called directly. Pushes the value of the textarea
22023 * into the iframe editor.
22025 pushValue : function(){
22026 if(this.initialized){
22027 var v = this.el.dom.value.trim();
22029 // if(v.length < 1){
22033 if(this.owner.fireEvent('beforepush', this, v) !== false){
22034 var d = (this.doc.body || this.doc.documentElement);
22036 this.cleanUpPaste();
22037 this.el.dom.value = d.innerHTML;
22038 this.owner.fireEvent('push', this, v);
22044 deferFocus : function(){
22045 this.focus.defer(10, this);
22049 focus : function(){
22050 if(this.win && !this.sourceEditMode){
22057 assignDocWin: function()
22059 var iframe = this.iframe;
22062 this.doc = iframe.contentWindow.document;
22063 this.win = iframe.contentWindow;
22065 // if (!Roo.get(this.frameId)) {
22068 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22069 // this.win = Roo.get(this.frameId).dom.contentWindow;
22071 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22075 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22076 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22081 initEditor : function(){
22082 //console.log("INIT EDITOR");
22083 this.assignDocWin();
22087 this.doc.designMode="on";
22089 this.doc.write(this.getDocMarkup());
22092 var dbody = (this.doc.body || this.doc.documentElement);
22093 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22094 // this copies styles from the containing element into thsi one..
22095 // not sure why we need all of this..
22096 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22098 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22099 //ss['background-attachment'] = 'fixed'; // w3c
22100 dbody.bgProperties = 'fixed'; // ie
22101 //Roo.DomHelper.applyStyles(dbody, ss);
22102 Roo.EventManager.on(this.doc, {
22103 //'mousedown': this.onEditorEvent,
22104 'mouseup': this.onEditorEvent,
22105 'dblclick': this.onEditorEvent,
22106 'click': this.onEditorEvent,
22107 'keyup': this.onEditorEvent,
22112 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22114 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22115 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22117 this.initialized = true;
22119 this.owner.fireEvent('initialize', this);
22124 onDestroy : function(){
22130 //for (var i =0; i < this.toolbars.length;i++) {
22131 // // fixme - ask toolbars for heights?
22132 // this.toolbars[i].onDestroy();
22135 //this.wrap.dom.innerHTML = '';
22136 //this.wrap.remove();
22141 onFirstFocus : function(){
22143 this.assignDocWin();
22146 this.activated = true;
22149 if(Roo.isGecko){ // prevent silly gecko errors
22151 var s = this.win.getSelection();
22152 if(!s.focusNode || s.focusNode.nodeType != 3){
22153 var r = s.getRangeAt(0);
22154 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22159 this.execCmd('useCSS', true);
22160 this.execCmd('styleWithCSS', false);
22163 this.owner.fireEvent('activate', this);
22167 adjustFont: function(btn){
22168 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22169 //if(Roo.isSafari){ // safari
22172 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22173 if(Roo.isSafari){ // safari
22174 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22175 v = (v < 10) ? 10 : v;
22176 v = (v > 48) ? 48 : v;
22177 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22182 v = Math.max(1, v+adjust);
22184 this.execCmd('FontSize', v );
22187 onEditorEvent : function(e)
22189 this.owner.fireEvent('editorevent', this, e);
22190 // this.updateToolbar();
22191 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22194 insertTag : function(tg)
22196 // could be a bit smarter... -> wrap the current selected tRoo..
22197 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22199 range = this.createRange(this.getSelection());
22200 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22201 wrappingNode.appendChild(range.extractContents());
22202 range.insertNode(wrappingNode);
22209 this.execCmd("formatblock", tg);
22213 insertText : function(txt)
22217 var range = this.createRange();
22218 range.deleteContents();
22219 //alert(Sender.getAttribute('label'));
22221 range.insertNode(this.doc.createTextNode(txt));
22227 * Executes a Midas editor command on the editor document and performs necessary focus and
22228 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22229 * @param {String} cmd The Midas command
22230 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22232 relayCmd : function(cmd, value){
22234 this.execCmd(cmd, value);
22235 this.owner.fireEvent('editorevent', this);
22236 //this.updateToolbar();
22237 this.owner.deferFocus();
22241 * Executes a Midas editor command directly on the editor document.
22242 * For visual commands, you should use {@link #relayCmd} instead.
22243 * <b>This should only be called after the editor is initialized.</b>
22244 * @param {String} cmd The Midas command
22245 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22247 execCmd : function(cmd, value){
22248 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22255 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22257 * @param {String} text | dom node..
22259 insertAtCursor : function(text)
22262 if(!this.activated){
22268 var r = this.doc.selection.createRange();
22279 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22283 // from jquery ui (MIT licenced)
22285 var win = this.win;
22287 if (win.getSelection && win.getSelection().getRangeAt) {
22288 range = win.getSelection().getRangeAt(0);
22289 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22290 range.insertNode(node);
22291 } else if (win.document.selection && win.document.selection.createRange) {
22292 // no firefox support
22293 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22294 win.document.selection.createRange().pasteHTML(txt);
22296 // no firefox support
22297 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22298 this.execCmd('InsertHTML', txt);
22307 mozKeyPress : function(e){
22309 var c = e.getCharCode(), cmd;
22312 c = String.fromCharCode(c).toLowerCase();
22326 this.cleanUpPaste.defer(100, this);
22334 e.preventDefault();
22342 fixKeys : function(){ // load time branching for fastest keydown performance
22344 return function(e){
22345 var k = e.getKey(), r;
22348 r = this.doc.selection.createRange();
22351 r.pasteHTML('    ');
22358 r = this.doc.selection.createRange();
22360 var target = r.parentElement();
22361 if(!target || target.tagName.toLowerCase() != 'li'){
22363 r.pasteHTML('<br />');
22369 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22370 this.cleanUpPaste.defer(100, this);
22376 }else if(Roo.isOpera){
22377 return function(e){
22378 var k = e.getKey();
22382 this.execCmd('InsertHTML','    ');
22385 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22386 this.cleanUpPaste.defer(100, this);
22391 }else if(Roo.isSafari){
22392 return function(e){
22393 var k = e.getKey();
22397 this.execCmd('InsertText','\t');
22401 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22402 this.cleanUpPaste.defer(100, this);
22410 getAllAncestors: function()
22412 var p = this.getSelectedNode();
22415 a.push(p); // push blank onto stack..
22416 p = this.getParentElement();
22420 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22424 a.push(this.doc.body);
22428 lastSelNode : false,
22431 getSelection : function()
22433 this.assignDocWin();
22434 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22437 getSelectedNode: function()
22439 // this may only work on Gecko!!!
22441 // should we cache this!!!!
22446 var range = this.createRange(this.getSelection()).cloneRange();
22449 var parent = range.parentElement();
22451 var testRange = range.duplicate();
22452 testRange.moveToElementText(parent);
22453 if (testRange.inRange(range)) {
22456 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22459 parent = parent.parentElement;
22464 // is ancestor a text element.
22465 var ac = range.commonAncestorContainer;
22466 if (ac.nodeType == 3) {
22467 ac = ac.parentNode;
22470 var ar = ac.childNodes;
22473 var other_nodes = [];
22474 var has_other_nodes = false;
22475 for (var i=0;i<ar.length;i++) {
22476 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22479 // fullly contained node.
22481 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22486 // probably selected..
22487 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22488 other_nodes.push(ar[i]);
22492 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22497 has_other_nodes = true;
22499 if (!nodes.length && other_nodes.length) {
22500 nodes= other_nodes;
22502 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22508 createRange: function(sel)
22510 // this has strange effects when using with
22511 // top toolbar - not sure if it's a great idea.
22512 //this.editor.contentWindow.focus();
22513 if (typeof sel != "undefined") {
22515 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22517 return this.doc.createRange();
22520 return this.doc.createRange();
22523 getParentElement: function()
22526 this.assignDocWin();
22527 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22529 var range = this.createRange(sel);
22532 var p = range.commonAncestorContainer;
22533 while (p.nodeType == 3) { // text node
22544 * Range intersection.. the hard stuff...
22548 * [ -- selected range --- ]
22552 * if end is before start or hits it. fail.
22553 * if start is after end or hits it fail.
22555 * if either hits (but other is outside. - then it's not
22561 // @see http://www.thismuchiknow.co.uk/?p=64.
22562 rangeIntersectsNode : function(range, node)
22564 var nodeRange = node.ownerDocument.createRange();
22566 nodeRange.selectNode(node);
22568 nodeRange.selectNodeContents(node);
22571 var rangeStartRange = range.cloneRange();
22572 rangeStartRange.collapse(true);
22574 var rangeEndRange = range.cloneRange();
22575 rangeEndRange.collapse(false);
22577 var nodeStartRange = nodeRange.cloneRange();
22578 nodeStartRange.collapse(true);
22580 var nodeEndRange = nodeRange.cloneRange();
22581 nodeEndRange.collapse(false);
22583 return rangeStartRange.compareBoundaryPoints(
22584 Range.START_TO_START, nodeEndRange) == -1 &&
22585 rangeEndRange.compareBoundaryPoints(
22586 Range.START_TO_START, nodeStartRange) == 1;
22590 rangeCompareNode : function(range, node)
22592 var nodeRange = node.ownerDocument.createRange();
22594 nodeRange.selectNode(node);
22596 nodeRange.selectNodeContents(node);
22600 range.collapse(true);
22602 nodeRange.collapse(true);
22604 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22605 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22607 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22609 var nodeIsBefore = ss == 1;
22610 var nodeIsAfter = ee == -1;
22612 if (nodeIsBefore && nodeIsAfter) {
22615 if (!nodeIsBefore && nodeIsAfter) {
22616 return 1; //right trailed.
22619 if (nodeIsBefore && !nodeIsAfter) {
22620 return 2; // left trailed.
22626 // private? - in a new class?
22627 cleanUpPaste : function()
22629 // cleans up the whole document..
22630 Roo.log('cleanuppaste');
22632 this.cleanUpChildren(this.doc.body);
22633 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22634 if (clean != this.doc.body.innerHTML) {
22635 this.doc.body.innerHTML = clean;
22640 cleanWordChars : function(input) {// change the chars to hex code
22641 var he = Roo.HtmlEditorCore;
22643 var output = input;
22644 Roo.each(he.swapCodes, function(sw) {
22645 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22647 output = output.replace(swapper, sw[1]);
22654 cleanUpChildren : function (n)
22656 if (!n.childNodes.length) {
22659 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22660 this.cleanUpChild(n.childNodes[i]);
22667 cleanUpChild : function (node)
22670 //console.log(node);
22671 if (node.nodeName == "#text") {
22672 // clean up silly Windows -- stuff?
22675 if (node.nodeName == "#comment") {
22676 node.parentNode.removeChild(node);
22677 // clean up silly Windows -- stuff?
22680 var lcname = node.tagName.toLowerCase();
22681 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22682 // whitelist of tags..
22684 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22686 node.parentNode.removeChild(node);
22691 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22693 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22694 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22696 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22697 // remove_keep_children = true;
22700 if (remove_keep_children) {
22701 this.cleanUpChildren(node);
22702 // inserts everything just before this node...
22703 while (node.childNodes.length) {
22704 var cn = node.childNodes[0];
22705 node.removeChild(cn);
22706 node.parentNode.insertBefore(cn, node);
22708 node.parentNode.removeChild(node);
22712 if (!node.attributes || !node.attributes.length) {
22713 this.cleanUpChildren(node);
22717 function cleanAttr(n,v)
22720 if (v.match(/^\./) || v.match(/^\//)) {
22723 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22726 if (v.match(/^#/)) {
22729 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22730 node.removeAttribute(n);
22734 var cwhite = this.cwhite;
22735 var cblack = this.cblack;
22737 function cleanStyle(n,v)
22739 if (v.match(/expression/)) { //XSS?? should we even bother..
22740 node.removeAttribute(n);
22744 var parts = v.split(/;/);
22747 Roo.each(parts, function(p) {
22748 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22752 var l = p.split(':').shift().replace(/\s+/g,'');
22753 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22755 if ( cwhite.length && cblack.indexOf(l) > -1) {
22756 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22757 //node.removeAttribute(n);
22761 // only allow 'c whitelisted system attributes'
22762 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22763 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22764 //node.removeAttribute(n);
22774 if (clean.length) {
22775 node.setAttribute(n, clean.join(';'));
22777 node.removeAttribute(n);
22783 for (var i = node.attributes.length-1; i > -1 ; i--) {
22784 var a = node.attributes[i];
22787 if (a.name.toLowerCase().substr(0,2)=='on') {
22788 node.removeAttribute(a.name);
22791 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22792 node.removeAttribute(a.name);
22795 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22796 cleanAttr(a.name,a.value); // fixme..
22799 if (a.name == 'style') {
22800 cleanStyle(a.name,a.value);
22803 /// clean up MS crap..
22804 // tecnically this should be a list of valid class'es..
22807 if (a.name == 'class') {
22808 if (a.value.match(/^Mso/)) {
22809 node.className = '';
22812 if (a.value.match(/^body$/)) {
22813 node.className = '';
22824 this.cleanUpChildren(node);
22830 * Clean up MS wordisms...
22832 cleanWord : function(node)
22837 this.cleanWord(this.doc.body);
22840 if (node.nodeName == "#text") {
22841 // clean up silly Windows -- stuff?
22844 if (node.nodeName == "#comment") {
22845 node.parentNode.removeChild(node);
22846 // clean up silly Windows -- stuff?
22850 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22851 node.parentNode.removeChild(node);
22855 // remove - but keep children..
22856 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22857 while (node.childNodes.length) {
22858 var cn = node.childNodes[0];
22859 node.removeChild(cn);
22860 node.parentNode.insertBefore(cn, node);
22862 node.parentNode.removeChild(node);
22863 this.iterateChildren(node, this.cleanWord);
22867 if (node.className.length) {
22869 var cn = node.className.split(/\W+/);
22871 Roo.each(cn, function(cls) {
22872 if (cls.match(/Mso[a-zA-Z]+/)) {
22877 node.className = cna.length ? cna.join(' ') : '';
22879 node.removeAttribute("class");
22883 if (node.hasAttribute("lang")) {
22884 node.removeAttribute("lang");
22887 if (node.hasAttribute("style")) {
22889 var styles = node.getAttribute("style").split(";");
22891 Roo.each(styles, function(s) {
22892 if (!s.match(/:/)) {
22895 var kv = s.split(":");
22896 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22899 // what ever is left... we allow.
22902 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22903 if (!nstyle.length) {
22904 node.removeAttribute('style');
22907 this.iterateChildren(node, this.cleanWord);
22913 * iterateChildren of a Node, calling fn each time, using this as the scole..
22914 * @param {DomNode} node node to iterate children of.
22915 * @param {Function} fn method of this class to call on each item.
22917 iterateChildren : function(node, fn)
22919 if (!node.childNodes.length) {
22922 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22923 fn.call(this, node.childNodes[i])
22929 * cleanTableWidths.
22931 * Quite often pasting from word etc.. results in tables with column and widths.
22932 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22935 cleanTableWidths : function(node)
22940 this.cleanTableWidths(this.doc.body);
22945 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22948 Roo.log(node.tagName);
22949 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22950 this.iterateChildren(node, this.cleanTableWidths);
22953 if (node.hasAttribute('width')) {
22954 node.removeAttribute('width');
22958 if (node.hasAttribute("style")) {
22961 var styles = node.getAttribute("style").split(";");
22963 Roo.each(styles, function(s) {
22964 if (!s.match(/:/)) {
22967 var kv = s.split(":");
22968 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22971 // what ever is left... we allow.
22974 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22975 if (!nstyle.length) {
22976 node.removeAttribute('style');
22980 this.iterateChildren(node, this.cleanTableWidths);
22988 domToHTML : function(currentElement, depth, nopadtext) {
22990 depth = depth || 0;
22991 nopadtext = nopadtext || false;
22993 if (!currentElement) {
22994 return this.domToHTML(this.doc.body);
22997 //Roo.log(currentElement);
22999 var allText = false;
23000 var nodeName = currentElement.nodeName;
23001 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23003 if (nodeName == '#text') {
23005 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23010 if (nodeName != 'BODY') {
23013 // Prints the node tagName, such as <A>, <IMG>, etc
23016 for(i = 0; i < currentElement.attributes.length;i++) {
23018 var aname = currentElement.attributes.item(i).name;
23019 if (!currentElement.attributes.item(i).value.length) {
23022 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23025 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23034 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23037 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23042 // Traverse the tree
23044 var currentElementChild = currentElement.childNodes.item(i);
23045 var allText = true;
23046 var innerHTML = '';
23048 while (currentElementChild) {
23049 // Formatting code (indent the tree so it looks nice on the screen)
23050 var nopad = nopadtext;
23051 if (lastnode == 'SPAN') {
23055 if (currentElementChild.nodeName == '#text') {
23056 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23057 toadd = nopadtext ? toadd : toadd.trim();
23058 if (!nopad && toadd.length > 80) {
23059 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23061 innerHTML += toadd;
23064 currentElementChild = currentElement.childNodes.item(i);
23070 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23072 // Recursively traverse the tree structure of the child node
23073 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23074 lastnode = currentElementChild.nodeName;
23076 currentElementChild=currentElement.childNodes.item(i);
23082 // The remaining code is mostly for formatting the tree
23083 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23088 ret+= "</"+tagName+">";
23094 applyBlacklists : function()
23096 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23097 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23101 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23102 if (b.indexOf(tag) > -1) {
23105 this.white.push(tag);
23109 Roo.each(w, function(tag) {
23110 if (b.indexOf(tag) > -1) {
23113 if (this.white.indexOf(tag) > -1) {
23116 this.white.push(tag);
23121 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23122 if (w.indexOf(tag) > -1) {
23125 this.black.push(tag);
23129 Roo.each(b, function(tag) {
23130 if (w.indexOf(tag) > -1) {
23133 if (this.black.indexOf(tag) > -1) {
23136 this.black.push(tag);
23141 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23142 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23146 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23147 if (b.indexOf(tag) > -1) {
23150 this.cwhite.push(tag);
23154 Roo.each(w, function(tag) {
23155 if (b.indexOf(tag) > -1) {
23158 if (this.cwhite.indexOf(tag) > -1) {
23161 this.cwhite.push(tag);
23166 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23167 if (w.indexOf(tag) > -1) {
23170 this.cblack.push(tag);
23174 Roo.each(b, function(tag) {
23175 if (w.indexOf(tag) > -1) {
23178 if (this.cblack.indexOf(tag) > -1) {
23181 this.cblack.push(tag);
23186 setStylesheets : function(stylesheets)
23188 if(typeof(stylesheets) == 'string'){
23189 Roo.get(this.iframe.contentDocument.head).createChild({
23191 rel : 'stylesheet',
23200 Roo.each(stylesheets, function(s) {
23205 Roo.get(_this.iframe.contentDocument.head).createChild({
23207 rel : 'stylesheet',
23216 removeStylesheets : function()
23220 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23225 setStyle : function(style)
23227 Roo.get(this.iframe.contentDocument.head).createChild({
23236 // hide stuff that is not compatible
23250 * @event specialkey
23254 * @cfg {String} fieldClass @hide
23257 * @cfg {String} focusClass @hide
23260 * @cfg {String} autoCreate @hide
23263 * @cfg {String} inputType @hide
23266 * @cfg {String} invalidClass @hide
23269 * @cfg {String} invalidText @hide
23272 * @cfg {String} msgFx @hide
23275 * @cfg {String} validateOnBlur @hide
23279 Roo.HtmlEditorCore.white = [
23280 'area', 'br', 'img', 'input', 'hr', 'wbr',
23282 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23283 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23284 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23285 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23286 'table', 'ul', 'xmp',
23288 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23291 'dir', 'menu', 'ol', 'ul', 'dl',
23297 Roo.HtmlEditorCore.black = [
23298 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23300 'base', 'basefont', 'bgsound', 'blink', 'body',
23301 'frame', 'frameset', 'head', 'html', 'ilayer',
23302 'iframe', 'layer', 'link', 'meta', 'object',
23303 'script', 'style' ,'title', 'xml' // clean later..
23305 Roo.HtmlEditorCore.clean = [
23306 'script', 'style', 'title', 'xml'
23308 Roo.HtmlEditorCore.remove = [
23313 Roo.HtmlEditorCore.ablack = [
23317 Roo.HtmlEditorCore.aclean = [
23318 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23322 Roo.HtmlEditorCore.pwhite= [
23323 'http', 'https', 'mailto'
23326 // white listed style attributes.
23327 Roo.HtmlEditorCore.cwhite= [
23328 // 'text-align', /// default is to allow most things..
23334 // black listed style attributes.
23335 Roo.HtmlEditorCore.cblack= [
23336 // 'font-size' -- this can be set by the project
23340 Roo.HtmlEditorCore.swapCodes =[
23359 * @class Roo.bootstrap.HtmlEditor
23360 * @extends Roo.bootstrap.TextArea
23361 * Bootstrap HtmlEditor class
23364 * Create a new HtmlEditor
23365 * @param {Object} config The config object
23368 Roo.bootstrap.HtmlEditor = function(config){
23369 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23370 if (!this.toolbars) {
23371 this.toolbars = [];
23374 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23377 * @event initialize
23378 * Fires when the editor is fully initialized (including the iframe)
23379 * @param {HtmlEditor} this
23384 * Fires when the editor is first receives the focus. Any insertion must wait
23385 * until after this event.
23386 * @param {HtmlEditor} this
23390 * @event beforesync
23391 * Fires before the textarea is updated with content from the editor iframe. Return false
23392 * to cancel the sync.
23393 * @param {HtmlEditor} this
23394 * @param {String} html
23398 * @event beforepush
23399 * Fires before the iframe editor is updated with content from the textarea. Return false
23400 * to cancel the push.
23401 * @param {HtmlEditor} this
23402 * @param {String} html
23407 * Fires when the textarea is updated with content from the editor iframe.
23408 * @param {HtmlEditor} this
23409 * @param {String} html
23414 * Fires when the iframe editor is updated with content from the textarea.
23415 * @param {HtmlEditor} this
23416 * @param {String} html
23420 * @event editmodechange
23421 * Fires when the editor switches edit modes
23422 * @param {HtmlEditor} this
23423 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23425 editmodechange: true,
23427 * @event editorevent
23428 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23429 * @param {HtmlEditor} this
23433 * @event firstfocus
23434 * Fires when on first focus - needed by toolbars..
23435 * @param {HtmlEditor} this
23440 * Auto save the htmlEditor value as a file into Events
23441 * @param {HtmlEditor} this
23445 * @event savedpreview
23446 * preview the saved version of htmlEditor
23447 * @param {HtmlEditor} this
23454 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23458 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23463 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23468 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23473 * @cfg {Number} height (in pixels)
23477 * @cfg {Number} width (in pixels)
23482 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23485 stylesheets: false,
23490 // private properties
23491 validationEvent : false,
23493 initialized : false,
23496 onFocus : Roo.emptyFn,
23498 hideMode:'offsets',
23500 tbContainer : false,
23504 toolbarContainer :function() {
23505 return this.wrap.select('.x-html-editor-tb',true).first();
23509 * Protected method that will not generally be called directly. It
23510 * is called when the editor creates its toolbar. Override this method if you need to
23511 * add custom toolbar buttons.
23512 * @param {HtmlEditor} editor
23514 createToolbar : function(){
23515 Roo.log('renewing');
23516 Roo.log("create toolbars");
23518 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23519 this.toolbars[0].render(this.toolbarContainer());
23523 // if (!editor.toolbars || !editor.toolbars.length) {
23524 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23527 // for (var i =0 ; i < editor.toolbars.length;i++) {
23528 // editor.toolbars[i] = Roo.factory(
23529 // typeof(editor.toolbars[i]) == 'string' ?
23530 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23531 // Roo.bootstrap.HtmlEditor);
23532 // editor.toolbars[i].init(editor);
23538 onRender : function(ct, position)
23540 // Roo.log("Call onRender: " + this.xtype);
23542 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23544 this.wrap = this.inputEl().wrap({
23545 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23548 this.editorcore.onRender(ct, position);
23550 if (this.resizable) {
23551 this.resizeEl = new Roo.Resizable(this.wrap, {
23555 minHeight : this.height,
23556 height: this.height,
23557 handles : this.resizable,
23560 resize : function(r, w, h) {
23561 _t.onResize(w,h); // -something
23567 this.createToolbar(this);
23570 if(!this.width && this.resizable){
23571 this.setSize(this.wrap.getSize());
23573 if (this.resizeEl) {
23574 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23575 // should trigger onReize..
23581 onResize : function(w, h)
23583 Roo.log('resize: ' +w + ',' + h );
23584 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23588 if(this.inputEl() ){
23589 if(typeof w == 'number'){
23590 var aw = w - this.wrap.getFrameWidth('lr');
23591 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23594 if(typeof h == 'number'){
23595 var tbh = -11; // fixme it needs to tool bar size!
23596 for (var i =0; i < this.toolbars.length;i++) {
23597 // fixme - ask toolbars for heights?
23598 tbh += this.toolbars[i].el.getHeight();
23599 //if (this.toolbars[i].footer) {
23600 // tbh += this.toolbars[i].footer.el.getHeight();
23608 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23609 ah -= 5; // knock a few pixes off for look..
23610 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23614 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23615 this.editorcore.onResize(ew,eh);
23620 * Toggles the editor between standard and source edit mode.
23621 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23623 toggleSourceEdit : function(sourceEditMode)
23625 this.editorcore.toggleSourceEdit(sourceEditMode);
23627 if(this.editorcore.sourceEditMode){
23628 Roo.log('editor - showing textarea');
23631 // Roo.log(this.syncValue());
23633 this.inputEl().removeClass(['hide', 'x-hidden']);
23634 this.inputEl().dom.removeAttribute('tabIndex');
23635 this.inputEl().focus();
23637 Roo.log('editor - hiding textarea');
23639 // Roo.log(this.pushValue());
23642 this.inputEl().addClass(['hide', 'x-hidden']);
23643 this.inputEl().dom.setAttribute('tabIndex', -1);
23644 //this.deferFocus();
23647 if(this.resizable){
23648 this.setSize(this.wrap.getSize());
23651 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23654 // private (for BoxComponent)
23655 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23657 // private (for BoxComponent)
23658 getResizeEl : function(){
23662 // private (for BoxComponent)
23663 getPositionEl : function(){
23668 initEvents : function(){
23669 this.originalValue = this.getValue();
23673 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23676 // markInvalid : Roo.emptyFn,
23678 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23681 // clearInvalid : Roo.emptyFn,
23683 setValue : function(v){
23684 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23685 this.editorcore.pushValue();
23690 deferFocus : function(){
23691 this.focus.defer(10, this);
23695 focus : function(){
23696 this.editorcore.focus();
23702 onDestroy : function(){
23708 for (var i =0; i < this.toolbars.length;i++) {
23709 // fixme - ask toolbars for heights?
23710 this.toolbars[i].onDestroy();
23713 this.wrap.dom.innerHTML = '';
23714 this.wrap.remove();
23719 onFirstFocus : function(){
23720 //Roo.log("onFirstFocus");
23721 this.editorcore.onFirstFocus();
23722 for (var i =0; i < this.toolbars.length;i++) {
23723 this.toolbars[i].onFirstFocus();
23729 syncValue : function()
23731 this.editorcore.syncValue();
23734 pushValue : function()
23736 this.editorcore.pushValue();
23740 // hide stuff that is not compatible
23754 * @event specialkey
23758 * @cfg {String} fieldClass @hide
23761 * @cfg {String} focusClass @hide
23764 * @cfg {String} autoCreate @hide
23767 * @cfg {String} inputType @hide
23770 * @cfg {String} invalidClass @hide
23773 * @cfg {String} invalidText @hide
23776 * @cfg {String} msgFx @hide
23779 * @cfg {String} validateOnBlur @hide
23788 Roo.namespace('Roo.bootstrap.htmleditor');
23790 * @class Roo.bootstrap.HtmlEditorToolbar1
23795 new Roo.bootstrap.HtmlEditor({
23798 new Roo.bootstrap.HtmlEditorToolbar1({
23799 disable : { fonts: 1 , format: 1, ..., ... , ...],
23805 * @cfg {Object} disable List of elements to disable..
23806 * @cfg {Array} btns List of additional buttons.
23810 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23813 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23816 Roo.apply(this, config);
23818 // default disabled, based on 'good practice'..
23819 this.disable = this.disable || {};
23820 Roo.applyIf(this.disable, {
23823 specialElements : true
23825 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23827 this.editor = config.editor;
23828 this.editorcore = config.editor.editorcore;
23830 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23832 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23833 // dont call parent... till later.
23835 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23840 editorcore : false,
23845 "h1","h2","h3","h4","h5","h6",
23847 "abbr", "acronym", "address", "cite", "samp", "var",
23851 onRender : function(ct, position)
23853 // Roo.log("Call onRender: " + this.xtype);
23855 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23857 this.el.dom.style.marginBottom = '0';
23859 var editorcore = this.editorcore;
23860 var editor= this.editor;
23863 var btn = function(id,cmd , toggle, handler, html){
23865 var event = toggle ? 'toggle' : 'click';
23870 xns: Roo.bootstrap,
23873 enableToggle:toggle !== false,
23875 pressed : toggle ? false : null,
23878 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23879 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23885 // var cb_box = function...
23890 xns: Roo.bootstrap,
23891 glyphicon : 'font',
23895 xns: Roo.bootstrap,
23899 Roo.each(this.formats, function(f) {
23900 style.menu.items.push({
23902 xns: Roo.bootstrap,
23903 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23908 editorcore.insertTag(this.tagname);
23915 children.push(style);
23917 btn('bold',false,true);
23918 btn('italic',false,true);
23919 btn('align-left', 'justifyleft',true);
23920 btn('align-center', 'justifycenter',true);
23921 btn('align-right' , 'justifyright',true);
23922 btn('link', false, false, function(btn) {
23923 //Roo.log("create link?");
23924 var url = prompt(this.createLinkText, this.defaultLinkValue);
23925 if(url && url != 'http:/'+'/'){
23926 this.editorcore.relayCmd('createlink', url);
23929 btn('list','insertunorderedlist',true);
23930 btn('pencil', false,true, function(btn){
23932 this.toggleSourceEdit(btn.pressed);
23935 if (this.editor.btns.length > 0) {
23936 for (var i = 0; i<this.editor.btns.length; i++) {
23937 children.push(this.editor.btns[i]);
23945 xns: Roo.bootstrap,
23950 xns: Roo.bootstrap,
23955 cog.menu.items.push({
23957 xns: Roo.bootstrap,
23958 html : Clean styles,
23963 editorcore.insertTag(this.tagname);
23972 this.xtype = 'NavSimplebar';
23974 for(var i=0;i< children.length;i++) {
23976 this.buttons.add(this.addxtypeChild(children[i]));
23980 editor.on('editorevent', this.updateToolbar, this);
23982 onBtnClick : function(id)
23984 this.editorcore.relayCmd(id);
23985 this.editorcore.focus();
23989 * Protected method that will not generally be called directly. It triggers
23990 * a toolbar update by reading the markup state of the current selection in the editor.
23992 updateToolbar: function(){
23994 if(!this.editorcore.activated){
23995 this.editor.onFirstFocus(); // is this neeed?
23999 var btns = this.buttons;
24000 var doc = this.editorcore.doc;
24001 btns.get('bold').setActive(doc.queryCommandState('bold'));
24002 btns.get('italic').setActive(doc.queryCommandState('italic'));
24003 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24005 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24006 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24007 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24009 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24010 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24013 var ans = this.editorcore.getAllAncestors();
24014 if (this.formatCombo) {
24017 var store = this.formatCombo.store;
24018 this.formatCombo.setValue("");
24019 for (var i =0; i < ans.length;i++) {
24020 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24022 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24030 // hides menus... - so this cant be on a menu...
24031 Roo.bootstrap.MenuMgr.hideAll();
24033 Roo.bootstrap.MenuMgr.hideAll();
24034 //this.editorsyncValue();
24036 onFirstFocus: function() {
24037 this.buttons.each(function(item){
24041 toggleSourceEdit : function(sourceEditMode){
24044 if(sourceEditMode){
24045 Roo.log("disabling buttons");
24046 this.buttons.each( function(item){
24047 if(item.cmd != 'pencil'){
24053 Roo.log("enabling buttons");
24054 if(this.editorcore.initialized){
24055 this.buttons.each( function(item){
24061 Roo.log("calling toggole on editor");
24062 // tell the editor that it's been pressed..
24063 this.editor.toggleSourceEdit(sourceEditMode);
24073 * @class Roo.bootstrap.Table.AbstractSelectionModel
24074 * @extends Roo.util.Observable
24075 * Abstract base class for grid SelectionModels. It provides the interface that should be
24076 * implemented by descendant classes. This class should not be directly instantiated.
24079 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24080 this.locked = false;
24081 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24085 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24086 /** @ignore Called by the grid automatically. Do not call directly. */
24087 init : function(grid){
24093 * Locks the selections.
24096 this.locked = true;
24100 * Unlocks the selections.
24102 unlock : function(){
24103 this.locked = false;
24107 * Returns true if the selections are locked.
24108 * @return {Boolean}
24110 isLocked : function(){
24111 return this.locked;
24115 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24116 * @class Roo.bootstrap.Table.RowSelectionModel
24117 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24118 * It supports multiple selections and keyboard selection/navigation.
24120 * @param {Object} config
24123 Roo.bootstrap.Table.RowSelectionModel = function(config){
24124 Roo.apply(this, config);
24125 this.selections = new Roo.util.MixedCollection(false, function(o){
24130 this.lastActive = false;
24134 * @event selectionchange
24135 * Fires when the selection changes
24136 * @param {SelectionModel} this
24138 "selectionchange" : true,
24140 * @event afterselectionchange
24141 * Fires after the selection changes (eg. by key press or clicking)
24142 * @param {SelectionModel} this
24144 "afterselectionchange" : true,
24146 * @event beforerowselect
24147 * Fires when a row is selected being selected, return false to cancel.
24148 * @param {SelectionModel} this
24149 * @param {Number} rowIndex The selected index
24150 * @param {Boolean} keepExisting False if other selections will be cleared
24152 "beforerowselect" : true,
24155 * Fires when a row is selected.
24156 * @param {SelectionModel} this
24157 * @param {Number} rowIndex The selected index
24158 * @param {Roo.data.Record} r The record
24160 "rowselect" : true,
24162 * @event rowdeselect
24163 * Fires when a row is deselected.
24164 * @param {SelectionModel} this
24165 * @param {Number} rowIndex The selected index
24167 "rowdeselect" : true
24169 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24170 this.locked = false;
24173 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24175 * @cfg {Boolean} singleSelect
24176 * True to allow selection of only one row at a time (defaults to false)
24178 singleSelect : false,
24181 initEvents : function()
24184 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24185 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24186 //}else{ // allow click to work like normal
24187 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24189 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24190 this.grid.on("rowclick", this.handleMouseDown, this);
24192 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24193 "up" : function(e){
24195 this.selectPrevious(e.shiftKey);
24196 }else if(this.last !== false && this.lastActive !== false){
24197 var last = this.last;
24198 this.selectRange(this.last, this.lastActive-1);
24199 this.grid.getView().focusRow(this.lastActive);
24200 if(last !== false){
24204 this.selectFirstRow();
24206 this.fireEvent("afterselectionchange", this);
24208 "down" : function(e){
24210 this.selectNext(e.shiftKey);
24211 }else if(this.last !== false && this.lastActive !== false){
24212 var last = this.last;
24213 this.selectRange(this.last, this.lastActive+1);
24214 this.grid.getView().focusRow(this.lastActive);
24215 if(last !== false){
24219 this.selectFirstRow();
24221 this.fireEvent("afterselectionchange", this);
24225 this.grid.store.on('load', function(){
24226 this.selections.clear();
24229 var view = this.grid.view;
24230 view.on("refresh", this.onRefresh, this);
24231 view.on("rowupdated", this.onRowUpdated, this);
24232 view.on("rowremoved", this.onRemove, this);
24237 onRefresh : function()
24239 var ds = this.grid.store, i, v = this.grid.view;
24240 var s = this.selections;
24241 s.each(function(r){
24242 if((i = ds.indexOfId(r.id)) != -1){
24251 onRemove : function(v, index, r){
24252 this.selections.remove(r);
24256 onRowUpdated : function(v, index, r){
24257 if(this.isSelected(r)){
24258 v.onRowSelect(index);
24264 * @param {Array} records The records to select
24265 * @param {Boolean} keepExisting (optional) True to keep existing selections
24267 selectRecords : function(records, keepExisting)
24270 this.clearSelections();
24272 var ds = this.grid.store;
24273 for(var i = 0, len = records.length; i < len; i++){
24274 this.selectRow(ds.indexOf(records[i]), true);
24279 * Gets the number of selected rows.
24282 getCount : function(){
24283 return this.selections.length;
24287 * Selects the first row in the grid.
24289 selectFirstRow : function(){
24294 * Select the last row.
24295 * @param {Boolean} keepExisting (optional) True to keep existing selections
24297 selectLastRow : function(keepExisting){
24298 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24299 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24303 * Selects the row immediately following the last selected row.
24304 * @param {Boolean} keepExisting (optional) True to keep existing selections
24306 selectNext : function(keepExisting)
24308 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24309 this.selectRow(this.last+1, keepExisting);
24310 this.grid.getView().focusRow(this.last);
24315 * Selects the row that precedes the last selected row.
24316 * @param {Boolean} keepExisting (optional) True to keep existing selections
24318 selectPrevious : function(keepExisting){
24320 this.selectRow(this.last-1, keepExisting);
24321 this.grid.getView().focusRow(this.last);
24326 * Returns the selected records
24327 * @return {Array} Array of selected records
24329 getSelections : function(){
24330 return [].concat(this.selections.items);
24334 * Returns the first selected record.
24337 getSelected : function(){
24338 return this.selections.itemAt(0);
24343 * Clears all selections.
24345 clearSelections : function(fast)
24351 var ds = this.grid.store;
24352 var s = this.selections;
24353 s.each(function(r){
24354 this.deselectRow(ds.indexOfId(r.id));
24358 this.selections.clear();
24365 * Selects all rows.
24367 selectAll : function(){
24371 this.selections.clear();
24372 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24373 this.selectRow(i, true);
24378 * Returns True if there is a selection.
24379 * @return {Boolean}
24381 hasSelection : function(){
24382 return this.selections.length > 0;
24386 * Returns True if the specified row is selected.
24387 * @param {Number/Record} record The record or index of the record to check
24388 * @return {Boolean}
24390 isSelected : function(index){
24391 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24392 return (r && this.selections.key(r.id) ? true : false);
24396 * Returns True if the specified record id is selected.
24397 * @param {String} id The id of record to check
24398 * @return {Boolean}
24400 isIdSelected : function(id){
24401 return (this.selections.key(id) ? true : false);
24406 handleMouseDBClick : function(e, t){
24410 handleMouseDown : function(e, t)
24412 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24413 if(this.isLocked() || rowIndex < 0 ){
24416 if(e.shiftKey && this.last !== false){
24417 var last = this.last;
24418 this.selectRange(last, rowIndex, e.ctrlKey);
24419 this.last = last; // reset the last
24423 var isSelected = this.isSelected(rowIndex);
24424 //Roo.log("select row:" + rowIndex);
24426 this.deselectRow(rowIndex);
24428 this.selectRow(rowIndex, true);
24432 if(e.button !== 0 && isSelected){
24433 alert('rowIndex 2: ' + rowIndex);
24434 view.focusRow(rowIndex);
24435 }else if(e.ctrlKey && isSelected){
24436 this.deselectRow(rowIndex);
24437 }else if(!isSelected){
24438 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24439 view.focusRow(rowIndex);
24443 this.fireEvent("afterselectionchange", this);
24446 handleDragableRowClick : function(grid, rowIndex, e)
24448 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24449 this.selectRow(rowIndex, false);
24450 grid.view.focusRow(rowIndex);
24451 this.fireEvent("afterselectionchange", this);
24456 * Selects multiple rows.
24457 * @param {Array} rows Array of the indexes of the row to select
24458 * @param {Boolean} keepExisting (optional) True to keep existing selections
24460 selectRows : function(rows, keepExisting){
24462 this.clearSelections();
24464 for(var i = 0, len = rows.length; i < len; i++){
24465 this.selectRow(rows[i], true);
24470 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24471 * @param {Number} startRow The index of the first row in the range
24472 * @param {Number} endRow The index of the last row in the range
24473 * @param {Boolean} keepExisting (optional) True to retain existing selections
24475 selectRange : function(startRow, endRow, keepExisting){
24480 this.clearSelections();
24482 if(startRow <= endRow){
24483 for(var i = startRow; i <= endRow; i++){
24484 this.selectRow(i, true);
24487 for(var i = startRow; i >= endRow; i--){
24488 this.selectRow(i, true);
24494 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24495 * @param {Number} startRow The index of the first row in the range
24496 * @param {Number} endRow The index of the last row in the range
24498 deselectRange : function(startRow, endRow, preventViewNotify){
24502 for(var i = startRow; i <= endRow; i++){
24503 this.deselectRow(i, preventViewNotify);
24509 * @param {Number} row The index of the row to select
24510 * @param {Boolean} keepExisting (optional) True to keep existing selections
24512 selectRow : function(index, keepExisting, preventViewNotify)
24514 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24517 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24518 if(!keepExisting || this.singleSelect){
24519 this.clearSelections();
24522 var r = this.grid.store.getAt(index);
24523 //console.log('selectRow - record id :' + r.id);
24525 this.selections.add(r);
24526 this.last = this.lastActive = index;
24527 if(!preventViewNotify){
24528 var proxy = new Roo.Element(
24529 this.grid.getRowDom(index)
24531 proxy.addClass('bg-info info');
24533 this.fireEvent("rowselect", this, index, r);
24534 this.fireEvent("selectionchange", this);
24540 * @param {Number} row The index of the row to deselect
24542 deselectRow : function(index, preventViewNotify)
24547 if(this.last == index){
24550 if(this.lastActive == index){
24551 this.lastActive = false;
24554 var r = this.grid.store.getAt(index);
24559 this.selections.remove(r);
24560 //.console.log('deselectRow - record id :' + r.id);
24561 if(!preventViewNotify){
24563 var proxy = new Roo.Element(
24564 this.grid.getRowDom(index)
24566 proxy.removeClass('bg-info info');
24568 this.fireEvent("rowdeselect", this, index);
24569 this.fireEvent("selectionchange", this);
24573 restoreLast : function(){
24575 this.last = this._last;
24580 acceptsNav : function(row, col, cm){
24581 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24585 onEditorKey : function(field, e){
24586 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24591 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24593 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24595 }else if(k == e.ENTER && !e.ctrlKey){
24599 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24601 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24603 }else if(k == e.ESC){
24607 g.startEditing(newCell[0], newCell[1]);
24613 * Ext JS Library 1.1.1
24614 * Copyright(c) 2006-2007, Ext JS, LLC.
24616 * Originally Released Under LGPL - original licence link has changed is not relivant.
24619 * <script type="text/javascript">
24623 * @class Roo.bootstrap.PagingToolbar
24624 * @extends Roo.bootstrap.NavSimplebar
24625 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24627 * Create a new PagingToolbar
24628 * @param {Object} config The config object
24629 * @param {Roo.data.Store} store
24631 Roo.bootstrap.PagingToolbar = function(config)
24633 // old args format still supported... - xtype is prefered..
24634 // created from xtype...
24636 this.ds = config.dataSource;
24638 if (config.store && !this.ds) {
24639 this.store= Roo.factory(config.store, Roo.data);
24640 this.ds = this.store;
24641 this.ds.xmodule = this.xmodule || false;
24644 this.toolbarItems = [];
24645 if (config.items) {
24646 this.toolbarItems = config.items;
24649 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24654 this.bind(this.ds);
24657 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24661 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24663 * @cfg {Roo.data.Store} dataSource
24664 * The underlying data store providing the paged data
24667 * @cfg {String/HTMLElement/Element} container
24668 * container The id or element that will contain the toolbar
24671 * @cfg {Boolean} displayInfo
24672 * True to display the displayMsg (defaults to false)
24675 * @cfg {Number} pageSize
24676 * The number of records to display per page (defaults to 20)
24680 * @cfg {String} displayMsg
24681 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24683 displayMsg : 'Displaying {0} - {1} of {2}',
24685 * @cfg {String} emptyMsg
24686 * The message to display when no records are found (defaults to "No data to display")
24688 emptyMsg : 'No data to display',
24690 * Customizable piece of the default paging text (defaults to "Page")
24693 beforePageText : "Page",
24695 * Customizable piece of the default paging text (defaults to "of %0")
24698 afterPageText : "of {0}",
24700 * Customizable piece of the default paging text (defaults to "First Page")
24703 firstText : "First Page",
24705 * Customizable piece of the default paging text (defaults to "Previous Page")
24708 prevText : "Previous Page",
24710 * Customizable piece of the default paging text (defaults to "Next Page")
24713 nextText : "Next Page",
24715 * Customizable piece of the default paging text (defaults to "Last Page")
24718 lastText : "Last Page",
24720 * Customizable piece of the default paging text (defaults to "Refresh")
24723 refreshText : "Refresh",
24727 onRender : function(ct, position)
24729 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24730 this.navgroup.parentId = this.id;
24731 this.navgroup.onRender(this.el, null);
24732 // add the buttons to the navgroup
24734 if(this.displayInfo){
24735 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24736 this.displayEl = this.el.select('.x-paging-info', true).first();
24737 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24738 // this.displayEl = navel.el.select('span',true).first();
24744 Roo.each(_this.buttons, function(e){ // this might need to use render????
24745 Roo.factory(e).render(_this.el);
24749 Roo.each(_this.toolbarItems, function(e) {
24750 _this.navgroup.addItem(e);
24754 this.first = this.navgroup.addItem({
24755 tooltip: this.firstText,
24757 icon : 'fa fa-step-backward',
24759 preventDefault: true,
24760 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24763 this.prev = this.navgroup.addItem({
24764 tooltip: this.prevText,
24766 icon : 'fa fa-backward',
24768 preventDefault: true,
24769 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24771 //this.addSeparator();
24774 var field = this.navgroup.addItem( {
24776 cls : 'x-paging-position',
24778 html : this.beforePageText +
24779 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24780 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24783 this.field = field.el.select('input', true).first();
24784 this.field.on("keydown", this.onPagingKeydown, this);
24785 this.field.on("focus", function(){this.dom.select();});
24788 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24789 //this.field.setHeight(18);
24790 //this.addSeparator();
24791 this.next = this.navgroup.addItem({
24792 tooltip: this.nextText,
24794 html : ' <i class="fa fa-forward">',
24796 preventDefault: true,
24797 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24799 this.last = this.navgroup.addItem({
24800 tooltip: this.lastText,
24801 icon : 'fa fa-step-forward',
24804 preventDefault: true,
24805 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24807 //this.addSeparator();
24808 this.loading = this.navgroup.addItem({
24809 tooltip: this.refreshText,
24810 icon: 'fa fa-refresh',
24811 preventDefault: true,
24812 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24818 updateInfo : function(){
24819 if(this.displayEl){
24820 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24821 var msg = count == 0 ?
24825 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24827 this.displayEl.update(msg);
24832 onLoad : function(ds, r, o)
24834 this.cursor = o.params.start ? o.params.start : 0;
24836 var d = this.getPageData(),
24841 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24842 this.field.dom.value = ap;
24843 this.first.setDisabled(ap == 1);
24844 this.prev.setDisabled(ap == 1);
24845 this.next.setDisabled(ap == ps);
24846 this.last.setDisabled(ap == ps);
24847 this.loading.enable();
24852 getPageData : function(){
24853 var total = this.ds.getTotalCount();
24856 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24857 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24862 onLoadError : function(){
24863 this.loading.enable();
24867 onPagingKeydown : function(e){
24868 var k = e.getKey();
24869 var d = this.getPageData();
24871 var v = this.field.dom.value, pageNum;
24872 if(!v || isNaN(pageNum = parseInt(v, 10))){
24873 this.field.dom.value = d.activePage;
24876 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24877 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24880 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))
24882 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24883 this.field.dom.value = pageNum;
24884 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24887 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24889 var v = this.field.dom.value, pageNum;
24890 var increment = (e.shiftKey) ? 10 : 1;
24891 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24894 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24895 this.field.dom.value = d.activePage;
24898 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24900 this.field.dom.value = parseInt(v, 10) + increment;
24901 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24902 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24909 beforeLoad : function(){
24911 this.loading.disable();
24916 onClick : function(which){
24925 ds.load({params:{start: 0, limit: this.pageSize}});
24928 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24931 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24934 var total = ds.getTotalCount();
24935 var extra = total % this.pageSize;
24936 var lastStart = extra ? (total - extra) : total-this.pageSize;
24937 ds.load({params:{start: lastStart, limit: this.pageSize}});
24940 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24946 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24947 * @param {Roo.data.Store} store The data store to unbind
24949 unbind : function(ds){
24950 ds.un("beforeload", this.beforeLoad, this);
24951 ds.un("load", this.onLoad, this);
24952 ds.un("loadexception", this.onLoadError, this);
24953 ds.un("remove", this.updateInfo, this);
24954 ds.un("add", this.updateInfo, this);
24955 this.ds = undefined;
24959 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24960 * @param {Roo.data.Store} store The data store to bind
24962 bind : function(ds){
24963 ds.on("beforeload", this.beforeLoad, this);
24964 ds.on("load", this.onLoad, this);
24965 ds.on("loadexception", this.onLoadError, this);
24966 ds.on("remove", this.updateInfo, this);
24967 ds.on("add", this.updateInfo, this);
24978 * @class Roo.bootstrap.MessageBar
24979 * @extends Roo.bootstrap.Component
24980 * Bootstrap MessageBar class
24981 * @cfg {String} html contents of the MessageBar
24982 * @cfg {String} weight (info | success | warning | danger) default info
24983 * @cfg {String} beforeClass insert the bar before the given class
24984 * @cfg {Boolean} closable (true | false) default false
24985 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24988 * Create a new Element
24989 * @param {Object} config The config object
24992 Roo.bootstrap.MessageBar = function(config){
24993 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24996 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25002 beforeClass: 'bootstrap-sticky-wrap',
25004 getAutoCreate : function(){
25008 cls: 'alert alert-dismissable alert-' + this.weight,
25013 html: this.html || ''
25019 cfg.cls += ' alert-messages-fixed';
25033 onRender : function(ct, position)
25035 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25038 var cfg = Roo.apply({}, this.getAutoCreate());
25042 cfg.cls += ' ' + this.cls;
25045 cfg.style = this.style;
25047 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25049 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25052 this.el.select('>button.close').on('click', this.hide, this);
25058 if (!this.rendered) {
25064 this.fireEvent('show', this);
25070 if (!this.rendered) {
25076 this.fireEvent('hide', this);
25079 update : function()
25081 // var e = this.el.dom.firstChild;
25083 // if(this.closable){
25084 // e = e.nextSibling;
25087 // e.data = this.html || '';
25089 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25105 * @class Roo.bootstrap.Graph
25106 * @extends Roo.bootstrap.Component
25107 * Bootstrap Graph class
25111 @cfg {String} graphtype bar | vbar | pie
25112 @cfg {number} g_x coodinator | centre x (pie)
25113 @cfg {number} g_y coodinator | centre y (pie)
25114 @cfg {number} g_r radius (pie)
25115 @cfg {number} g_height height of the chart (respected by all elements in the set)
25116 @cfg {number} g_width width of the chart (respected by all elements in the set)
25117 @cfg {Object} title The title of the chart
25120 -opts (object) options for the chart
25122 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25123 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25125 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.
25126 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25128 o stretch (boolean)
25130 -opts (object) options for the pie
25133 o startAngle (number)
25134 o endAngle (number)
25138 * Create a new Input
25139 * @param {Object} config The config object
25142 Roo.bootstrap.Graph = function(config){
25143 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25149 * The img click event for the img.
25150 * @param {Roo.EventObject} e
25156 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25167 //g_colors: this.colors,
25174 getAutoCreate : function(){
25185 onRender : function(ct,position){
25188 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25190 if (typeof(Raphael) == 'undefined') {
25191 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25195 this.raphael = Raphael(this.el.dom);
25197 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25198 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25199 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25200 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25202 r.text(160, 10, "Single Series Chart").attr(txtattr);
25203 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25204 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25205 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25207 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25208 r.barchart(330, 10, 300, 220, data1);
25209 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25210 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25213 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25214 // r.barchart(30, 30, 560, 250, xdata, {
25215 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25216 // axis : "0 0 1 1",
25217 // axisxlabels : xdata
25218 // //yvalues : cols,
25221 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25223 // this.load(null,xdata,{
25224 // axis : "0 0 1 1",
25225 // axisxlabels : xdata
25230 load : function(graphtype,xdata,opts)
25232 this.raphael.clear();
25234 graphtype = this.graphtype;
25239 var r = this.raphael,
25240 fin = function () {
25241 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25243 fout = function () {
25244 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25246 pfin = function() {
25247 this.sector.stop();
25248 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25251 this.label[0].stop();
25252 this.label[0].attr({ r: 7.5 });
25253 this.label[1].attr({ "font-weight": 800 });
25256 pfout = function() {
25257 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25260 this.label[0].animate({ r: 5 }, 500, "bounce");
25261 this.label[1].attr({ "font-weight": 400 });
25267 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25270 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25273 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25274 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25276 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25283 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25288 setTitle: function(o)
25293 initEvents: function() {
25296 this.el.on('click', this.onClick, this);
25300 onClick : function(e)
25302 Roo.log('img onclick');
25303 this.fireEvent('click', this, e);
25315 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25318 * @class Roo.bootstrap.dash.NumberBox
25319 * @extends Roo.bootstrap.Component
25320 * Bootstrap NumberBox class
25321 * @cfg {String} headline Box headline
25322 * @cfg {String} content Box content
25323 * @cfg {String} icon Box icon
25324 * @cfg {String} footer Footer text
25325 * @cfg {String} fhref Footer href
25328 * Create a new NumberBox
25329 * @param {Object} config The config object
25333 Roo.bootstrap.dash.NumberBox = function(config){
25334 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25338 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25347 getAutoCreate : function(){
25351 cls : 'small-box ',
25359 cls : 'roo-headline',
25360 html : this.headline
25364 cls : 'roo-content',
25365 html : this.content
25379 cls : 'ion ' + this.icon
25388 cls : 'small-box-footer',
25389 href : this.fhref || '#',
25393 cfg.cn.push(footer);
25400 onRender : function(ct,position){
25401 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25408 setHeadline: function (value)
25410 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25413 setFooter: function (value, href)
25415 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25418 this.el.select('a.small-box-footer',true).first().attr('href', href);
25423 setContent: function (value)
25425 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25428 initEvents: function()
25442 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25445 * @class Roo.bootstrap.dash.TabBox
25446 * @extends Roo.bootstrap.Component
25447 * Bootstrap TabBox class
25448 * @cfg {String} title Title of the TabBox
25449 * @cfg {String} icon Icon of the TabBox
25450 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25451 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25454 * Create a new TabBox
25455 * @param {Object} config The config object
25459 Roo.bootstrap.dash.TabBox = function(config){
25460 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25465 * When a pane is added
25466 * @param {Roo.bootstrap.dash.TabPane} pane
25470 * @event activatepane
25471 * When a pane is activated
25472 * @param {Roo.bootstrap.dash.TabPane} pane
25474 "activatepane" : true
25482 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25487 tabScrollable : false,
25489 getChildContainer : function()
25491 return this.el.select('.tab-content', true).first();
25494 getAutoCreate : function(){
25498 cls: 'pull-left header',
25506 cls: 'fa ' + this.icon
25512 cls: 'nav nav-tabs pull-right',
25518 if(this.tabScrollable){
25525 cls: 'nav nav-tabs pull-right',
25536 cls: 'nav-tabs-custom',
25541 cls: 'tab-content no-padding',
25549 initEvents : function()
25551 //Roo.log('add add pane handler');
25552 this.on('addpane', this.onAddPane, this);
25555 * Updates the box title
25556 * @param {String} html to set the title to.
25558 setTitle : function(value)
25560 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25562 onAddPane : function(pane)
25564 this.panes.push(pane);
25565 //Roo.log('addpane');
25567 // tabs are rendere left to right..
25568 if(!this.showtabs){
25572 var ctr = this.el.select('.nav-tabs', true).first();
25575 var existing = ctr.select('.nav-tab',true);
25576 var qty = existing.getCount();;
25579 var tab = ctr.createChild({
25581 cls : 'nav-tab' + (qty ? '' : ' active'),
25589 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25592 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25594 pane.el.addClass('active');
25599 onTabClick : function(ev,un,ob,pane)
25601 //Roo.log('tab - prev default');
25602 ev.preventDefault();
25605 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25606 pane.tab.addClass('active');
25607 //Roo.log(pane.title);
25608 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25609 // technically we should have a deactivate event.. but maybe add later.
25610 // and it should not de-activate the selected tab...
25611 this.fireEvent('activatepane', pane);
25612 pane.el.addClass('active');
25613 pane.fireEvent('activate');
25618 getActivePane : function()
25621 Roo.each(this.panes, function(p) {
25622 if(p.el.hasClass('active')){
25643 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25645 * @class Roo.bootstrap.TabPane
25646 * @extends Roo.bootstrap.Component
25647 * Bootstrap TabPane class
25648 * @cfg {Boolean} active (false | true) Default false
25649 * @cfg {String} title title of panel
25653 * Create a new TabPane
25654 * @param {Object} config The config object
25657 Roo.bootstrap.dash.TabPane = function(config){
25658 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25664 * When a pane is activated
25665 * @param {Roo.bootstrap.dash.TabPane} pane
25672 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25677 // the tabBox that this is attached to.
25680 getAutoCreate : function()
25688 cfg.cls += ' active';
25693 initEvents : function()
25695 //Roo.log('trigger add pane handler');
25696 this.parent().fireEvent('addpane', this)
25700 * Updates the tab title
25701 * @param {String} html to set the title to.
25703 setTitle: function(str)
25709 this.tab.select('a', true).first().dom.innerHTML = str;
25726 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25729 * @class Roo.bootstrap.menu.Menu
25730 * @extends Roo.bootstrap.Component
25731 * Bootstrap Menu class - container for Menu
25732 * @cfg {String} html Text of the menu
25733 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25734 * @cfg {String} icon Font awesome icon
25735 * @cfg {String} pos Menu align to (top | bottom) default bottom
25739 * Create a new Menu
25740 * @param {Object} config The config object
25744 Roo.bootstrap.menu.Menu = function(config){
25745 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25749 * @event beforeshow
25750 * Fires before this menu is displayed
25751 * @param {Roo.bootstrap.menu.Menu} this
25755 * @event beforehide
25756 * Fires before this menu is hidden
25757 * @param {Roo.bootstrap.menu.Menu} this
25762 * Fires after this menu is displayed
25763 * @param {Roo.bootstrap.menu.Menu} this
25768 * Fires after this menu is hidden
25769 * @param {Roo.bootstrap.menu.Menu} this
25774 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25775 * @param {Roo.bootstrap.menu.Menu} this
25776 * @param {Roo.EventObject} e
25783 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25787 weight : 'default',
25792 getChildContainer : function() {
25793 if(this.isSubMenu){
25797 return this.el.select('ul.dropdown-menu', true).first();
25800 getAutoCreate : function()
25805 cls : 'roo-menu-text',
25813 cls : 'fa ' + this.icon
25824 cls : 'dropdown-button btn btn-' + this.weight,
25829 cls : 'dropdown-toggle btn btn-' + this.weight,
25839 cls : 'dropdown-menu'
25845 if(this.pos == 'top'){
25846 cfg.cls += ' dropup';
25849 if(this.isSubMenu){
25852 cls : 'dropdown-menu'
25859 onRender : function(ct, position)
25861 this.isSubMenu = ct.hasClass('dropdown-submenu');
25863 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25866 initEvents : function()
25868 if(this.isSubMenu){
25872 this.hidden = true;
25874 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25875 this.triggerEl.on('click', this.onTriggerPress, this);
25877 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25878 this.buttonEl.on('click', this.onClick, this);
25884 if(this.isSubMenu){
25888 return this.el.select('ul.dropdown-menu', true).first();
25891 onClick : function(e)
25893 this.fireEvent("click", this, e);
25896 onTriggerPress : function(e)
25898 if (this.isVisible()) {
25905 isVisible : function(){
25906 return !this.hidden;
25911 this.fireEvent("beforeshow", this);
25913 this.hidden = false;
25914 this.el.addClass('open');
25916 Roo.get(document).on("mouseup", this.onMouseUp, this);
25918 this.fireEvent("show", this);
25925 this.fireEvent("beforehide", this);
25927 this.hidden = true;
25928 this.el.removeClass('open');
25930 Roo.get(document).un("mouseup", this.onMouseUp);
25932 this.fireEvent("hide", this);
25935 onMouseUp : function()
25949 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25952 * @class Roo.bootstrap.menu.Item
25953 * @extends Roo.bootstrap.Component
25954 * Bootstrap MenuItem class
25955 * @cfg {Boolean} submenu (true | false) default false
25956 * @cfg {String} html text of the item
25957 * @cfg {String} href the link
25958 * @cfg {Boolean} disable (true | false) default false
25959 * @cfg {Boolean} preventDefault (true | false) default true
25960 * @cfg {String} icon Font awesome icon
25961 * @cfg {String} pos Submenu align to (left | right) default right
25965 * Create a new Item
25966 * @param {Object} config The config object
25970 Roo.bootstrap.menu.Item = function(config){
25971 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25975 * Fires when the mouse is hovering over this menu
25976 * @param {Roo.bootstrap.menu.Item} this
25977 * @param {Roo.EventObject} e
25982 * Fires when the mouse exits this menu
25983 * @param {Roo.bootstrap.menu.Item} this
25984 * @param {Roo.EventObject} e
25990 * The raw click event for the entire grid.
25991 * @param {Roo.EventObject} e
25997 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26002 preventDefault: true,
26007 getAutoCreate : function()
26012 cls : 'roo-menu-item-text',
26020 cls : 'fa ' + this.icon
26029 href : this.href || '#',
26036 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26040 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26042 if(this.pos == 'left'){
26043 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26050 initEvents : function()
26052 this.el.on('mouseover', this.onMouseOver, this);
26053 this.el.on('mouseout', this.onMouseOut, this);
26055 this.el.select('a', true).first().on('click', this.onClick, this);
26059 onClick : function(e)
26061 if(this.preventDefault){
26062 e.preventDefault();
26065 this.fireEvent("click", this, e);
26068 onMouseOver : function(e)
26070 if(this.submenu && this.pos == 'left'){
26071 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26074 this.fireEvent("mouseover", this, e);
26077 onMouseOut : function(e)
26079 this.fireEvent("mouseout", this, e);
26091 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26094 * @class Roo.bootstrap.menu.Separator
26095 * @extends Roo.bootstrap.Component
26096 * Bootstrap Separator class
26099 * Create a new Separator
26100 * @param {Object} config The config object
26104 Roo.bootstrap.menu.Separator = function(config){
26105 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26108 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26110 getAutoCreate : function(){
26131 * @class Roo.bootstrap.Tooltip
26132 * Bootstrap Tooltip class
26133 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26134 * to determine which dom element triggers the tooltip.
26136 * It needs to add support for additional attributes like tooltip-position
26139 * Create a new Toolti
26140 * @param {Object} config The config object
26143 Roo.bootstrap.Tooltip = function(config){
26144 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26146 this.alignment = Roo.bootstrap.Tooltip.alignment;
26148 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26149 this.alignment = config.alignment;
26154 Roo.apply(Roo.bootstrap.Tooltip, {
26156 * @function init initialize tooltip monitoring.
26160 currentTip : false,
26161 currentRegion : false,
26167 Roo.get(document).on('mouseover', this.enter ,this);
26168 Roo.get(document).on('mouseout', this.leave, this);
26171 this.currentTip = new Roo.bootstrap.Tooltip();
26174 enter : function(ev)
26176 var dom = ev.getTarget();
26178 //Roo.log(['enter',dom]);
26179 var el = Roo.fly(dom);
26180 if (this.currentEl) {
26182 //Roo.log(this.currentEl);
26183 //Roo.log(this.currentEl.contains(dom));
26184 if (this.currentEl == el) {
26187 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26193 if (this.currentTip.el) {
26194 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26198 if(!el || el.dom == document){
26204 // you can not look for children, as if el is the body.. then everythign is the child..
26205 if (!el.attr('tooltip')) { //
26206 if (!el.select("[tooltip]").elements.length) {
26209 // is the mouse over this child...?
26210 bindEl = el.select("[tooltip]").first();
26211 var xy = ev.getXY();
26212 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26213 //Roo.log("not in region.");
26216 //Roo.log("child element over..");
26219 this.currentEl = bindEl;
26220 this.currentTip.bind(bindEl);
26221 this.currentRegion = Roo.lib.Region.getRegion(dom);
26222 this.currentTip.enter();
26225 leave : function(ev)
26227 var dom = ev.getTarget();
26228 //Roo.log(['leave',dom]);
26229 if (!this.currentEl) {
26234 if (dom != this.currentEl.dom) {
26237 var xy = ev.getXY();
26238 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26241 // only activate leave if mouse cursor is outside... bounding box..
26246 if (this.currentTip) {
26247 this.currentTip.leave();
26249 //Roo.log('clear currentEl');
26250 this.currentEl = false;
26255 'left' : ['r-l', [-2,0], 'right'],
26256 'right' : ['l-r', [2,0], 'left'],
26257 'bottom' : ['t-b', [0,2], 'top'],
26258 'top' : [ 'b-t', [0,-2], 'bottom']
26264 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26269 delay : null, // can be { show : 300 , hide: 500}
26273 hoverState : null, //???
26275 placement : 'bottom',
26279 getAutoCreate : function(){
26286 cls : 'tooltip-arrow'
26289 cls : 'tooltip-inner'
26296 bind : function(el)
26302 enter : function () {
26304 if (this.timeout != null) {
26305 clearTimeout(this.timeout);
26308 this.hoverState = 'in';
26309 //Roo.log("enter - show");
26310 if (!this.delay || !this.delay.show) {
26315 this.timeout = setTimeout(function () {
26316 if (_t.hoverState == 'in') {
26319 }, this.delay.show);
26323 clearTimeout(this.timeout);
26325 this.hoverState = 'out';
26326 if (!this.delay || !this.delay.hide) {
26332 this.timeout = setTimeout(function () {
26333 //Roo.log("leave - timeout");
26335 if (_t.hoverState == 'out') {
26337 Roo.bootstrap.Tooltip.currentEl = false;
26342 show : function (msg)
26345 this.render(document.body);
26348 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26350 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26352 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26354 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26356 var placement = typeof this.placement == 'function' ?
26357 this.placement.call(this, this.el, on_el) :
26360 var autoToken = /\s?auto?\s?/i;
26361 var autoPlace = autoToken.test(placement);
26363 placement = placement.replace(autoToken, '') || 'top';
26367 //this.el.setXY([0,0]);
26369 //this.el.dom.style.display='block';
26371 //this.el.appendTo(on_el);
26373 var p = this.getPosition();
26374 var box = this.el.getBox();
26380 var align = this.alignment[placement];
26382 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26384 if(placement == 'top' || placement == 'bottom'){
26386 placement = 'right';
26389 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26390 placement = 'left';
26393 var scroll = Roo.select('body', true).first().getScroll();
26395 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26399 align = this.alignment[placement];
26402 this.el.alignTo(this.bindEl, align[0],align[1]);
26403 //var arrow = this.el.select('.arrow',true).first();
26404 //arrow.set(align[2],
26406 this.el.addClass(placement);
26408 this.el.addClass('in fade');
26410 this.hoverState = null;
26412 if (this.el.hasClass('fade')) {
26423 //this.el.setXY([0,0]);
26424 this.el.removeClass('in');
26440 * @class Roo.bootstrap.LocationPicker
26441 * @extends Roo.bootstrap.Component
26442 * Bootstrap LocationPicker class
26443 * @cfg {Number} latitude Position when init default 0
26444 * @cfg {Number} longitude Position when init default 0
26445 * @cfg {Number} zoom default 15
26446 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26447 * @cfg {Boolean} mapTypeControl default false
26448 * @cfg {Boolean} disableDoubleClickZoom default false
26449 * @cfg {Boolean} scrollwheel default true
26450 * @cfg {Boolean} streetViewControl default false
26451 * @cfg {Number} radius default 0
26452 * @cfg {String} locationName
26453 * @cfg {Boolean} draggable default true
26454 * @cfg {Boolean} enableAutocomplete default false
26455 * @cfg {Boolean} enableReverseGeocode default true
26456 * @cfg {String} markerTitle
26459 * Create a new LocationPicker
26460 * @param {Object} config The config object
26464 Roo.bootstrap.LocationPicker = function(config){
26466 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26471 * Fires when the picker initialized.
26472 * @param {Roo.bootstrap.LocationPicker} this
26473 * @param {Google Location} location
26477 * @event positionchanged
26478 * Fires when the picker position changed.
26479 * @param {Roo.bootstrap.LocationPicker} this
26480 * @param {Google Location} location
26482 positionchanged : true,
26485 * Fires when the map resize.
26486 * @param {Roo.bootstrap.LocationPicker} this
26491 * Fires when the map show.
26492 * @param {Roo.bootstrap.LocationPicker} this
26497 * Fires when the map hide.
26498 * @param {Roo.bootstrap.LocationPicker} this
26503 * Fires when click the map.
26504 * @param {Roo.bootstrap.LocationPicker} this
26505 * @param {Map event} e
26509 * @event mapRightClick
26510 * Fires when right click the map.
26511 * @param {Roo.bootstrap.LocationPicker} this
26512 * @param {Map event} e
26514 mapRightClick : true,
26516 * @event markerClick
26517 * Fires when click the marker.
26518 * @param {Roo.bootstrap.LocationPicker} this
26519 * @param {Map event} e
26521 markerClick : true,
26523 * @event markerRightClick
26524 * Fires when right click the marker.
26525 * @param {Roo.bootstrap.LocationPicker} this
26526 * @param {Map event} e
26528 markerRightClick : true,
26530 * @event OverlayViewDraw
26531 * Fires when OverlayView Draw
26532 * @param {Roo.bootstrap.LocationPicker} this
26534 OverlayViewDraw : true,
26536 * @event OverlayViewOnAdd
26537 * Fires when OverlayView Draw
26538 * @param {Roo.bootstrap.LocationPicker} this
26540 OverlayViewOnAdd : true,
26542 * @event OverlayViewOnRemove
26543 * Fires when OverlayView Draw
26544 * @param {Roo.bootstrap.LocationPicker} this
26546 OverlayViewOnRemove : true,
26548 * @event OverlayViewShow
26549 * Fires when OverlayView Draw
26550 * @param {Roo.bootstrap.LocationPicker} this
26551 * @param {Pixel} cpx
26553 OverlayViewShow : true,
26555 * @event OverlayViewHide
26556 * Fires when OverlayView Draw
26557 * @param {Roo.bootstrap.LocationPicker} this
26559 OverlayViewHide : true,
26561 * @event loadexception
26562 * Fires when load google lib failed.
26563 * @param {Roo.bootstrap.LocationPicker} this
26565 loadexception : true
26570 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26572 gMapContext: false,
26578 mapTypeControl: false,
26579 disableDoubleClickZoom: false,
26581 streetViewControl: false,
26585 enableAutocomplete: false,
26586 enableReverseGeocode: true,
26589 getAutoCreate: function()
26594 cls: 'roo-location-picker'
26600 initEvents: function(ct, position)
26602 if(!this.el.getWidth() || this.isApplied()){
26606 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26611 initial: function()
26613 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26614 this.fireEvent('loadexception', this);
26618 if(!this.mapTypeId){
26619 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26622 this.gMapContext = this.GMapContext();
26624 this.initOverlayView();
26626 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26630 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26631 _this.setPosition(_this.gMapContext.marker.position);
26634 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26635 _this.fireEvent('mapClick', this, event);
26639 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26640 _this.fireEvent('mapRightClick', this, event);
26644 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26645 _this.fireEvent('markerClick', this, event);
26649 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26650 _this.fireEvent('markerRightClick', this, event);
26654 this.setPosition(this.gMapContext.location);
26656 this.fireEvent('initial', this, this.gMapContext.location);
26659 initOverlayView: function()
26663 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26667 _this.fireEvent('OverlayViewDraw', _this);
26672 _this.fireEvent('OverlayViewOnAdd', _this);
26675 onRemove: function()
26677 _this.fireEvent('OverlayViewOnRemove', _this);
26680 show: function(cpx)
26682 _this.fireEvent('OverlayViewShow', _this, cpx);
26687 _this.fireEvent('OverlayViewHide', _this);
26693 fromLatLngToContainerPixel: function(event)
26695 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26698 isApplied: function()
26700 return this.getGmapContext() == false ? false : true;
26703 getGmapContext: function()
26705 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26708 GMapContext: function()
26710 var position = new google.maps.LatLng(this.latitude, this.longitude);
26712 var _map = new google.maps.Map(this.el.dom, {
26715 mapTypeId: this.mapTypeId,
26716 mapTypeControl: this.mapTypeControl,
26717 disableDoubleClickZoom: this.disableDoubleClickZoom,
26718 scrollwheel: this.scrollwheel,
26719 streetViewControl: this.streetViewControl,
26720 locationName: this.locationName,
26721 draggable: this.draggable,
26722 enableAutocomplete: this.enableAutocomplete,
26723 enableReverseGeocode: this.enableReverseGeocode
26726 var _marker = new google.maps.Marker({
26727 position: position,
26729 title: this.markerTitle,
26730 draggable: this.draggable
26737 location: position,
26738 radius: this.radius,
26739 locationName: this.locationName,
26740 addressComponents: {
26741 formatted_address: null,
26742 addressLine1: null,
26743 addressLine2: null,
26745 streetNumber: null,
26749 stateOrProvince: null
26752 domContainer: this.el.dom,
26753 geodecoder: new google.maps.Geocoder()
26757 drawCircle: function(center, radius, options)
26759 if (this.gMapContext.circle != null) {
26760 this.gMapContext.circle.setMap(null);
26764 options = Roo.apply({}, options, {
26765 strokeColor: "#0000FF",
26766 strokeOpacity: .35,
26768 fillColor: "#0000FF",
26772 options.map = this.gMapContext.map;
26773 options.radius = radius;
26774 options.center = center;
26775 this.gMapContext.circle = new google.maps.Circle(options);
26776 return this.gMapContext.circle;
26782 setPosition: function(location)
26784 this.gMapContext.location = location;
26785 this.gMapContext.marker.setPosition(location);
26786 this.gMapContext.map.panTo(location);
26787 this.drawCircle(location, this.gMapContext.radius, {});
26791 if (this.gMapContext.settings.enableReverseGeocode) {
26792 this.gMapContext.geodecoder.geocode({
26793 latLng: this.gMapContext.location
26794 }, function(results, status) {
26796 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26797 _this.gMapContext.locationName = results[0].formatted_address;
26798 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26800 _this.fireEvent('positionchanged', this, location);
26807 this.fireEvent('positionchanged', this, location);
26812 google.maps.event.trigger(this.gMapContext.map, "resize");
26814 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26816 this.fireEvent('resize', this);
26819 setPositionByLatLng: function(latitude, longitude)
26821 this.setPosition(new google.maps.LatLng(latitude, longitude));
26824 getCurrentPosition: function()
26827 latitude: this.gMapContext.location.lat(),
26828 longitude: this.gMapContext.location.lng()
26832 getAddressName: function()
26834 return this.gMapContext.locationName;
26837 getAddressComponents: function()
26839 return this.gMapContext.addressComponents;
26842 address_component_from_google_geocode: function(address_components)
26846 for (var i = 0; i < address_components.length; i++) {
26847 var component = address_components[i];
26848 if (component.types.indexOf("postal_code") >= 0) {
26849 result.postalCode = component.short_name;
26850 } else if (component.types.indexOf("street_number") >= 0) {
26851 result.streetNumber = component.short_name;
26852 } else if (component.types.indexOf("route") >= 0) {
26853 result.streetName = component.short_name;
26854 } else if (component.types.indexOf("neighborhood") >= 0) {
26855 result.city = component.short_name;
26856 } else if (component.types.indexOf("locality") >= 0) {
26857 result.city = component.short_name;
26858 } else if (component.types.indexOf("sublocality") >= 0) {
26859 result.district = component.short_name;
26860 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26861 result.stateOrProvince = component.short_name;
26862 } else if (component.types.indexOf("country") >= 0) {
26863 result.country = component.short_name;
26867 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26868 result.addressLine2 = "";
26872 setZoomLevel: function(zoom)
26874 this.gMapContext.map.setZoom(zoom);
26887 this.fireEvent('show', this);
26898 this.fireEvent('hide', this);
26903 Roo.apply(Roo.bootstrap.LocationPicker, {
26905 OverlayView : function(map, options)
26907 options = options || {};
26921 * @class Roo.bootstrap.Alert
26922 * @extends Roo.bootstrap.Component
26923 * Bootstrap Alert class
26924 * @cfg {String} title The title of alert
26925 * @cfg {String} html The content of alert
26926 * @cfg {String} weight ( success | info | warning | danger )
26927 * @cfg {String} faicon font-awesomeicon
26930 * Create a new alert
26931 * @param {Object} config The config object
26935 Roo.bootstrap.Alert = function(config){
26936 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26940 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26947 getAutoCreate : function()
26956 cls : 'roo-alert-icon'
26961 cls : 'roo-alert-title',
26966 cls : 'roo-alert-text',
26973 cfg.cn[0].cls += ' fa ' + this.faicon;
26977 cfg.cls += ' alert-' + this.weight;
26983 initEvents: function()
26985 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26988 setTitle : function(str)
26990 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26993 setText : function(str)
26995 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26998 setWeight : function(weight)
27001 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27004 this.weight = weight;
27006 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27009 setIcon : function(icon)
27012 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27015 this.faicon = icon;
27017 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27038 * @class Roo.bootstrap.UploadCropbox
27039 * @extends Roo.bootstrap.Component
27040 * Bootstrap UploadCropbox class
27041 * @cfg {String} emptyText show when image has been loaded
27042 * @cfg {String} rotateNotify show when image too small to rotate
27043 * @cfg {Number} errorTimeout default 3000
27044 * @cfg {Number} minWidth default 300
27045 * @cfg {Number} minHeight default 300
27046 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27047 * @cfg {Boolean} isDocument (true|false) default false
27048 * @cfg {String} url action url
27049 * @cfg {String} paramName default 'imageUpload'
27050 * @cfg {String} method default POST
27051 * @cfg {Boolean} loadMask (true|false) default true
27052 * @cfg {Boolean} loadingText default 'Loading...'
27055 * Create a new UploadCropbox
27056 * @param {Object} config The config object
27059 Roo.bootstrap.UploadCropbox = function(config){
27060 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27064 * @event beforeselectfile
27065 * Fire before select file
27066 * @param {Roo.bootstrap.UploadCropbox} this
27068 "beforeselectfile" : true,
27071 * Fire after initEvent
27072 * @param {Roo.bootstrap.UploadCropbox} this
27077 * Fire after initEvent
27078 * @param {Roo.bootstrap.UploadCropbox} this
27079 * @param {String} data
27084 * Fire when preparing the file data
27085 * @param {Roo.bootstrap.UploadCropbox} this
27086 * @param {Object} file
27091 * Fire when get exception
27092 * @param {Roo.bootstrap.UploadCropbox} this
27093 * @param {XMLHttpRequest} xhr
27095 "exception" : true,
27097 * @event beforeloadcanvas
27098 * Fire before load the canvas
27099 * @param {Roo.bootstrap.UploadCropbox} this
27100 * @param {String} src
27102 "beforeloadcanvas" : true,
27105 * Fire when trash image
27106 * @param {Roo.bootstrap.UploadCropbox} this
27111 * Fire when download the image
27112 * @param {Roo.bootstrap.UploadCropbox} this
27116 * @event footerbuttonclick
27117 * Fire when footerbuttonclick
27118 * @param {Roo.bootstrap.UploadCropbox} this
27119 * @param {String} type
27121 "footerbuttonclick" : true,
27125 * @param {Roo.bootstrap.UploadCropbox} this
27130 * Fire when rotate the image
27131 * @param {Roo.bootstrap.UploadCropbox} this
27132 * @param {String} pos
27137 * Fire when inspect the file
27138 * @param {Roo.bootstrap.UploadCropbox} this
27139 * @param {Object} file
27144 * Fire when xhr upload the file
27145 * @param {Roo.bootstrap.UploadCropbox} this
27146 * @param {Object} data
27151 * Fire when arrange the file data
27152 * @param {Roo.bootstrap.UploadCropbox} this
27153 * @param {Object} formData
27158 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27161 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27163 emptyText : 'Click to upload image',
27164 rotateNotify : 'Image is too small to rotate',
27165 errorTimeout : 3000,
27179 cropType : 'image/jpeg',
27181 canvasLoaded : false,
27182 isDocument : false,
27184 paramName : 'imageUpload',
27186 loadingText : 'Loading...',
27189 getAutoCreate : function()
27193 cls : 'roo-upload-cropbox',
27197 cls : 'roo-upload-cropbox-selector',
27202 cls : 'roo-upload-cropbox-body',
27203 style : 'cursor:pointer',
27207 cls : 'roo-upload-cropbox-preview'
27211 cls : 'roo-upload-cropbox-thumb'
27215 cls : 'roo-upload-cropbox-empty-notify',
27216 html : this.emptyText
27220 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27221 html : this.rotateNotify
27227 cls : 'roo-upload-cropbox-footer',
27230 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27240 onRender : function(ct, position)
27242 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27244 if (this.buttons.length) {
27246 Roo.each(this.buttons, function(bb) {
27248 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27250 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27256 this.maskEl = this.el;
27260 initEvents : function()
27262 this.urlAPI = (window.createObjectURL && window) ||
27263 (window.URL && URL.revokeObjectURL && URL) ||
27264 (window.webkitURL && webkitURL);
27266 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27267 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27269 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27270 this.selectorEl.hide();
27272 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27273 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27275 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27276 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27277 this.thumbEl.hide();
27279 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27280 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27282 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27283 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27284 this.errorEl.hide();
27286 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27287 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27288 this.footerEl.hide();
27290 this.setThumbBoxSize();
27296 this.fireEvent('initial', this);
27303 window.addEventListener("resize", function() { _this.resize(); } );
27305 this.bodyEl.on('click', this.beforeSelectFile, this);
27308 this.bodyEl.on('touchstart', this.onTouchStart, this);
27309 this.bodyEl.on('touchmove', this.onTouchMove, this);
27310 this.bodyEl.on('touchend', this.onTouchEnd, this);
27314 this.bodyEl.on('mousedown', this.onMouseDown, this);
27315 this.bodyEl.on('mousemove', this.onMouseMove, this);
27316 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27317 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27318 Roo.get(document).on('mouseup', this.onMouseUp, this);
27321 this.selectorEl.on('change', this.onFileSelected, this);
27327 this.baseScale = 1;
27329 this.baseRotate = 1;
27330 this.dragable = false;
27331 this.pinching = false;
27334 this.cropData = false;
27335 this.notifyEl.dom.innerHTML = this.emptyText;
27337 this.selectorEl.dom.value = '';
27341 resize : function()
27343 if(this.fireEvent('resize', this) != false){
27344 this.setThumbBoxPosition();
27345 this.setCanvasPosition();
27349 onFooterButtonClick : function(e, el, o, type)
27352 case 'rotate-left' :
27353 this.onRotateLeft(e);
27355 case 'rotate-right' :
27356 this.onRotateRight(e);
27359 this.beforeSelectFile(e);
27374 this.fireEvent('footerbuttonclick', this, type);
27377 beforeSelectFile : function(e)
27379 e.preventDefault();
27381 if(this.fireEvent('beforeselectfile', this) != false){
27382 this.selectorEl.dom.click();
27386 onFileSelected : function(e)
27388 e.preventDefault();
27390 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27394 var file = this.selectorEl.dom.files[0];
27396 if(this.fireEvent('inspect', this, file) != false){
27397 this.prepare(file);
27402 trash : function(e)
27404 this.fireEvent('trash', this);
27407 download : function(e)
27409 this.fireEvent('download', this);
27412 loadCanvas : function(src)
27414 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27418 this.imageEl = document.createElement('img');
27422 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27424 this.imageEl.src = src;
27428 onLoadCanvas : function()
27430 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27431 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27433 this.bodyEl.un('click', this.beforeSelectFile, this);
27435 this.notifyEl.hide();
27436 this.thumbEl.show();
27437 this.footerEl.show();
27439 this.baseRotateLevel();
27441 if(this.isDocument){
27442 this.setThumbBoxSize();
27445 this.setThumbBoxPosition();
27447 this.baseScaleLevel();
27453 this.canvasLoaded = true;
27456 this.maskEl.unmask();
27461 setCanvasPosition : function()
27463 if(!this.canvasEl){
27467 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27468 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27470 this.previewEl.setLeft(pw);
27471 this.previewEl.setTop(ph);
27475 onMouseDown : function(e)
27479 this.dragable = true;
27480 this.pinching = false;
27482 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27483 this.dragable = false;
27487 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27488 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27492 onMouseMove : function(e)
27496 if(!this.canvasLoaded){
27500 if (!this.dragable){
27504 var minX = Math.ceil(this.thumbEl.getLeft(true));
27505 var minY = Math.ceil(this.thumbEl.getTop(true));
27507 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27508 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27510 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27511 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27513 x = x - this.mouseX;
27514 y = y - this.mouseY;
27516 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27517 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27519 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27520 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27522 this.previewEl.setLeft(bgX);
27523 this.previewEl.setTop(bgY);
27525 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27526 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27529 onMouseUp : function(e)
27533 this.dragable = false;
27536 onMouseWheel : function(e)
27540 this.startScale = this.scale;
27542 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27544 if(!this.zoomable()){
27545 this.scale = this.startScale;
27554 zoomable : function()
27556 var minScale = this.thumbEl.getWidth() / this.minWidth;
27558 if(this.minWidth < this.minHeight){
27559 minScale = this.thumbEl.getHeight() / this.minHeight;
27562 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27563 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27567 (this.rotate == 0 || this.rotate == 180) &&
27569 width > this.imageEl.OriginWidth ||
27570 height > this.imageEl.OriginHeight ||
27571 (width < this.minWidth && height < this.minHeight)
27579 (this.rotate == 90 || this.rotate == 270) &&
27581 width > this.imageEl.OriginWidth ||
27582 height > this.imageEl.OriginHeight ||
27583 (width < this.minHeight && height < this.minWidth)
27590 !this.isDocument &&
27591 (this.rotate == 0 || this.rotate == 180) &&
27593 width < this.minWidth ||
27594 width > this.imageEl.OriginWidth ||
27595 height < this.minHeight ||
27596 height > this.imageEl.OriginHeight
27603 !this.isDocument &&
27604 (this.rotate == 90 || this.rotate == 270) &&
27606 width < this.minHeight ||
27607 width > this.imageEl.OriginWidth ||
27608 height < this.minWidth ||
27609 height > this.imageEl.OriginHeight
27619 onRotateLeft : function(e)
27621 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27623 var minScale = this.thumbEl.getWidth() / this.minWidth;
27625 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27626 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27628 this.startScale = this.scale;
27630 while (this.getScaleLevel() < minScale){
27632 this.scale = this.scale + 1;
27634 if(!this.zoomable()){
27639 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27640 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27645 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27652 this.scale = this.startScale;
27654 this.onRotateFail();
27659 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27661 if(this.isDocument){
27662 this.setThumbBoxSize();
27663 this.setThumbBoxPosition();
27664 this.setCanvasPosition();
27669 this.fireEvent('rotate', this, 'left');
27673 onRotateRight : function(e)
27675 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27677 var minScale = this.thumbEl.getWidth() / this.minWidth;
27679 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27680 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27682 this.startScale = this.scale;
27684 while (this.getScaleLevel() < minScale){
27686 this.scale = this.scale + 1;
27688 if(!this.zoomable()){
27693 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27694 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27699 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27706 this.scale = this.startScale;
27708 this.onRotateFail();
27713 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27715 if(this.isDocument){
27716 this.setThumbBoxSize();
27717 this.setThumbBoxPosition();
27718 this.setCanvasPosition();
27723 this.fireEvent('rotate', this, 'right');
27726 onRotateFail : function()
27728 this.errorEl.show(true);
27732 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27737 this.previewEl.dom.innerHTML = '';
27739 var canvasEl = document.createElement("canvas");
27741 var contextEl = canvasEl.getContext("2d");
27743 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27744 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27745 var center = this.imageEl.OriginWidth / 2;
27747 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27748 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27749 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27750 center = this.imageEl.OriginHeight / 2;
27753 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27755 contextEl.translate(center, center);
27756 contextEl.rotate(this.rotate * Math.PI / 180);
27758 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27760 this.canvasEl = document.createElement("canvas");
27762 this.contextEl = this.canvasEl.getContext("2d");
27764 switch (this.rotate) {
27767 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27768 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27770 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27775 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27776 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27778 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27779 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);
27783 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27788 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27789 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27791 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27792 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);
27796 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);
27801 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27802 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27804 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27805 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27809 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);
27816 this.previewEl.appendChild(this.canvasEl);
27818 this.setCanvasPosition();
27823 if(!this.canvasLoaded){
27827 var imageCanvas = document.createElement("canvas");
27829 var imageContext = imageCanvas.getContext("2d");
27831 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27832 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27834 var center = imageCanvas.width / 2;
27836 imageContext.translate(center, center);
27838 imageContext.rotate(this.rotate * Math.PI / 180);
27840 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27842 var canvas = document.createElement("canvas");
27844 var context = canvas.getContext("2d");
27846 canvas.width = this.minWidth;
27847 canvas.height = this.minHeight;
27849 switch (this.rotate) {
27852 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27853 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27855 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27856 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27858 var targetWidth = this.minWidth - 2 * x;
27859 var targetHeight = this.minHeight - 2 * y;
27863 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27864 scale = targetWidth / width;
27867 if(x > 0 && y == 0){
27868 scale = targetHeight / height;
27871 if(x > 0 && y > 0){
27872 scale = targetWidth / width;
27874 if(width < height){
27875 scale = targetHeight / height;
27879 context.scale(scale, scale);
27881 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27882 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27884 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27885 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27887 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27892 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27893 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27895 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27896 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27898 var targetWidth = this.minWidth - 2 * x;
27899 var targetHeight = this.minHeight - 2 * y;
27903 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27904 scale = targetWidth / width;
27907 if(x > 0 && y == 0){
27908 scale = targetHeight / height;
27911 if(x > 0 && y > 0){
27912 scale = targetWidth / width;
27914 if(width < height){
27915 scale = targetHeight / height;
27919 context.scale(scale, scale);
27921 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27922 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27924 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27925 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27927 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27929 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27934 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27935 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27937 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27938 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27940 var targetWidth = this.minWidth - 2 * x;
27941 var targetHeight = this.minHeight - 2 * y;
27945 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27946 scale = targetWidth / width;
27949 if(x > 0 && y == 0){
27950 scale = targetHeight / height;
27953 if(x > 0 && y > 0){
27954 scale = targetWidth / width;
27956 if(width < height){
27957 scale = targetHeight / height;
27961 context.scale(scale, scale);
27963 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27964 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27966 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27967 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27969 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27970 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27972 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27977 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27978 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27980 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27981 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27983 var targetWidth = this.minWidth - 2 * x;
27984 var targetHeight = this.minHeight - 2 * y;
27988 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27989 scale = targetWidth / width;
27992 if(x > 0 && y == 0){
27993 scale = targetHeight / height;
27996 if(x > 0 && y > 0){
27997 scale = targetWidth / width;
27999 if(width < height){
28000 scale = targetHeight / height;
28004 context.scale(scale, scale);
28006 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28007 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28009 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28010 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28012 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28014 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28021 this.cropData = canvas.toDataURL(this.cropType);
28023 if(this.fireEvent('crop', this, this.cropData) !== false){
28024 this.process(this.file, this.cropData);
28031 setThumbBoxSize : function()
28035 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28036 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28037 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28039 this.minWidth = width;
28040 this.minHeight = height;
28042 if(this.rotate == 90 || this.rotate == 270){
28043 this.minWidth = height;
28044 this.minHeight = width;
28049 width = Math.ceil(this.minWidth * height / this.minHeight);
28051 if(this.minWidth > this.minHeight){
28053 height = Math.ceil(this.minHeight * width / this.minWidth);
28056 this.thumbEl.setStyle({
28057 width : width + 'px',
28058 height : height + 'px'
28065 setThumbBoxPosition : function()
28067 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28068 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28070 this.thumbEl.setLeft(x);
28071 this.thumbEl.setTop(y);
28075 baseRotateLevel : function()
28077 this.baseRotate = 1;
28080 typeof(this.exif) != 'undefined' &&
28081 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28082 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28084 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28087 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28091 baseScaleLevel : function()
28095 if(this.isDocument){
28097 if(this.baseRotate == 6 || this.baseRotate == 8){
28099 height = this.thumbEl.getHeight();
28100 this.baseScale = height / this.imageEl.OriginWidth;
28102 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28103 width = this.thumbEl.getWidth();
28104 this.baseScale = width / this.imageEl.OriginHeight;
28110 height = this.thumbEl.getHeight();
28111 this.baseScale = height / this.imageEl.OriginHeight;
28113 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28114 width = this.thumbEl.getWidth();
28115 this.baseScale = width / this.imageEl.OriginWidth;
28121 if(this.baseRotate == 6 || this.baseRotate == 8){
28123 width = this.thumbEl.getHeight();
28124 this.baseScale = width / this.imageEl.OriginHeight;
28126 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28127 height = this.thumbEl.getWidth();
28128 this.baseScale = height / this.imageEl.OriginHeight;
28131 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28132 height = this.thumbEl.getWidth();
28133 this.baseScale = height / this.imageEl.OriginHeight;
28135 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28136 width = this.thumbEl.getHeight();
28137 this.baseScale = width / this.imageEl.OriginWidth;
28144 width = this.thumbEl.getWidth();
28145 this.baseScale = width / this.imageEl.OriginWidth;
28147 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28148 height = this.thumbEl.getHeight();
28149 this.baseScale = height / this.imageEl.OriginHeight;
28152 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28154 height = this.thumbEl.getHeight();
28155 this.baseScale = height / this.imageEl.OriginHeight;
28157 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28158 width = this.thumbEl.getWidth();
28159 this.baseScale = width / this.imageEl.OriginWidth;
28167 getScaleLevel : function()
28169 return this.baseScale * Math.pow(1.1, this.scale);
28172 onTouchStart : function(e)
28174 if(!this.canvasLoaded){
28175 this.beforeSelectFile(e);
28179 var touches = e.browserEvent.touches;
28185 if(touches.length == 1){
28186 this.onMouseDown(e);
28190 if(touches.length != 2){
28196 for(var i = 0, finger; finger = touches[i]; i++){
28197 coords.push(finger.pageX, finger.pageY);
28200 var x = Math.pow(coords[0] - coords[2], 2);
28201 var y = Math.pow(coords[1] - coords[3], 2);
28203 this.startDistance = Math.sqrt(x + y);
28205 this.startScale = this.scale;
28207 this.pinching = true;
28208 this.dragable = false;
28212 onTouchMove : function(e)
28214 if(!this.pinching && !this.dragable){
28218 var touches = e.browserEvent.touches;
28225 this.onMouseMove(e);
28231 for(var i = 0, finger; finger = touches[i]; i++){
28232 coords.push(finger.pageX, finger.pageY);
28235 var x = Math.pow(coords[0] - coords[2], 2);
28236 var y = Math.pow(coords[1] - coords[3], 2);
28238 this.endDistance = Math.sqrt(x + y);
28240 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28242 if(!this.zoomable()){
28243 this.scale = this.startScale;
28251 onTouchEnd : function(e)
28253 this.pinching = false;
28254 this.dragable = false;
28258 process : function(file, crop)
28261 this.maskEl.mask(this.loadingText);
28264 this.xhr = new XMLHttpRequest();
28266 file.xhr = this.xhr;
28268 this.xhr.open(this.method, this.url, true);
28271 "Accept": "application/json",
28272 "Cache-Control": "no-cache",
28273 "X-Requested-With": "XMLHttpRequest"
28276 for (var headerName in headers) {
28277 var headerValue = headers[headerName];
28279 this.xhr.setRequestHeader(headerName, headerValue);
28285 this.xhr.onload = function()
28287 _this.xhrOnLoad(_this.xhr);
28290 this.xhr.onerror = function()
28292 _this.xhrOnError(_this.xhr);
28295 var formData = new FormData();
28297 formData.append('returnHTML', 'NO');
28300 formData.append('crop', crop);
28303 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28304 formData.append(this.paramName, file, file.name);
28307 if(typeof(file.filename) != 'undefined'){
28308 formData.append('filename', file.filename);
28311 if(typeof(file.mimetype) != 'undefined'){
28312 formData.append('mimetype', file.mimetype);
28315 if(this.fireEvent('arrange', this, formData) != false){
28316 this.xhr.send(formData);
28320 xhrOnLoad : function(xhr)
28323 this.maskEl.unmask();
28326 if (xhr.readyState !== 4) {
28327 this.fireEvent('exception', this, xhr);
28331 var response = Roo.decode(xhr.responseText);
28333 if(!response.success){
28334 this.fireEvent('exception', this, xhr);
28338 var response = Roo.decode(xhr.responseText);
28340 this.fireEvent('upload', this, response);
28344 xhrOnError : function()
28347 this.maskEl.unmask();
28350 Roo.log('xhr on error');
28352 var response = Roo.decode(xhr.responseText);
28358 prepare : function(file)
28361 this.maskEl.mask(this.loadingText);
28367 if(typeof(file) === 'string'){
28368 this.loadCanvas(file);
28372 if(!file || !this.urlAPI){
28377 this.cropType = file.type;
28381 if(this.fireEvent('prepare', this, this.file) != false){
28383 var reader = new FileReader();
28385 reader.onload = function (e) {
28386 if (e.target.error) {
28387 Roo.log(e.target.error);
28391 var buffer = e.target.result,
28392 dataView = new DataView(buffer),
28394 maxOffset = dataView.byteLength - 4,
28398 if (dataView.getUint16(0) === 0xffd8) {
28399 while (offset < maxOffset) {
28400 markerBytes = dataView.getUint16(offset);
28402 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28403 markerLength = dataView.getUint16(offset + 2) + 2;
28404 if (offset + markerLength > dataView.byteLength) {
28405 Roo.log('Invalid meta data: Invalid segment size.');
28409 if(markerBytes == 0xffe1){
28410 _this.parseExifData(
28417 offset += markerLength;
28427 var url = _this.urlAPI.createObjectURL(_this.file);
28429 _this.loadCanvas(url);
28434 reader.readAsArrayBuffer(this.file);
28440 parseExifData : function(dataView, offset, length)
28442 var tiffOffset = offset + 10,
28446 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28447 // No Exif data, might be XMP data instead
28451 // Check for the ASCII code for "Exif" (0x45786966):
28452 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28453 // No Exif data, might be XMP data instead
28456 if (tiffOffset + 8 > dataView.byteLength) {
28457 Roo.log('Invalid Exif data: Invalid segment size.');
28460 // Check for the two null bytes:
28461 if (dataView.getUint16(offset + 8) !== 0x0000) {
28462 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28465 // Check the byte alignment:
28466 switch (dataView.getUint16(tiffOffset)) {
28468 littleEndian = true;
28471 littleEndian = false;
28474 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28477 // Check for the TIFF tag marker (0x002A):
28478 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28479 Roo.log('Invalid Exif data: Missing TIFF marker.');
28482 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28483 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28485 this.parseExifTags(
28488 tiffOffset + dirOffset,
28493 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28498 if (dirOffset + 6 > dataView.byteLength) {
28499 Roo.log('Invalid Exif data: Invalid directory offset.');
28502 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28503 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28504 if (dirEndOffset + 4 > dataView.byteLength) {
28505 Roo.log('Invalid Exif data: Invalid directory size.');
28508 for (i = 0; i < tagsNumber; i += 1) {
28512 dirOffset + 2 + 12 * i, // tag offset
28516 // Return the offset to the next directory:
28517 return dataView.getUint32(dirEndOffset, littleEndian);
28520 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28522 var tag = dataView.getUint16(offset, littleEndian);
28524 this.exif[tag] = this.getExifValue(
28528 dataView.getUint16(offset + 2, littleEndian), // tag type
28529 dataView.getUint32(offset + 4, littleEndian), // tag length
28534 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28536 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28545 Roo.log('Invalid Exif data: Invalid tag type.');
28549 tagSize = tagType.size * length;
28550 // Determine if the value is contained in the dataOffset bytes,
28551 // or if the value at the dataOffset is a pointer to the actual data:
28552 dataOffset = tagSize > 4 ?
28553 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28554 if (dataOffset + tagSize > dataView.byteLength) {
28555 Roo.log('Invalid Exif data: Invalid data offset.');
28558 if (length === 1) {
28559 return tagType.getValue(dataView, dataOffset, littleEndian);
28562 for (i = 0; i < length; i += 1) {
28563 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28566 if (tagType.ascii) {
28568 // Concatenate the chars:
28569 for (i = 0; i < values.length; i += 1) {
28571 // Ignore the terminating NULL byte(s):
28572 if (c === '\u0000') {
28584 Roo.apply(Roo.bootstrap.UploadCropbox, {
28586 'Orientation': 0x0112
28590 1: 0, //'top-left',
28592 3: 180, //'bottom-right',
28593 // 4: 'bottom-left',
28595 6: 90, //'right-top',
28596 // 7: 'right-bottom',
28597 8: 270 //'left-bottom'
28601 // byte, 8-bit unsigned int:
28603 getValue: function (dataView, dataOffset) {
28604 return dataView.getUint8(dataOffset);
28608 // ascii, 8-bit byte:
28610 getValue: function (dataView, dataOffset) {
28611 return String.fromCharCode(dataView.getUint8(dataOffset));
28616 // short, 16 bit int:
28618 getValue: function (dataView, dataOffset, littleEndian) {
28619 return dataView.getUint16(dataOffset, littleEndian);
28623 // long, 32 bit int:
28625 getValue: function (dataView, dataOffset, littleEndian) {
28626 return dataView.getUint32(dataOffset, littleEndian);
28630 // rational = two long values, first is numerator, second is denominator:
28632 getValue: function (dataView, dataOffset, littleEndian) {
28633 return dataView.getUint32(dataOffset, littleEndian) /
28634 dataView.getUint32(dataOffset + 4, littleEndian);
28638 // slong, 32 bit signed int:
28640 getValue: function (dataView, dataOffset, littleEndian) {
28641 return dataView.getInt32(dataOffset, littleEndian);
28645 // srational, two slongs, first is numerator, second is denominator:
28647 getValue: function (dataView, dataOffset, littleEndian) {
28648 return dataView.getInt32(dataOffset, littleEndian) /
28649 dataView.getInt32(dataOffset + 4, littleEndian);
28659 cls : 'btn-group roo-upload-cropbox-rotate-left',
28660 action : 'rotate-left',
28664 cls : 'btn btn-default',
28665 html : '<i class="fa fa-undo"></i>'
28671 cls : 'btn-group roo-upload-cropbox-picture',
28672 action : 'picture',
28676 cls : 'btn btn-default',
28677 html : '<i class="fa fa-picture-o"></i>'
28683 cls : 'btn-group roo-upload-cropbox-rotate-right',
28684 action : 'rotate-right',
28688 cls : 'btn btn-default',
28689 html : '<i class="fa fa-repeat"></i>'
28697 cls : 'btn-group roo-upload-cropbox-rotate-left',
28698 action : 'rotate-left',
28702 cls : 'btn btn-default',
28703 html : '<i class="fa fa-undo"></i>'
28709 cls : 'btn-group roo-upload-cropbox-download',
28710 action : 'download',
28714 cls : 'btn btn-default',
28715 html : '<i class="fa fa-download"></i>'
28721 cls : 'btn-group roo-upload-cropbox-crop',
28726 cls : 'btn btn-default',
28727 html : '<i class="fa fa-crop"></i>'
28733 cls : 'btn-group roo-upload-cropbox-trash',
28738 cls : 'btn btn-default',
28739 html : '<i class="fa fa-trash"></i>'
28745 cls : 'btn-group roo-upload-cropbox-rotate-right',
28746 action : 'rotate-right',
28750 cls : 'btn btn-default',
28751 html : '<i class="fa fa-repeat"></i>'
28759 cls : 'btn-group roo-upload-cropbox-rotate-left',
28760 action : 'rotate-left',
28764 cls : 'btn btn-default',
28765 html : '<i class="fa fa-undo"></i>'
28771 cls : 'btn-group roo-upload-cropbox-rotate-right',
28772 action : 'rotate-right',
28776 cls : 'btn btn-default',
28777 html : '<i class="fa fa-repeat"></i>'
28790 * @class Roo.bootstrap.DocumentManager
28791 * @extends Roo.bootstrap.Component
28792 * Bootstrap DocumentManager class
28793 * @cfg {String} paramName default 'imageUpload'
28794 * @cfg {String} toolTipName default 'filename'
28795 * @cfg {String} method default POST
28796 * @cfg {String} url action url
28797 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28798 * @cfg {Boolean} multiple multiple upload default true
28799 * @cfg {Number} thumbSize default 300
28800 * @cfg {String} fieldLabel
28801 * @cfg {Number} labelWidth default 4
28802 * @cfg {String} labelAlign (left|top) default left
28803 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28804 * @cfg {Number} labellg set the width of label (1-12)
28805 * @cfg {Number} labelmd set the width of label (1-12)
28806 * @cfg {Number} labelsm set the width of label (1-12)
28807 * @cfg {Number} labelxs set the width of label (1-12)
28810 * Create a new DocumentManager
28811 * @param {Object} config The config object
28814 Roo.bootstrap.DocumentManager = function(config){
28815 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28818 this.delegates = [];
28823 * Fire when initial the DocumentManager
28824 * @param {Roo.bootstrap.DocumentManager} this
28829 * inspect selected file
28830 * @param {Roo.bootstrap.DocumentManager} this
28831 * @param {File} file
28836 * Fire when xhr load exception
28837 * @param {Roo.bootstrap.DocumentManager} this
28838 * @param {XMLHttpRequest} xhr
28840 "exception" : true,
28842 * @event afterupload
28843 * Fire when xhr load exception
28844 * @param {Roo.bootstrap.DocumentManager} this
28845 * @param {XMLHttpRequest} xhr
28847 "afterupload" : true,
28850 * prepare the form data
28851 * @param {Roo.bootstrap.DocumentManager} this
28852 * @param {Object} formData
28857 * Fire when remove the file
28858 * @param {Roo.bootstrap.DocumentManager} this
28859 * @param {Object} file
28864 * Fire after refresh the file
28865 * @param {Roo.bootstrap.DocumentManager} this
28870 * Fire after click the image
28871 * @param {Roo.bootstrap.DocumentManager} this
28872 * @param {Object} file
28877 * Fire when upload a image and editable set to true
28878 * @param {Roo.bootstrap.DocumentManager} this
28879 * @param {Object} file
28883 * @event beforeselectfile
28884 * Fire before select file
28885 * @param {Roo.bootstrap.DocumentManager} this
28887 "beforeselectfile" : true,
28890 * Fire before process file
28891 * @param {Roo.bootstrap.DocumentManager} this
28892 * @param {Object} file
28896 * @event previewrendered
28897 * Fire when preview rendered
28898 * @param {Roo.bootstrap.DocumentManager} this
28899 * @param {Object} file
28901 "previewrendered" : true,
28904 "previewResize" : true
28909 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28918 paramName : 'imageUpload',
28919 toolTipName : 'filename',
28922 labelAlign : 'left',
28932 getAutoCreate : function()
28934 var managerWidget = {
28936 cls : 'roo-document-manager',
28940 cls : 'roo-document-manager-selector',
28945 cls : 'roo-document-manager-uploader',
28949 cls : 'roo-document-manager-upload-btn',
28950 html : '<i class="fa fa-plus"></i>'
28961 cls : 'column col-md-12',
28966 if(this.fieldLabel.length){
28971 cls : 'column col-md-12',
28972 html : this.fieldLabel
28976 cls : 'column col-md-12',
28981 if(this.labelAlign == 'left'){
28986 html : this.fieldLabel
28995 if(this.labelWidth > 12){
28996 content[0].style = "width: " + this.labelWidth + 'px';
28999 if(this.labelWidth < 13 && this.labelmd == 0){
29000 this.labelmd = this.labelWidth;
29003 if(this.labellg > 0){
29004 content[0].cls += ' col-lg-' + this.labellg;
29005 content[1].cls += ' col-lg-' + (12 - this.labellg);
29008 if(this.labelmd > 0){
29009 content[0].cls += ' col-md-' + this.labelmd;
29010 content[1].cls += ' col-md-' + (12 - this.labelmd);
29013 if(this.labelsm > 0){
29014 content[0].cls += ' col-sm-' + this.labelsm;
29015 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29018 if(this.labelxs > 0){
29019 content[0].cls += ' col-xs-' + this.labelxs;
29020 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29028 cls : 'row clearfix',
29036 initEvents : function()
29038 this.managerEl = this.el.select('.roo-document-manager', true).first();
29039 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29041 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29042 this.selectorEl.hide();
29045 this.selectorEl.attr('multiple', 'multiple');
29048 this.selectorEl.on('change', this.onFileSelected, this);
29050 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29051 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29053 this.uploader.on('click', this.onUploaderClick, this);
29055 this.renderProgressDialog();
29059 window.addEventListener("resize", function() { _this.refresh(); } );
29061 this.fireEvent('initial', this);
29064 renderProgressDialog : function()
29068 this.progressDialog = new Roo.bootstrap.Modal({
29069 cls : 'roo-document-manager-progress-dialog',
29070 allow_close : false,
29080 btnclick : function() {
29081 _this.uploadCancel();
29087 this.progressDialog.render(Roo.get(document.body));
29089 this.progress = new Roo.bootstrap.Progress({
29090 cls : 'roo-document-manager-progress',
29095 this.progress.render(this.progressDialog.getChildContainer());
29097 this.progressBar = new Roo.bootstrap.ProgressBar({
29098 cls : 'roo-document-manager-progress-bar',
29101 aria_valuemax : 12,
29105 this.progressBar.render(this.progress.getChildContainer());
29108 onUploaderClick : function(e)
29110 e.preventDefault();
29112 if(this.fireEvent('beforeselectfile', this) != false){
29113 this.selectorEl.dom.click();
29118 onFileSelected : function(e)
29120 e.preventDefault();
29122 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29126 Roo.each(this.selectorEl.dom.files, function(file){
29127 if(this.fireEvent('inspect', this, file) != false){
29128 this.files.push(file);
29138 this.selectorEl.dom.value = '';
29140 if(!this.files || !this.files.length){
29144 if(this.boxes > 0 && this.files.length > this.boxes){
29145 this.files = this.files.slice(0, this.boxes);
29148 this.uploader.show();
29150 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29151 this.uploader.hide();
29160 Roo.each(this.files, function(file){
29162 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29163 var f = this.renderPreview(file);
29168 if(file.type.indexOf('image') != -1){
29169 this.delegates.push(
29171 _this.process(file);
29172 }).createDelegate(this)
29180 _this.process(file);
29181 }).createDelegate(this)
29186 this.files = files;
29188 this.delegates = this.delegates.concat(docs);
29190 if(!this.delegates.length){
29195 this.progressBar.aria_valuemax = this.delegates.length;
29202 arrange : function()
29204 if(!this.delegates.length){
29205 this.progressDialog.hide();
29210 var delegate = this.delegates.shift();
29212 this.progressDialog.show();
29214 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29216 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29221 refresh : function()
29223 this.uploader.show();
29225 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29226 this.uploader.hide();
29229 Roo.isTouch ? this.closable(false) : this.closable(true);
29231 this.fireEvent('refresh', this);
29234 onRemove : function(e, el, o)
29236 e.preventDefault();
29238 this.fireEvent('remove', this, o);
29242 remove : function(o)
29246 Roo.each(this.files, function(file){
29247 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29256 this.files = files;
29263 Roo.each(this.files, function(file){
29268 file.target.remove();
29277 onClick : function(e, el, o)
29279 e.preventDefault();
29281 this.fireEvent('click', this, o);
29285 closable : function(closable)
29287 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29289 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29301 xhrOnLoad : function(xhr)
29303 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29307 if (xhr.readyState !== 4) {
29309 this.fireEvent('exception', this, xhr);
29313 var response = Roo.decode(xhr.responseText);
29315 if(!response.success){
29317 this.fireEvent('exception', this, xhr);
29321 var file = this.renderPreview(response.data);
29323 this.files.push(file);
29327 this.fireEvent('afterupload', this, xhr);
29331 xhrOnError : function(xhr)
29333 Roo.log('xhr on error');
29335 var response = Roo.decode(xhr.responseText);
29342 process : function(file)
29344 if(this.fireEvent('process', this, file) !== false){
29345 if(this.editable && file.type.indexOf('image') != -1){
29346 this.fireEvent('edit', this, file);
29350 this.uploadStart(file, false);
29357 uploadStart : function(file, crop)
29359 this.xhr = new XMLHttpRequest();
29361 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29366 file.xhr = this.xhr;
29368 this.managerEl.createChild({
29370 cls : 'roo-document-manager-loading',
29374 tooltip : file.name,
29375 cls : 'roo-document-manager-thumb',
29376 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29382 this.xhr.open(this.method, this.url, true);
29385 "Accept": "application/json",
29386 "Cache-Control": "no-cache",
29387 "X-Requested-With": "XMLHttpRequest"
29390 for (var headerName in headers) {
29391 var headerValue = headers[headerName];
29393 this.xhr.setRequestHeader(headerName, headerValue);
29399 this.xhr.onload = function()
29401 _this.xhrOnLoad(_this.xhr);
29404 this.xhr.onerror = function()
29406 _this.xhrOnError(_this.xhr);
29409 var formData = new FormData();
29411 formData.append('returnHTML', 'NO');
29414 formData.append('crop', crop);
29417 formData.append(this.paramName, file, file.name);
29424 if(this.fireEvent('prepare', this, formData, options) != false){
29426 if(options.manually){
29430 this.xhr.send(formData);
29434 this.uploadCancel();
29437 uploadCancel : function()
29443 this.delegates = [];
29445 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29452 renderPreview : function(file)
29454 if(typeof(file.target) != 'undefined' && file.target){
29458 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29460 var previewEl = this.managerEl.createChild({
29462 cls : 'roo-document-manager-preview',
29466 tooltip : file[this.toolTipName],
29467 cls : 'roo-document-manager-thumb',
29468 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29473 html : '<i class="fa fa-times-circle"></i>'
29478 var close = previewEl.select('button.close', true).first();
29480 close.on('click', this.onRemove, this, file);
29482 file.target = previewEl;
29484 var image = previewEl.select('img', true).first();
29488 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29490 image.on('click', this.onClick, this, file);
29492 this.fireEvent('previewrendered', this, file);
29498 onPreviewLoad : function(file, image)
29500 if(typeof(file.target) == 'undefined' || !file.target){
29504 var width = image.dom.naturalWidth || image.dom.width;
29505 var height = image.dom.naturalHeight || image.dom.height;
29507 if(!this.previewResize) {
29511 if(width > height){
29512 file.target.addClass('wide');
29516 file.target.addClass('tall');
29521 uploadFromSource : function(file, crop)
29523 this.xhr = new XMLHttpRequest();
29525 this.managerEl.createChild({
29527 cls : 'roo-document-manager-loading',
29531 tooltip : file.name,
29532 cls : 'roo-document-manager-thumb',
29533 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29539 this.xhr.open(this.method, this.url, true);
29542 "Accept": "application/json",
29543 "Cache-Control": "no-cache",
29544 "X-Requested-With": "XMLHttpRequest"
29547 for (var headerName in headers) {
29548 var headerValue = headers[headerName];
29550 this.xhr.setRequestHeader(headerName, headerValue);
29556 this.xhr.onload = function()
29558 _this.xhrOnLoad(_this.xhr);
29561 this.xhr.onerror = function()
29563 _this.xhrOnError(_this.xhr);
29566 var formData = new FormData();
29568 formData.append('returnHTML', 'NO');
29570 formData.append('crop', crop);
29572 if(typeof(file.filename) != 'undefined'){
29573 formData.append('filename', file.filename);
29576 if(typeof(file.mimetype) != 'undefined'){
29577 formData.append('mimetype', file.mimetype);
29582 if(this.fireEvent('prepare', this, formData) != false){
29583 this.xhr.send(formData);
29593 * @class Roo.bootstrap.DocumentViewer
29594 * @extends Roo.bootstrap.Component
29595 * Bootstrap DocumentViewer class
29596 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29597 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29600 * Create a new DocumentViewer
29601 * @param {Object} config The config object
29604 Roo.bootstrap.DocumentViewer = function(config){
29605 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29610 * Fire after initEvent
29611 * @param {Roo.bootstrap.DocumentViewer} this
29617 * @param {Roo.bootstrap.DocumentViewer} this
29622 * Fire after download button
29623 * @param {Roo.bootstrap.DocumentViewer} this
29628 * Fire after trash button
29629 * @param {Roo.bootstrap.DocumentViewer} this
29636 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29638 showDownload : true,
29642 getAutoCreate : function()
29646 cls : 'roo-document-viewer',
29650 cls : 'roo-document-viewer-body',
29654 cls : 'roo-document-viewer-thumb',
29658 cls : 'roo-document-viewer-image'
29666 cls : 'roo-document-viewer-footer',
29669 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29673 cls : 'btn-group roo-document-viewer-download',
29677 cls : 'btn btn-default',
29678 html : '<i class="fa fa-download"></i>'
29684 cls : 'btn-group roo-document-viewer-trash',
29688 cls : 'btn btn-default',
29689 html : '<i class="fa fa-trash"></i>'
29702 initEvents : function()
29704 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29705 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29707 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29708 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29710 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29711 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29713 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29714 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29716 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29717 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29719 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29720 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29722 this.bodyEl.on('click', this.onClick, this);
29723 this.downloadBtn.on('click', this.onDownload, this);
29724 this.trashBtn.on('click', this.onTrash, this);
29726 this.downloadBtn.hide();
29727 this.trashBtn.hide();
29729 if(this.showDownload){
29730 this.downloadBtn.show();
29733 if(this.showTrash){
29734 this.trashBtn.show();
29737 if(!this.showDownload && !this.showTrash) {
29738 this.footerEl.hide();
29743 initial : function()
29745 this.fireEvent('initial', this);
29749 onClick : function(e)
29751 e.preventDefault();
29753 this.fireEvent('click', this);
29756 onDownload : function(e)
29758 e.preventDefault();
29760 this.fireEvent('download', this);
29763 onTrash : function(e)
29765 e.preventDefault();
29767 this.fireEvent('trash', this);
29779 * @class Roo.bootstrap.NavProgressBar
29780 * @extends Roo.bootstrap.Component
29781 * Bootstrap NavProgressBar class
29784 * Create a new nav progress bar
29785 * @param {Object} config The config object
29788 Roo.bootstrap.NavProgressBar = function(config){
29789 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29791 this.bullets = this.bullets || [];
29793 // Roo.bootstrap.NavProgressBar.register(this);
29797 * Fires when the active item changes
29798 * @param {Roo.bootstrap.NavProgressBar} this
29799 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29800 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29807 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29812 getAutoCreate : function()
29814 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29818 cls : 'roo-navigation-bar-group',
29822 cls : 'roo-navigation-top-bar'
29826 cls : 'roo-navigation-bullets-bar',
29830 cls : 'roo-navigation-bar'
29837 cls : 'roo-navigation-bottom-bar'
29847 initEvents: function()
29852 onRender : function(ct, position)
29854 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29856 if(this.bullets.length){
29857 Roo.each(this.bullets, function(b){
29866 addItem : function(cfg)
29868 var item = new Roo.bootstrap.NavProgressItem(cfg);
29870 item.parentId = this.id;
29871 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29874 var top = new Roo.bootstrap.Element({
29876 cls : 'roo-navigation-bar-text'
29879 var bottom = new Roo.bootstrap.Element({
29881 cls : 'roo-navigation-bar-text'
29884 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29885 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29887 var topText = new Roo.bootstrap.Element({
29889 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29892 var bottomText = new Roo.bootstrap.Element({
29894 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29897 topText.onRender(top.el, null);
29898 bottomText.onRender(bottom.el, null);
29901 item.bottomEl = bottom;
29904 this.barItems.push(item);
29909 getActive : function()
29911 var active = false;
29913 Roo.each(this.barItems, function(v){
29915 if (!v.isActive()) {
29927 setActiveItem : function(item)
29931 Roo.each(this.barItems, function(v){
29932 if (v.rid == item.rid) {
29936 if (v.isActive()) {
29937 v.setActive(false);
29942 item.setActive(true);
29944 this.fireEvent('changed', this, item, prev);
29947 getBarItem: function(rid)
29951 Roo.each(this.barItems, function(e) {
29952 if (e.rid != rid) {
29963 indexOfItem : function(item)
29967 Roo.each(this.barItems, function(v, i){
29969 if (v.rid != item.rid) {
29980 setActiveNext : function()
29982 var i = this.indexOfItem(this.getActive());
29984 if (i > this.barItems.length) {
29988 this.setActiveItem(this.barItems[i+1]);
29991 setActivePrev : function()
29993 var i = this.indexOfItem(this.getActive());
29999 this.setActiveItem(this.barItems[i-1]);
30002 format : function()
30004 if(!this.barItems.length){
30008 var width = 100 / this.barItems.length;
30010 Roo.each(this.barItems, function(i){
30011 i.el.setStyle('width', width + '%');
30012 i.topEl.el.setStyle('width', width + '%');
30013 i.bottomEl.el.setStyle('width', width + '%');
30022 * Nav Progress Item
30027 * @class Roo.bootstrap.NavProgressItem
30028 * @extends Roo.bootstrap.Component
30029 * Bootstrap NavProgressItem class
30030 * @cfg {String} rid the reference id
30031 * @cfg {Boolean} active (true|false) Is item active default false
30032 * @cfg {Boolean} disabled (true|false) Is item active default false
30033 * @cfg {String} html
30034 * @cfg {String} position (top|bottom) text position default bottom
30035 * @cfg {String} icon show icon instead of number
30038 * Create a new NavProgressItem
30039 * @param {Object} config The config object
30041 Roo.bootstrap.NavProgressItem = function(config){
30042 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30047 * The raw click event for the entire grid.
30048 * @param {Roo.bootstrap.NavProgressItem} this
30049 * @param {Roo.EventObject} e
30056 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30062 position : 'bottom',
30065 getAutoCreate : function()
30067 var iconCls = 'roo-navigation-bar-item-icon';
30069 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30073 cls: 'roo-navigation-bar-item',
30083 cfg.cls += ' active';
30086 cfg.cls += ' disabled';
30092 disable : function()
30094 this.setDisabled(true);
30097 enable : function()
30099 this.setDisabled(false);
30102 initEvents: function()
30104 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30106 this.iconEl.on('click', this.onClick, this);
30109 onClick : function(e)
30111 e.preventDefault();
30117 if(this.fireEvent('click', this, e) === false){
30121 this.parent().setActiveItem(this);
30124 isActive: function ()
30126 return this.active;
30129 setActive : function(state)
30131 if(this.active == state){
30135 this.active = state;
30138 this.el.addClass('active');
30142 this.el.removeClass('active');
30147 setDisabled : function(state)
30149 if(this.disabled == state){
30153 this.disabled = state;
30156 this.el.addClass('disabled');
30160 this.el.removeClass('disabled');
30163 tooltipEl : function()
30165 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30178 * @class Roo.bootstrap.FieldLabel
30179 * @extends Roo.bootstrap.Component
30180 * Bootstrap FieldLabel class
30181 * @cfg {String} html contents of the element
30182 * @cfg {String} tag tag of the element default label
30183 * @cfg {String} cls class of the element
30184 * @cfg {String} target label target
30185 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30186 * @cfg {String} invalidClass default "text-warning"
30187 * @cfg {String} validClass default "text-success"
30188 * @cfg {String} iconTooltip default "This field is required"
30189 * @cfg {String} indicatorpos (left|right) default left
30192 * Create a new FieldLabel
30193 * @param {Object} config The config object
30196 Roo.bootstrap.FieldLabel = function(config){
30197 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30202 * Fires after the field has been marked as invalid.
30203 * @param {Roo.form.FieldLabel} this
30204 * @param {String} msg The validation message
30209 * Fires after the field has been validated with no errors.
30210 * @param {Roo.form.FieldLabel} this
30216 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30223 invalidClass : 'has-warning',
30224 validClass : 'has-success',
30225 iconTooltip : 'This field is required',
30226 indicatorpos : 'left',
30228 getAutoCreate : function(){
30231 if (!this.allowBlank) {
30237 cls : 'roo-bootstrap-field-label ' + this.cls,
30242 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30243 tooltip : this.iconTooltip
30252 if(this.indicatorpos == 'right'){
30255 cls : 'roo-bootstrap-field-label ' + this.cls,
30264 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30265 tooltip : this.iconTooltip
30274 initEvents: function()
30276 Roo.bootstrap.Element.superclass.initEvents.call(this);
30278 this.indicator = this.indicatorEl();
30280 if(this.indicator){
30281 this.indicator.removeClass('visible');
30282 this.indicator.addClass('invisible');
30285 Roo.bootstrap.FieldLabel.register(this);
30288 indicatorEl : function()
30290 var indicator = this.el.select('i.roo-required-indicator',true).first();
30301 * Mark this field as valid
30303 markValid : function()
30305 if(this.indicator){
30306 this.indicator.removeClass('visible');
30307 this.indicator.addClass('invisible');
30310 this.el.removeClass(this.invalidClass);
30312 this.el.addClass(this.validClass);
30314 this.fireEvent('valid', this);
30318 * Mark this field as invalid
30319 * @param {String} msg The validation message
30321 markInvalid : function(msg)
30323 if(this.indicator){
30324 this.indicator.removeClass('invisible');
30325 this.indicator.addClass('visible');
30328 this.el.removeClass(this.validClass);
30330 this.el.addClass(this.invalidClass);
30332 this.fireEvent('invalid', this, msg);
30338 Roo.apply(Roo.bootstrap.FieldLabel, {
30343 * register a FieldLabel Group
30344 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30346 register : function(label)
30348 if(this.groups.hasOwnProperty(label.target)){
30352 this.groups[label.target] = label;
30356 * fetch a FieldLabel Group based on the target
30357 * @param {string} target
30358 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30360 get: function(target) {
30361 if (typeof(this.groups[target]) == 'undefined') {
30365 return this.groups[target] ;
30374 * page DateSplitField.
30380 * @class Roo.bootstrap.DateSplitField
30381 * @extends Roo.bootstrap.Component
30382 * Bootstrap DateSplitField class
30383 * @cfg {string} fieldLabel - the label associated
30384 * @cfg {Number} labelWidth set the width of label (0-12)
30385 * @cfg {String} labelAlign (top|left)
30386 * @cfg {Boolean} dayAllowBlank (true|false) default false
30387 * @cfg {Boolean} monthAllowBlank (true|false) default false
30388 * @cfg {Boolean} yearAllowBlank (true|false) default false
30389 * @cfg {string} dayPlaceholder
30390 * @cfg {string} monthPlaceholder
30391 * @cfg {string} yearPlaceholder
30392 * @cfg {string} dayFormat default 'd'
30393 * @cfg {string} monthFormat default 'm'
30394 * @cfg {string} yearFormat default 'Y'
30395 * @cfg {Number} labellg set the width of label (1-12)
30396 * @cfg {Number} labelmd set the width of label (1-12)
30397 * @cfg {Number} labelsm set the width of label (1-12)
30398 * @cfg {Number} labelxs set the width of label (1-12)
30402 * Create a new DateSplitField
30403 * @param {Object} config The config object
30406 Roo.bootstrap.DateSplitField = function(config){
30407 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30413 * getting the data of years
30414 * @param {Roo.bootstrap.DateSplitField} this
30415 * @param {Object} years
30420 * getting the data of days
30421 * @param {Roo.bootstrap.DateSplitField} this
30422 * @param {Object} days
30427 * Fires after the field has been marked as invalid.
30428 * @param {Roo.form.Field} this
30429 * @param {String} msg The validation message
30434 * Fires after the field has been validated with no errors.
30435 * @param {Roo.form.Field} this
30441 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30444 labelAlign : 'top',
30446 dayAllowBlank : false,
30447 monthAllowBlank : false,
30448 yearAllowBlank : false,
30449 dayPlaceholder : '',
30450 monthPlaceholder : '',
30451 yearPlaceholder : '',
30455 isFormField : true,
30461 getAutoCreate : function()
30465 cls : 'row roo-date-split-field-group',
30470 cls : 'form-hidden-field roo-date-split-field-group-value',
30476 var labelCls = 'col-md-12';
30477 var contentCls = 'col-md-4';
30479 if(this.fieldLabel){
30483 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30487 html : this.fieldLabel
30492 if(this.labelAlign == 'left'){
30494 if(this.labelWidth > 12){
30495 label.style = "width: " + this.labelWidth + 'px';
30498 if(this.labelWidth < 13 && this.labelmd == 0){
30499 this.labelmd = this.labelWidth;
30502 if(this.labellg > 0){
30503 labelCls = ' col-lg-' + this.labellg;
30504 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30507 if(this.labelmd > 0){
30508 labelCls = ' col-md-' + this.labelmd;
30509 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30512 if(this.labelsm > 0){
30513 labelCls = ' col-sm-' + this.labelsm;
30514 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30517 if(this.labelxs > 0){
30518 labelCls = ' col-xs-' + this.labelxs;
30519 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30523 label.cls += ' ' + labelCls;
30525 cfg.cn.push(label);
30528 Roo.each(['day', 'month', 'year'], function(t){
30531 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30538 inputEl: function ()
30540 return this.el.select('.roo-date-split-field-group-value', true).first();
30543 onRender : function(ct, position)
30547 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30549 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30551 this.dayField = new Roo.bootstrap.ComboBox({
30552 allowBlank : this.dayAllowBlank,
30553 alwaysQuery : true,
30554 displayField : 'value',
30557 forceSelection : true,
30559 placeholder : this.dayPlaceholder,
30560 selectOnFocus : true,
30561 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30562 triggerAction : 'all',
30564 valueField : 'value',
30565 store : new Roo.data.SimpleStore({
30566 data : (function() {
30568 _this.fireEvent('days', _this, days);
30571 fields : [ 'value' ]
30574 select : function (_self, record, index)
30576 _this.setValue(_this.getValue());
30581 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30583 this.monthField = new Roo.bootstrap.MonthField({
30584 after : '<i class=\"fa fa-calendar\"></i>',
30585 allowBlank : this.monthAllowBlank,
30586 placeholder : this.monthPlaceholder,
30589 render : function (_self)
30591 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30592 e.preventDefault();
30596 select : function (_self, oldvalue, newvalue)
30598 _this.setValue(_this.getValue());
30603 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30605 this.yearField = new Roo.bootstrap.ComboBox({
30606 allowBlank : this.yearAllowBlank,
30607 alwaysQuery : true,
30608 displayField : 'value',
30611 forceSelection : true,
30613 placeholder : this.yearPlaceholder,
30614 selectOnFocus : true,
30615 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30616 triggerAction : 'all',
30618 valueField : 'value',
30619 store : new Roo.data.SimpleStore({
30620 data : (function() {
30622 _this.fireEvent('years', _this, years);
30625 fields : [ 'value' ]
30628 select : function (_self, record, index)
30630 _this.setValue(_this.getValue());
30635 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30638 setValue : function(v, format)
30640 this.inputEl.dom.value = v;
30642 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30644 var d = Date.parseDate(v, f);
30651 this.setDay(d.format(this.dayFormat));
30652 this.setMonth(d.format(this.monthFormat));
30653 this.setYear(d.format(this.yearFormat));
30660 setDay : function(v)
30662 this.dayField.setValue(v);
30663 this.inputEl.dom.value = this.getValue();
30668 setMonth : function(v)
30670 this.monthField.setValue(v, true);
30671 this.inputEl.dom.value = this.getValue();
30676 setYear : function(v)
30678 this.yearField.setValue(v);
30679 this.inputEl.dom.value = this.getValue();
30684 getDay : function()
30686 return this.dayField.getValue();
30689 getMonth : function()
30691 return this.monthField.getValue();
30694 getYear : function()
30696 return this.yearField.getValue();
30699 getValue : function()
30701 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30703 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30713 this.inputEl.dom.value = '';
30718 validate : function()
30720 var d = this.dayField.validate();
30721 var m = this.monthField.validate();
30722 var y = this.yearField.validate();
30727 (!this.dayAllowBlank && !d) ||
30728 (!this.monthAllowBlank && !m) ||
30729 (!this.yearAllowBlank && !y)
30734 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30743 this.markInvalid();
30748 markValid : function()
30751 var label = this.el.select('label', true).first();
30752 var icon = this.el.select('i.fa-star', true).first();
30758 this.fireEvent('valid', this);
30762 * Mark this field as invalid
30763 * @param {String} msg The validation message
30765 markInvalid : function(msg)
30768 var label = this.el.select('label', true).first();
30769 var icon = this.el.select('i.fa-star', true).first();
30771 if(label && !icon){
30772 this.el.select('.roo-date-split-field-label', true).createChild({
30774 cls : 'text-danger fa fa-lg fa-star',
30775 tooltip : 'This field is required',
30776 style : 'margin-right:5px;'
30780 this.fireEvent('invalid', this, msg);
30783 clearInvalid : function()
30785 var label = this.el.select('label', true).first();
30786 var icon = this.el.select('i.fa-star', true).first();
30792 this.fireEvent('valid', this);
30795 getName: function()
30805 * http://masonry.desandro.com
30807 * The idea is to render all the bricks based on vertical width...
30809 * The original code extends 'outlayer' - we might need to use that....
30815 * @class Roo.bootstrap.LayoutMasonry
30816 * @extends Roo.bootstrap.Component
30817 * Bootstrap Layout Masonry class
30820 * Create a new Element
30821 * @param {Object} config The config object
30824 Roo.bootstrap.LayoutMasonry = function(config){
30826 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30830 Roo.bootstrap.LayoutMasonry.register(this);
30836 * Fire after layout the items
30837 * @param {Roo.bootstrap.LayoutMasonry} this
30838 * @param {Roo.EventObject} e
30845 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30848 * @cfg {Boolean} isLayoutInstant = no animation?
30850 isLayoutInstant : false, // needed?
30853 * @cfg {Number} boxWidth width of the columns
30858 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30863 * @cfg {Number} padWidth padding below box..
30868 * @cfg {Number} gutter gutter width..
30873 * @cfg {Number} maxCols maximum number of columns
30879 * @cfg {Boolean} isAutoInitial defalut true
30881 isAutoInitial : true,
30886 * @cfg {Boolean} isHorizontal defalut false
30888 isHorizontal : false,
30890 currentSize : null,
30896 bricks: null, //CompositeElement
30900 _isLayoutInited : false,
30902 // isAlternative : false, // only use for vertical layout...
30905 * @cfg {Number} alternativePadWidth padding below box..
30907 alternativePadWidth : 50,
30909 selectedBrick : [],
30911 getAutoCreate : function(){
30913 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30917 cls: 'blog-masonary-wrapper ' + this.cls,
30919 cls : 'mas-boxes masonary'
30926 getChildContainer: function( )
30928 if (this.boxesEl) {
30929 return this.boxesEl;
30932 this.boxesEl = this.el.select('.mas-boxes').first();
30934 return this.boxesEl;
30938 initEvents : function()
30942 if(this.isAutoInitial){
30943 Roo.log('hook children rendered');
30944 this.on('childrenrendered', function() {
30945 Roo.log('children rendered');
30951 initial : function()
30953 this.selectedBrick = [];
30955 this.currentSize = this.el.getBox(true);
30957 Roo.EventManager.onWindowResize(this.resize, this);
30959 if(!this.isAutoInitial){
30967 //this.layout.defer(500,this);
30971 resize : function()
30973 var cs = this.el.getBox(true);
30976 this.currentSize.width == cs.width &&
30977 this.currentSize.x == cs.x &&
30978 this.currentSize.height == cs.height &&
30979 this.currentSize.y == cs.y
30981 Roo.log("no change in with or X or Y");
30985 this.currentSize = cs;
30991 layout : function()
30993 this._resetLayout();
30995 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30997 this.layoutItems( isInstant );
30999 this._isLayoutInited = true;
31001 this.fireEvent('layout', this);
31005 _resetLayout : function()
31007 if(this.isHorizontal){
31008 this.horizontalMeasureColumns();
31012 this.verticalMeasureColumns();
31016 verticalMeasureColumns : function()
31018 this.getContainerWidth();
31020 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31021 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31025 var boxWidth = this.boxWidth + this.padWidth;
31027 if(this.containerWidth < this.boxWidth){
31028 boxWidth = this.containerWidth
31031 var containerWidth = this.containerWidth;
31033 var cols = Math.floor(containerWidth / boxWidth);
31035 this.cols = Math.max( cols, 1 );
31037 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31039 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31041 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31043 this.colWidth = boxWidth + avail - this.padWidth;
31045 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31046 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31049 horizontalMeasureColumns : function()
31051 this.getContainerWidth();
31053 var boxWidth = this.boxWidth;
31055 if(this.containerWidth < boxWidth){
31056 boxWidth = this.containerWidth;
31059 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31061 this.el.setHeight(boxWidth);
31065 getContainerWidth : function()
31067 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31070 layoutItems : function( isInstant )
31072 Roo.log(this.bricks);
31074 var items = Roo.apply([], this.bricks);
31076 if(this.isHorizontal){
31077 this._horizontalLayoutItems( items , isInstant );
31081 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31082 // this._verticalAlternativeLayoutItems( items , isInstant );
31086 this._verticalLayoutItems( items , isInstant );
31090 _verticalLayoutItems : function ( items , isInstant)
31092 if ( !items || !items.length ) {
31097 ['xs', 'xs', 'xs', 'tall'],
31098 ['xs', 'xs', 'tall'],
31099 ['xs', 'xs', 'sm'],
31100 ['xs', 'xs', 'xs'],
31106 ['sm', 'xs', 'xs'],
31110 ['tall', 'xs', 'xs', 'xs'],
31111 ['tall', 'xs', 'xs'],
31123 Roo.each(items, function(item, k){
31125 switch (item.size) {
31126 // these layouts take up a full box,
31137 boxes.push([item]);
31160 var filterPattern = function(box, length)
31168 var pattern = box.slice(0, length);
31172 Roo.each(pattern, function(i){
31173 format.push(i.size);
31176 Roo.each(standard, function(s){
31178 if(String(s) != String(format)){
31187 if(!match && length == 1){
31192 filterPattern(box, length - 1);
31196 queue.push(pattern);
31198 box = box.slice(length, box.length);
31200 filterPattern(box, 4);
31206 Roo.each(boxes, function(box, k){
31212 if(box.length == 1){
31217 filterPattern(box, 4);
31221 this._processVerticalLayoutQueue( queue, isInstant );
31225 // _verticalAlternativeLayoutItems : function( items , isInstant )
31227 // if ( !items || !items.length ) {
31231 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31235 _horizontalLayoutItems : function ( items , isInstant)
31237 if ( !items || !items.length || items.length < 3) {
31243 var eItems = items.slice(0, 3);
31245 items = items.slice(3, items.length);
31248 ['xs', 'xs', 'xs', 'wide'],
31249 ['xs', 'xs', 'wide'],
31250 ['xs', 'xs', 'sm'],
31251 ['xs', 'xs', 'xs'],
31257 ['sm', 'xs', 'xs'],
31261 ['wide', 'xs', 'xs', 'xs'],
31262 ['wide', 'xs', 'xs'],
31275 Roo.each(items, function(item, k){
31277 switch (item.size) {
31288 boxes.push([item]);
31312 var filterPattern = function(box, length)
31320 var pattern = box.slice(0, length);
31324 Roo.each(pattern, function(i){
31325 format.push(i.size);
31328 Roo.each(standard, function(s){
31330 if(String(s) != String(format)){
31339 if(!match && length == 1){
31344 filterPattern(box, length - 1);
31348 queue.push(pattern);
31350 box = box.slice(length, box.length);
31352 filterPattern(box, 4);
31358 Roo.each(boxes, function(box, k){
31364 if(box.length == 1){
31369 filterPattern(box, 4);
31376 var pos = this.el.getBox(true);
31380 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31382 var hit_end = false;
31384 Roo.each(queue, function(box){
31388 Roo.each(box, function(b){
31390 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31400 Roo.each(box, function(b){
31402 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31405 mx = Math.max(mx, b.x);
31409 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31413 Roo.each(box, function(b){
31415 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31429 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31432 /** Sets position of item in DOM
31433 * @param {Element} item
31434 * @param {Number} x - horizontal position
31435 * @param {Number} y - vertical position
31436 * @param {Boolean} isInstant - disables transitions
31438 _processVerticalLayoutQueue : function( queue, isInstant )
31440 var pos = this.el.getBox(true);
31445 for (var i = 0; i < this.cols; i++){
31449 Roo.each(queue, function(box, k){
31451 var col = k % this.cols;
31453 Roo.each(box, function(b,kk){
31455 b.el.position('absolute');
31457 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31458 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31460 if(b.size == 'md-left' || b.size == 'md-right'){
31461 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31462 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31465 b.el.setWidth(width);
31466 b.el.setHeight(height);
31468 b.el.select('iframe',true).setSize(width,height);
31472 for (var i = 0; i < this.cols; i++){
31474 if(maxY[i] < maxY[col]){
31479 col = Math.min(col, i);
31483 x = pos.x + col * (this.colWidth + this.padWidth);
31487 var positions = [];
31489 switch (box.length){
31491 positions = this.getVerticalOneBoxColPositions(x, y, box);
31494 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31497 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31500 positions = this.getVerticalFourBoxColPositions(x, y, box);
31506 Roo.each(box, function(b,kk){
31508 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31510 var sz = b.el.getSize();
31512 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31520 for (var i = 0; i < this.cols; i++){
31521 mY = Math.max(mY, maxY[i]);
31524 this.el.setHeight(mY - pos.y);
31528 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31530 // var pos = this.el.getBox(true);
31533 // var maxX = pos.right;
31535 // var maxHeight = 0;
31537 // Roo.each(items, function(item, k){
31541 // item.el.position('absolute');
31543 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31545 // item.el.setWidth(width);
31547 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31549 // item.el.setHeight(height);
31552 // item.el.setXY([x, y], isInstant ? false : true);
31554 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31557 // y = y + height + this.alternativePadWidth;
31559 // maxHeight = maxHeight + height + this.alternativePadWidth;
31563 // this.el.setHeight(maxHeight);
31567 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31569 var pos = this.el.getBox(true);
31574 var maxX = pos.right;
31576 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31578 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31580 Roo.each(queue, function(box, k){
31582 Roo.each(box, function(b, kk){
31584 b.el.position('absolute');
31586 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31587 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31589 if(b.size == 'md-left' || b.size == 'md-right'){
31590 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31591 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31594 b.el.setWidth(width);
31595 b.el.setHeight(height);
31603 var positions = [];
31605 switch (box.length){
31607 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31610 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31613 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31616 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31622 Roo.each(box, function(b,kk){
31624 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31626 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31634 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31636 Roo.each(eItems, function(b,k){
31638 b.size = (k == 0) ? 'sm' : 'xs';
31639 b.x = (k == 0) ? 2 : 1;
31640 b.y = (k == 0) ? 2 : 1;
31642 b.el.position('absolute');
31644 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31646 b.el.setWidth(width);
31648 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31650 b.el.setHeight(height);
31654 var positions = [];
31657 x : maxX - this.unitWidth * 2 - this.gutter,
31662 x : maxX - this.unitWidth,
31663 y : minY + (this.unitWidth + this.gutter) * 2
31667 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31671 Roo.each(eItems, function(b,k){
31673 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31679 getVerticalOneBoxColPositions : function(x, y, box)
31683 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31685 if(box[0].size == 'md-left'){
31689 if(box[0].size == 'md-right'){
31694 x : x + (this.unitWidth + this.gutter) * rand,
31701 getVerticalTwoBoxColPositions : function(x, y, box)
31705 if(box[0].size == 'xs'){
31709 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31713 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31727 x : x + (this.unitWidth + this.gutter) * 2,
31728 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31735 getVerticalThreeBoxColPositions : function(x, y, box)
31739 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31747 x : x + (this.unitWidth + this.gutter) * 1,
31752 x : x + (this.unitWidth + this.gutter) * 2,
31760 if(box[0].size == 'xs' && box[1].size == 'xs'){
31769 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31773 x : x + (this.unitWidth + this.gutter) * 1,
31787 x : x + (this.unitWidth + this.gutter) * 2,
31792 x : x + (this.unitWidth + this.gutter) * 2,
31793 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31800 getVerticalFourBoxColPositions : function(x, y, box)
31804 if(box[0].size == 'xs'){
31813 y : y + (this.unitHeight + this.gutter) * 1
31818 y : y + (this.unitHeight + this.gutter) * 2
31822 x : x + (this.unitWidth + this.gutter) * 1,
31836 x : x + (this.unitWidth + this.gutter) * 2,
31841 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31842 y : y + (this.unitHeight + this.gutter) * 1
31846 x : x + (this.unitWidth + this.gutter) * 2,
31847 y : y + (this.unitWidth + this.gutter) * 2
31854 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31858 if(box[0].size == 'md-left'){
31860 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31867 if(box[0].size == 'md-right'){
31869 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31870 y : minY + (this.unitWidth + this.gutter) * 1
31876 var rand = Math.floor(Math.random() * (4 - box[0].y));
31879 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31880 y : minY + (this.unitWidth + this.gutter) * rand
31887 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31891 if(box[0].size == 'xs'){
31894 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31899 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31900 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31908 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31913 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31914 y : minY + (this.unitWidth + this.gutter) * 2
31921 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31925 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31928 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31933 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31934 y : minY + (this.unitWidth + this.gutter) * 1
31938 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31939 y : minY + (this.unitWidth + this.gutter) * 2
31946 if(box[0].size == 'xs' && box[1].size == 'xs'){
31949 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31954 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31959 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31960 y : minY + (this.unitWidth + this.gutter) * 1
31968 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31973 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31974 y : minY + (this.unitWidth + this.gutter) * 2
31978 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31979 y : minY + (this.unitWidth + this.gutter) * 2
31986 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31990 if(box[0].size == 'xs'){
31993 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31998 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32003 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),
32008 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32009 y : minY + (this.unitWidth + this.gutter) * 1
32017 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32022 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32023 y : minY + (this.unitWidth + this.gutter) * 2
32027 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32028 y : minY + (this.unitWidth + this.gutter) * 2
32032 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),
32033 y : minY + (this.unitWidth + this.gutter) * 2
32041 * remove a Masonry Brick
32042 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32044 removeBrick : function(brick_id)
32050 for (var i = 0; i<this.bricks.length; i++) {
32051 if (this.bricks[i].id == brick_id) {
32052 this.bricks.splice(i,1);
32053 this.el.dom.removeChild(Roo.get(brick_id).dom);
32060 * adds a Masonry Brick
32061 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32063 addBrick : function(cfg)
32065 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32066 //this.register(cn);
32067 cn.parentId = this.id;
32068 cn.render(this.el);
32073 * register a Masonry Brick
32074 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32077 register : function(brick)
32079 this.bricks.push(brick);
32080 brick.masonryId = this.id;
32084 * clear all the Masonry Brick
32086 clearAll : function()
32089 //this.getChildContainer().dom.innerHTML = "";
32090 this.el.dom.innerHTML = '';
32093 getSelected : function()
32095 if (!this.selectedBrick) {
32099 return this.selectedBrick;
32103 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32107 * register a Masonry Layout
32108 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32111 register : function(layout)
32113 this.groups[layout.id] = layout;
32116 * fetch a Masonry Layout based on the masonry layout ID
32117 * @param {string} the masonry layout to add
32118 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32121 get: function(layout_id) {
32122 if (typeof(this.groups[layout_id]) == 'undefined') {
32125 return this.groups[layout_id] ;
32137 * http://masonry.desandro.com
32139 * The idea is to render all the bricks based on vertical width...
32141 * The original code extends 'outlayer' - we might need to use that....
32147 * @class Roo.bootstrap.LayoutMasonryAuto
32148 * @extends Roo.bootstrap.Component
32149 * Bootstrap Layout Masonry class
32152 * Create a new Element
32153 * @param {Object} config The config object
32156 Roo.bootstrap.LayoutMasonryAuto = function(config){
32157 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32160 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32163 * @cfg {Boolean} isFitWidth - resize the width..
32165 isFitWidth : false, // options..
32167 * @cfg {Boolean} isOriginLeft = left align?
32169 isOriginLeft : true,
32171 * @cfg {Boolean} isOriginTop = top align?
32173 isOriginTop : false,
32175 * @cfg {Boolean} isLayoutInstant = no animation?
32177 isLayoutInstant : false, // needed?
32179 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32181 isResizingContainer : true,
32183 * @cfg {Number} columnWidth width of the columns
32189 * @cfg {Number} maxCols maximum number of columns
32194 * @cfg {Number} padHeight padding below box..
32200 * @cfg {Boolean} isAutoInitial defalut true
32203 isAutoInitial : true,
32209 initialColumnWidth : 0,
32210 currentSize : null,
32212 colYs : null, // array.
32219 bricks: null, //CompositeElement
32220 cols : 0, // array?
32221 // element : null, // wrapped now this.el
32222 _isLayoutInited : null,
32225 getAutoCreate : function(){
32229 cls: 'blog-masonary-wrapper ' + this.cls,
32231 cls : 'mas-boxes masonary'
32238 getChildContainer: function( )
32240 if (this.boxesEl) {
32241 return this.boxesEl;
32244 this.boxesEl = this.el.select('.mas-boxes').first();
32246 return this.boxesEl;
32250 initEvents : function()
32254 if(this.isAutoInitial){
32255 Roo.log('hook children rendered');
32256 this.on('childrenrendered', function() {
32257 Roo.log('children rendered');
32264 initial : function()
32266 this.reloadItems();
32268 this.currentSize = this.el.getBox(true);
32270 /// was window resize... - let's see if this works..
32271 Roo.EventManager.onWindowResize(this.resize, this);
32273 if(!this.isAutoInitial){
32278 this.layout.defer(500,this);
32281 reloadItems: function()
32283 this.bricks = this.el.select('.masonry-brick', true);
32285 this.bricks.each(function(b) {
32286 //Roo.log(b.getSize());
32287 if (!b.attr('originalwidth')) {
32288 b.attr('originalwidth', b.getSize().width);
32293 Roo.log(this.bricks.elements.length);
32296 resize : function()
32299 var cs = this.el.getBox(true);
32301 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32302 Roo.log("no change in with or X");
32305 this.currentSize = cs;
32309 layout : function()
32312 this._resetLayout();
32313 //this._manageStamps();
32315 // don't animate first layout
32316 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32317 this.layoutItems( isInstant );
32319 // flag for initalized
32320 this._isLayoutInited = true;
32323 layoutItems : function( isInstant )
32325 //var items = this._getItemsForLayout( this.items );
32326 // original code supports filtering layout items.. we just ignore it..
32328 this._layoutItems( this.bricks , isInstant );
32330 this._postLayout();
32332 _layoutItems : function ( items , isInstant)
32334 //this.fireEvent( 'layout', this, items );
32337 if ( !items || !items.elements.length ) {
32338 // no items, emit event with empty array
32343 items.each(function(item) {
32344 Roo.log("layout item");
32346 // get x/y object from method
32347 var position = this._getItemLayoutPosition( item );
32349 position.item = item;
32350 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32351 queue.push( position );
32354 this._processLayoutQueue( queue );
32356 /** Sets position of item in DOM
32357 * @param {Element} item
32358 * @param {Number} x - horizontal position
32359 * @param {Number} y - vertical position
32360 * @param {Boolean} isInstant - disables transitions
32362 _processLayoutQueue : function( queue )
32364 for ( var i=0, len = queue.length; i < len; i++ ) {
32365 var obj = queue[i];
32366 obj.item.position('absolute');
32367 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32373 * Any logic you want to do after each layout,
32374 * i.e. size the container
32376 _postLayout : function()
32378 this.resizeContainer();
32381 resizeContainer : function()
32383 if ( !this.isResizingContainer ) {
32386 var size = this._getContainerSize();
32388 this.el.setSize(size.width,size.height);
32389 this.boxesEl.setSize(size.width,size.height);
32395 _resetLayout : function()
32397 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32398 this.colWidth = this.el.getWidth();
32399 //this.gutter = this.el.getWidth();
32401 this.measureColumns();
32407 this.colYs.push( 0 );
32413 measureColumns : function()
32415 this.getContainerWidth();
32416 // if columnWidth is 0, default to outerWidth of first item
32417 if ( !this.columnWidth ) {
32418 var firstItem = this.bricks.first();
32419 Roo.log(firstItem);
32420 this.columnWidth = this.containerWidth;
32421 if (firstItem && firstItem.attr('originalwidth') ) {
32422 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32424 // columnWidth fall back to item of first element
32425 Roo.log("set column width?");
32426 this.initialColumnWidth = this.columnWidth ;
32428 // if first elem has no width, default to size of container
32433 if (this.initialColumnWidth) {
32434 this.columnWidth = this.initialColumnWidth;
32439 // column width is fixed at the top - however if container width get's smaller we should
32442 // this bit calcs how man columns..
32444 var columnWidth = this.columnWidth += this.gutter;
32446 // calculate columns
32447 var containerWidth = this.containerWidth + this.gutter;
32449 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32450 // fix rounding errors, typically with gutters
32451 var excess = columnWidth - containerWidth % columnWidth;
32454 // if overshoot is less than a pixel, round up, otherwise floor it
32455 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32456 cols = Math[ mathMethod ]( cols );
32457 this.cols = Math.max( cols, 1 );
32458 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32460 // padding positioning..
32461 var totalColWidth = this.cols * this.columnWidth;
32462 var padavail = this.containerWidth - totalColWidth;
32463 // so for 2 columns - we need 3 'pads'
32465 var padNeeded = (1+this.cols) * this.padWidth;
32467 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32469 this.columnWidth += padExtra
32470 //this.padWidth = Math.floor(padavail / ( this.cols));
32472 // adjust colum width so that padding is fixed??
32474 // we have 3 columns ... total = width * 3
32475 // we have X left over... that should be used by
32477 //if (this.expandC) {
32485 getContainerWidth : function()
32487 /* // container is parent if fit width
32488 var container = this.isFitWidth ? this.element.parentNode : this.element;
32489 // check that this.size and size are there
32490 // IE8 triggers resize on body size change, so they might not be
32492 var size = getSize( container ); //FIXME
32493 this.containerWidth = size && size.innerWidth; //FIXME
32496 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32500 _getItemLayoutPosition : function( item ) // what is item?
32502 // we resize the item to our columnWidth..
32504 item.setWidth(this.columnWidth);
32505 item.autoBoxAdjust = false;
32507 var sz = item.getSize();
32509 // how many columns does this brick span
32510 var remainder = this.containerWidth % this.columnWidth;
32512 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32513 // round if off by 1 pixel, otherwise use ceil
32514 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32515 colSpan = Math.min( colSpan, this.cols );
32517 // normally this should be '1' as we dont' currently allow multi width columns..
32519 var colGroup = this._getColGroup( colSpan );
32520 // get the minimum Y value from the columns
32521 var minimumY = Math.min.apply( Math, colGroup );
32522 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32524 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32526 // position the brick
32528 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32529 y: this.currentSize.y + minimumY + this.padHeight
32533 // apply setHeight to necessary columns
32534 var setHeight = minimumY + sz.height + this.padHeight;
32535 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32537 var setSpan = this.cols + 1 - colGroup.length;
32538 for ( var i = 0; i < setSpan; i++ ) {
32539 this.colYs[ shortColIndex + i ] = setHeight ;
32546 * @param {Number} colSpan - number of columns the element spans
32547 * @returns {Array} colGroup
32549 _getColGroup : function( colSpan )
32551 if ( colSpan < 2 ) {
32552 // if brick spans only one column, use all the column Ys
32557 // how many different places could this brick fit horizontally
32558 var groupCount = this.cols + 1 - colSpan;
32559 // for each group potential horizontal position
32560 for ( var i = 0; i < groupCount; i++ ) {
32561 // make an array of colY values for that one group
32562 var groupColYs = this.colYs.slice( i, i + colSpan );
32563 // and get the max value of the array
32564 colGroup[i] = Math.max.apply( Math, groupColYs );
32569 _manageStamp : function( stamp )
32571 var stampSize = stamp.getSize();
32572 var offset = stamp.getBox();
32573 // get the columns that this stamp affects
32574 var firstX = this.isOriginLeft ? offset.x : offset.right;
32575 var lastX = firstX + stampSize.width;
32576 var firstCol = Math.floor( firstX / this.columnWidth );
32577 firstCol = Math.max( 0, firstCol );
32579 var lastCol = Math.floor( lastX / this.columnWidth );
32580 // lastCol should not go over if multiple of columnWidth #425
32581 lastCol -= lastX % this.columnWidth ? 0 : 1;
32582 lastCol = Math.min( this.cols - 1, lastCol );
32584 // set colYs to bottom of the stamp
32585 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32588 for ( var i = firstCol; i <= lastCol; i++ ) {
32589 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32594 _getContainerSize : function()
32596 this.maxY = Math.max.apply( Math, this.colYs );
32601 if ( this.isFitWidth ) {
32602 size.width = this._getContainerFitWidth();
32608 _getContainerFitWidth : function()
32610 var unusedCols = 0;
32611 // count unused columns
32614 if ( this.colYs[i] !== 0 ) {
32619 // fit container to columns that have been used
32620 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32623 needsResizeLayout : function()
32625 var previousWidth = this.containerWidth;
32626 this.getContainerWidth();
32627 return previousWidth !== this.containerWidth;
32642 * @class Roo.bootstrap.MasonryBrick
32643 * @extends Roo.bootstrap.Component
32644 * Bootstrap MasonryBrick class
32647 * Create a new MasonryBrick
32648 * @param {Object} config The config object
32651 Roo.bootstrap.MasonryBrick = function(config){
32653 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32655 Roo.bootstrap.MasonryBrick.register(this);
32661 * When a MasonryBrick is clcik
32662 * @param {Roo.bootstrap.MasonryBrick} this
32663 * @param {Roo.EventObject} e
32669 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32672 * @cfg {String} title
32676 * @cfg {String} html
32680 * @cfg {String} bgimage
32684 * @cfg {String} videourl
32688 * @cfg {String} cls
32692 * @cfg {String} href
32696 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32701 * @cfg {String} placetitle (center|bottom)
32706 * @cfg {Boolean} isFitContainer defalut true
32708 isFitContainer : true,
32711 * @cfg {Boolean} preventDefault defalut false
32713 preventDefault : false,
32716 * @cfg {Boolean} inverse defalut false
32718 maskInverse : false,
32720 getAutoCreate : function()
32722 if(!this.isFitContainer){
32723 return this.getSplitAutoCreate();
32726 var cls = 'masonry-brick masonry-brick-full';
32728 if(this.href.length){
32729 cls += ' masonry-brick-link';
32732 if(this.bgimage.length){
32733 cls += ' masonry-brick-image';
32736 if(this.maskInverse){
32737 cls += ' mask-inverse';
32740 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32741 cls += ' enable-mask';
32745 cls += ' masonry-' + this.size + '-brick';
32748 if(this.placetitle.length){
32750 switch (this.placetitle) {
32752 cls += ' masonry-center-title';
32755 cls += ' masonry-bottom-title';
32762 if(!this.html.length && !this.bgimage.length){
32763 cls += ' masonry-center-title';
32766 if(!this.html.length && this.bgimage.length){
32767 cls += ' masonry-bottom-title';
32772 cls += ' ' + this.cls;
32776 tag: (this.href.length) ? 'a' : 'div',
32781 cls: 'masonry-brick-mask'
32785 cls: 'masonry-brick-paragraph',
32791 if(this.href.length){
32792 cfg.href = this.href;
32795 var cn = cfg.cn[1].cn;
32797 if(this.title.length){
32800 cls: 'masonry-brick-title',
32805 if(this.html.length){
32808 cls: 'masonry-brick-text',
32813 if (!this.title.length && !this.html.length) {
32814 cfg.cn[1].cls += ' hide';
32817 if(this.bgimage.length){
32820 cls: 'masonry-brick-image-view',
32825 if(this.videourl.length){
32826 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32827 // youtube support only?
32830 cls: 'masonry-brick-image-view',
32833 allowfullscreen : true
32841 getSplitAutoCreate : function()
32843 var cls = 'masonry-brick masonry-brick-split';
32845 if(this.href.length){
32846 cls += ' masonry-brick-link';
32849 if(this.bgimage.length){
32850 cls += ' masonry-brick-image';
32854 cls += ' masonry-' + this.size + '-brick';
32857 switch (this.placetitle) {
32859 cls += ' masonry-center-title';
32862 cls += ' masonry-bottom-title';
32865 if(!this.bgimage.length){
32866 cls += ' masonry-center-title';
32869 if(this.bgimage.length){
32870 cls += ' masonry-bottom-title';
32876 cls += ' ' + this.cls;
32880 tag: (this.href.length) ? 'a' : 'div',
32885 cls: 'masonry-brick-split-head',
32889 cls: 'masonry-brick-paragraph',
32896 cls: 'masonry-brick-split-body',
32902 if(this.href.length){
32903 cfg.href = this.href;
32906 if(this.title.length){
32907 cfg.cn[0].cn[0].cn.push({
32909 cls: 'masonry-brick-title',
32914 if(this.html.length){
32915 cfg.cn[1].cn.push({
32917 cls: 'masonry-brick-text',
32922 if(this.bgimage.length){
32923 cfg.cn[0].cn.push({
32925 cls: 'masonry-brick-image-view',
32930 if(this.videourl.length){
32931 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32932 // youtube support only?
32933 cfg.cn[0].cn.cn.push({
32935 cls: 'masonry-brick-image-view',
32938 allowfullscreen : true
32945 initEvents: function()
32947 switch (this.size) {
32980 this.el.on('touchstart', this.onTouchStart, this);
32981 this.el.on('touchmove', this.onTouchMove, this);
32982 this.el.on('touchend', this.onTouchEnd, this);
32983 this.el.on('contextmenu', this.onContextMenu, this);
32985 this.el.on('mouseenter' ,this.enter, this);
32986 this.el.on('mouseleave', this.leave, this);
32987 this.el.on('click', this.onClick, this);
32990 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32991 this.parent().bricks.push(this);
32996 onClick: function(e, el)
32998 var time = this.endTimer - this.startTimer;
32999 // Roo.log(e.preventDefault());
33002 e.preventDefault();
33007 if(!this.preventDefault){
33011 e.preventDefault();
33013 if (this.activeClass != '') {
33014 this.selectBrick();
33017 this.fireEvent('click', this, e);
33020 enter: function(e, el)
33022 e.preventDefault();
33024 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33028 if(this.bgimage.length && this.html.length){
33029 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33033 leave: function(e, el)
33035 e.preventDefault();
33037 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33041 if(this.bgimage.length && this.html.length){
33042 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33046 onTouchStart: function(e, el)
33048 // e.preventDefault();
33050 this.touchmoved = false;
33052 if(!this.isFitContainer){
33056 if(!this.bgimage.length || !this.html.length){
33060 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33062 this.timer = new Date().getTime();
33066 onTouchMove: function(e, el)
33068 this.touchmoved = true;
33071 onContextMenu : function(e,el)
33073 e.preventDefault();
33074 e.stopPropagation();
33078 onTouchEnd: function(e, el)
33080 // e.preventDefault();
33082 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33089 if(!this.bgimage.length || !this.html.length){
33091 if(this.href.length){
33092 window.location.href = this.href;
33098 if(!this.isFitContainer){
33102 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33104 window.location.href = this.href;
33107 //selection on single brick only
33108 selectBrick : function() {
33110 if (!this.parentId) {
33114 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33115 var index = m.selectedBrick.indexOf(this.id);
33118 m.selectedBrick.splice(index,1);
33119 this.el.removeClass(this.activeClass);
33123 for(var i = 0; i < m.selectedBrick.length; i++) {
33124 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33125 b.el.removeClass(b.activeClass);
33128 m.selectedBrick = [];
33130 m.selectedBrick.push(this.id);
33131 this.el.addClass(this.activeClass);
33135 isSelected : function(){
33136 return this.el.hasClass(this.activeClass);
33141 Roo.apply(Roo.bootstrap.MasonryBrick, {
33144 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33146 * register a Masonry Brick
33147 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33150 register : function(brick)
33152 //this.groups[brick.id] = brick;
33153 this.groups.add(brick.id, brick);
33156 * fetch a masonry brick based on the masonry brick ID
33157 * @param {string} the masonry brick to add
33158 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33161 get: function(brick_id)
33163 // if (typeof(this.groups[brick_id]) == 'undefined') {
33166 // return this.groups[brick_id] ;
33168 if(this.groups.key(brick_id)) {
33169 return this.groups.key(brick_id);
33187 * @class Roo.bootstrap.Brick
33188 * @extends Roo.bootstrap.Component
33189 * Bootstrap Brick class
33192 * Create a new Brick
33193 * @param {Object} config The config object
33196 Roo.bootstrap.Brick = function(config){
33197 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33203 * When a Brick is click
33204 * @param {Roo.bootstrap.Brick} this
33205 * @param {Roo.EventObject} e
33211 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33214 * @cfg {String} title
33218 * @cfg {String} html
33222 * @cfg {String} bgimage
33226 * @cfg {String} cls
33230 * @cfg {String} href
33234 * @cfg {String} video
33238 * @cfg {Boolean} square
33242 getAutoCreate : function()
33244 var cls = 'roo-brick';
33246 if(this.href.length){
33247 cls += ' roo-brick-link';
33250 if(this.bgimage.length){
33251 cls += ' roo-brick-image';
33254 if(!this.html.length && !this.bgimage.length){
33255 cls += ' roo-brick-center-title';
33258 if(!this.html.length && this.bgimage.length){
33259 cls += ' roo-brick-bottom-title';
33263 cls += ' ' + this.cls;
33267 tag: (this.href.length) ? 'a' : 'div',
33272 cls: 'roo-brick-paragraph',
33278 if(this.href.length){
33279 cfg.href = this.href;
33282 var cn = cfg.cn[0].cn;
33284 if(this.title.length){
33287 cls: 'roo-brick-title',
33292 if(this.html.length){
33295 cls: 'roo-brick-text',
33302 if(this.bgimage.length){
33305 cls: 'roo-brick-image-view',
33313 initEvents: function()
33315 if(this.title.length || this.html.length){
33316 this.el.on('mouseenter' ,this.enter, this);
33317 this.el.on('mouseleave', this.leave, this);
33320 Roo.EventManager.onWindowResize(this.resize, this);
33322 if(this.bgimage.length){
33323 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33324 this.imageEl.on('load', this.onImageLoad, this);
33331 onImageLoad : function()
33336 resize : function()
33338 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33340 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33342 if(this.bgimage.length){
33343 var image = this.el.select('.roo-brick-image-view', true).first();
33345 image.setWidth(paragraph.getWidth());
33348 image.setHeight(paragraph.getWidth());
33351 this.el.setHeight(image.getHeight());
33352 paragraph.setHeight(image.getHeight());
33358 enter: function(e, el)
33360 e.preventDefault();
33362 if(this.bgimage.length){
33363 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33364 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33368 leave: function(e, el)
33370 e.preventDefault();
33372 if(this.bgimage.length){
33373 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33374 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33389 * @class Roo.bootstrap.NumberField
33390 * @extends Roo.bootstrap.Input
33391 * Bootstrap NumberField class
33397 * Create a new NumberField
33398 * @param {Object} config The config object
33401 Roo.bootstrap.NumberField = function(config){
33402 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33405 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33408 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33410 allowDecimals : true,
33412 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33414 decimalSeparator : ".",
33416 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33418 decimalPrecision : 2,
33420 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33422 allowNegative : true,
33425 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33429 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33431 minValue : Number.NEGATIVE_INFINITY,
33433 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33435 maxValue : Number.MAX_VALUE,
33437 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33439 minText : "The minimum value for this field is {0}",
33441 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33443 maxText : "The maximum value for this field is {0}",
33445 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33446 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33448 nanText : "{0} is not a valid number",
33450 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33452 thousandsDelimiter : false,
33454 * @cfg {String} valueAlign alignment of value
33456 valueAlign : "left",
33458 getAutoCreate : function()
33460 var hiddenInput = {
33464 cls: 'hidden-number-input'
33468 hiddenInput.name = this.name;
33473 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33475 this.name = hiddenInput.name;
33477 if(cfg.cn.length > 0) {
33478 cfg.cn.push(hiddenInput);
33485 initEvents : function()
33487 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33489 var allowed = "0123456789";
33491 if(this.allowDecimals){
33492 allowed += this.decimalSeparator;
33495 if(this.allowNegative){
33499 if(this.thousandsDelimiter) {
33503 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33505 var keyPress = function(e){
33507 var k = e.getKey();
33509 var c = e.getCharCode();
33512 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33513 allowed.indexOf(String.fromCharCode(c)) === -1
33519 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33523 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33528 this.el.on("keypress", keyPress, this);
33531 validateValue : function(value)
33534 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33538 var num = this.parseValue(value);
33541 this.markInvalid(String.format(this.nanText, value));
33545 if(num < this.minValue){
33546 this.markInvalid(String.format(this.minText, this.minValue));
33550 if(num > this.maxValue){
33551 this.markInvalid(String.format(this.maxText, this.maxValue));
33558 getValue : function()
33560 var v = this.hiddenEl().getValue();
33562 return this.fixPrecision(this.parseValue(v));
33565 parseValue : function(value)
33567 if(this.thousandsDelimiter) {
33569 r = new RegExp(",", "g");
33570 value = value.replace(r, "");
33573 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33574 return isNaN(value) ? '' : value;
33577 fixPrecision : function(value)
33579 if(this.thousandsDelimiter) {
33581 r = new RegExp(",", "g");
33582 value = value.replace(r, "");
33585 var nan = isNaN(value);
33587 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33588 return nan ? '' : value;
33590 return parseFloat(value).toFixed(this.decimalPrecision);
33593 setValue : function(v)
33595 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33601 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33603 this.inputEl().dom.value = (v == '') ? '' :
33604 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33606 if(!this.allowZero && v === '0') {
33607 this.hiddenEl().dom.value = '';
33608 this.inputEl().dom.value = '';
33615 decimalPrecisionFcn : function(v)
33617 return Math.floor(v);
33620 beforeBlur : function()
33622 var v = this.parseValue(this.getRawValue());
33624 if(v || v === 0 || v === ''){
33629 hiddenEl : function()
33631 return this.el.select('input.hidden-number-input',true).first();
33643 * @class Roo.bootstrap.DocumentSlider
33644 * @extends Roo.bootstrap.Component
33645 * Bootstrap DocumentSlider class
33648 * Create a new DocumentViewer
33649 * @param {Object} config The config object
33652 Roo.bootstrap.DocumentSlider = function(config){
33653 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33660 * Fire after initEvent
33661 * @param {Roo.bootstrap.DocumentSlider} this
33666 * Fire after update
33667 * @param {Roo.bootstrap.DocumentSlider} this
33673 * @param {Roo.bootstrap.DocumentSlider} this
33679 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33685 getAutoCreate : function()
33689 cls : 'roo-document-slider',
33693 cls : 'roo-document-slider-header',
33697 cls : 'roo-document-slider-header-title'
33703 cls : 'roo-document-slider-body',
33707 cls : 'roo-document-slider-prev',
33711 cls : 'fa fa-chevron-left'
33717 cls : 'roo-document-slider-thumb',
33721 cls : 'roo-document-slider-image'
33727 cls : 'roo-document-slider-next',
33731 cls : 'fa fa-chevron-right'
33743 initEvents : function()
33745 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33746 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33748 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33749 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33751 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33752 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33754 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33755 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33757 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33758 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33760 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33761 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33763 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33764 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33766 this.thumbEl.on('click', this.onClick, this);
33768 this.prevIndicator.on('click', this.prev, this);
33770 this.nextIndicator.on('click', this.next, this);
33774 initial : function()
33776 if(this.files.length){
33777 this.indicator = 1;
33781 this.fireEvent('initial', this);
33784 update : function()
33786 this.imageEl.attr('src', this.files[this.indicator - 1]);
33788 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33790 this.prevIndicator.show();
33792 if(this.indicator == 1){
33793 this.prevIndicator.hide();
33796 this.nextIndicator.show();
33798 if(this.indicator == this.files.length){
33799 this.nextIndicator.hide();
33802 this.thumbEl.scrollTo('top');
33804 this.fireEvent('update', this);
33807 onClick : function(e)
33809 e.preventDefault();
33811 this.fireEvent('click', this);
33816 e.preventDefault();
33818 this.indicator = Math.max(1, this.indicator - 1);
33825 e.preventDefault();
33827 this.indicator = Math.min(this.files.length, this.indicator + 1);
33841 * @class Roo.bootstrap.RadioSet
33842 * @extends Roo.bootstrap.Input
33843 * Bootstrap RadioSet class
33844 * @cfg {String} indicatorpos (left|right) default left
33845 * @cfg {Boolean} inline (true|false) inline the element (default true)
33846 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33848 * Create a new RadioSet
33849 * @param {Object} config The config object
33852 Roo.bootstrap.RadioSet = function(config){
33854 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33858 Roo.bootstrap.RadioSet.register(this);
33863 * Fires when the element is checked or unchecked.
33864 * @param {Roo.bootstrap.RadioSet} this This radio
33865 * @param {Roo.bootstrap.Radio} item The checked item
33870 * Fires when the element is click.
33871 * @param {Roo.bootstrap.RadioSet} this This radio set
33872 * @param {Roo.bootstrap.Radio} item The checked item
33873 * @param {Roo.EventObject} e The event object
33880 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33888 indicatorpos : 'left',
33890 getAutoCreate : function()
33894 cls : 'roo-radio-set-label',
33898 html : this.fieldLabel
33903 if(this.indicatorpos == 'left'){
33906 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33907 tooltip : 'This field is required'
33912 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33913 tooltip : 'This field is required'
33919 cls : 'roo-radio-set-items'
33922 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33924 if (align === 'left' && this.fieldLabel.length) {
33927 cls : "roo-radio-set-right",
33933 if(this.labelWidth > 12){
33934 label.style = "width: " + this.labelWidth + 'px';
33937 if(this.labelWidth < 13 && this.labelmd == 0){
33938 this.labelmd = this.labelWidth;
33941 if(this.labellg > 0){
33942 label.cls += ' col-lg-' + this.labellg;
33943 items.cls += ' col-lg-' + (12 - this.labellg);
33946 if(this.labelmd > 0){
33947 label.cls += ' col-md-' + this.labelmd;
33948 items.cls += ' col-md-' + (12 - this.labelmd);
33951 if(this.labelsm > 0){
33952 label.cls += ' col-sm-' + this.labelsm;
33953 items.cls += ' col-sm-' + (12 - this.labelsm);
33956 if(this.labelxs > 0){
33957 label.cls += ' col-xs-' + this.labelxs;
33958 items.cls += ' col-xs-' + (12 - this.labelxs);
33964 cls : 'roo-radio-set',
33968 cls : 'roo-radio-set-input',
33971 value : this.value ? this.value : ''
33978 if(this.weight.length){
33979 cfg.cls += ' roo-radio-' + this.weight;
33983 cfg.cls += ' roo-radio-set-inline';
33987 ['xs','sm','md','lg'].map(function(size){
33988 if (settings[size]) {
33989 cfg.cls += ' col-' + size + '-' + settings[size];
33997 initEvents : function()
33999 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34000 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34002 if(!this.fieldLabel.length){
34003 this.labelEl.hide();
34006 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34007 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34009 this.indicator = this.indicatorEl();
34011 if(this.indicator){
34012 this.indicator.addClass('invisible');
34015 this.originalValue = this.getValue();
34019 inputEl: function ()
34021 return this.el.select('.roo-radio-set-input', true).first();
34024 getChildContainer : function()
34026 return this.itemsEl;
34029 register : function(item)
34031 this.radioes.push(item);
34035 validate : function()
34037 if(this.getVisibilityEl().hasClass('hidden')){
34043 Roo.each(this.radioes, function(i){
34052 if(this.allowBlank) {
34056 if(this.disabled || valid){
34061 this.markInvalid();
34066 markValid : function()
34068 if(this.labelEl.isVisible(true)){
34069 this.indicatorEl().removeClass('visible');
34070 this.indicatorEl().addClass('invisible');
34073 this.el.removeClass([this.invalidClass, this.validClass]);
34074 this.el.addClass(this.validClass);
34076 this.fireEvent('valid', this);
34079 markInvalid : function(msg)
34081 if(this.allowBlank || this.disabled){
34085 if(this.labelEl.isVisible(true)){
34086 this.indicatorEl().removeClass('invisible');
34087 this.indicatorEl().addClass('visible');
34090 this.el.removeClass([this.invalidClass, this.validClass]);
34091 this.el.addClass(this.invalidClass);
34093 this.fireEvent('invalid', this, msg);
34097 setValue : function(v, suppressEvent)
34099 if(this.value === v){
34106 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34109 Roo.each(this.radioes, function(i){
34111 i.el.removeClass('checked');
34114 Roo.each(this.radioes, function(i){
34116 if(i.value === v || i.value.toString() === v.toString()){
34118 i.el.addClass('checked');
34120 if(suppressEvent !== true){
34121 this.fireEvent('check', this, i);
34132 clearInvalid : function(){
34134 if(!this.el || this.preventMark){
34138 this.el.removeClass([this.invalidClass]);
34140 this.fireEvent('valid', this);
34145 Roo.apply(Roo.bootstrap.RadioSet, {
34149 register : function(set)
34151 this.groups[set.name] = set;
34154 get: function(name)
34156 if (typeof(this.groups[name]) == 'undefined') {
34160 return this.groups[name] ;
34166 * Ext JS Library 1.1.1
34167 * Copyright(c) 2006-2007, Ext JS, LLC.
34169 * Originally Released Under LGPL - original licence link has changed is not relivant.
34172 * <script type="text/javascript">
34177 * @class Roo.bootstrap.SplitBar
34178 * @extends Roo.util.Observable
34179 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34183 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34184 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34185 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34186 split.minSize = 100;
34187 split.maxSize = 600;
34188 split.animate = true;
34189 split.on('moved', splitterMoved);
34192 * Create a new SplitBar
34193 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34194 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34195 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34196 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34197 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34198 position of the SplitBar).
34200 Roo.bootstrap.SplitBar = function(cfg){
34205 // dragElement : elm
34206 // resizingElement: el,
34208 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34209 // placement : Roo.bootstrap.SplitBar.LEFT ,
34210 // existingProxy ???
34213 this.el = Roo.get(cfg.dragElement, true);
34214 this.el.dom.unselectable = "on";
34216 this.resizingEl = Roo.get(cfg.resizingElement, true);
34220 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34221 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34224 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34227 * The minimum size of the resizing element. (Defaults to 0)
34233 * The maximum size of the resizing element. (Defaults to 2000)
34236 this.maxSize = 2000;
34239 * Whether to animate the transition to the new size
34242 this.animate = false;
34245 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34248 this.useShim = false;
34253 if(!cfg.existingProxy){
34255 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34257 this.proxy = Roo.get(cfg.existingProxy).dom;
34260 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34263 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34266 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34269 this.dragSpecs = {};
34272 * @private The adapter to use to positon and resize elements
34274 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34275 this.adapter.init(this);
34277 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34279 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34280 this.el.addClass("roo-splitbar-h");
34283 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34284 this.el.addClass("roo-splitbar-v");
34290 * Fires when the splitter is moved (alias for {@link #event-moved})
34291 * @param {Roo.bootstrap.SplitBar} this
34292 * @param {Number} newSize the new width or height
34297 * Fires when the splitter is moved
34298 * @param {Roo.bootstrap.SplitBar} this
34299 * @param {Number} newSize the new width or height
34303 * @event beforeresize
34304 * Fires before the splitter is dragged
34305 * @param {Roo.bootstrap.SplitBar} this
34307 "beforeresize" : true,
34309 "beforeapply" : true
34312 Roo.util.Observable.call(this);
34315 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34316 onStartProxyDrag : function(x, y){
34317 this.fireEvent("beforeresize", this);
34319 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34321 o.enableDisplayMode("block");
34322 // all splitbars share the same overlay
34323 Roo.bootstrap.SplitBar.prototype.overlay = o;
34325 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34326 this.overlay.show();
34327 Roo.get(this.proxy).setDisplayed("block");
34328 var size = this.adapter.getElementSize(this);
34329 this.activeMinSize = this.getMinimumSize();;
34330 this.activeMaxSize = this.getMaximumSize();;
34331 var c1 = size - this.activeMinSize;
34332 var c2 = Math.max(this.activeMaxSize - size, 0);
34333 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34334 this.dd.resetConstraints();
34335 this.dd.setXConstraint(
34336 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34337 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34339 this.dd.setYConstraint(0, 0);
34341 this.dd.resetConstraints();
34342 this.dd.setXConstraint(0, 0);
34343 this.dd.setYConstraint(
34344 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34345 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34348 this.dragSpecs.startSize = size;
34349 this.dragSpecs.startPoint = [x, y];
34350 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34354 * @private Called after the drag operation by the DDProxy
34356 onEndProxyDrag : function(e){
34357 Roo.get(this.proxy).setDisplayed(false);
34358 var endPoint = Roo.lib.Event.getXY(e);
34360 this.overlay.hide();
34363 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34364 newSize = this.dragSpecs.startSize +
34365 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34366 endPoint[0] - this.dragSpecs.startPoint[0] :
34367 this.dragSpecs.startPoint[0] - endPoint[0]
34370 newSize = this.dragSpecs.startSize +
34371 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34372 endPoint[1] - this.dragSpecs.startPoint[1] :
34373 this.dragSpecs.startPoint[1] - endPoint[1]
34376 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34377 if(newSize != this.dragSpecs.startSize){
34378 if(this.fireEvent('beforeapply', this, newSize) !== false){
34379 this.adapter.setElementSize(this, newSize);
34380 this.fireEvent("moved", this, newSize);
34381 this.fireEvent("resize", this, newSize);
34387 * Get the adapter this SplitBar uses
34388 * @return The adapter object
34390 getAdapter : function(){
34391 return this.adapter;
34395 * Set the adapter this SplitBar uses
34396 * @param {Object} adapter A SplitBar adapter object
34398 setAdapter : function(adapter){
34399 this.adapter = adapter;
34400 this.adapter.init(this);
34404 * Gets the minimum size for the resizing element
34405 * @return {Number} The minimum size
34407 getMinimumSize : function(){
34408 return this.minSize;
34412 * Sets the minimum size for the resizing element
34413 * @param {Number} minSize The minimum size
34415 setMinimumSize : function(minSize){
34416 this.minSize = minSize;
34420 * Gets the maximum size for the resizing element
34421 * @return {Number} The maximum size
34423 getMaximumSize : function(){
34424 return this.maxSize;
34428 * Sets the maximum size for the resizing element
34429 * @param {Number} maxSize The maximum size
34431 setMaximumSize : function(maxSize){
34432 this.maxSize = maxSize;
34436 * Sets the initialize size for the resizing element
34437 * @param {Number} size The initial size
34439 setCurrentSize : function(size){
34440 var oldAnimate = this.animate;
34441 this.animate = false;
34442 this.adapter.setElementSize(this, size);
34443 this.animate = oldAnimate;
34447 * Destroy this splitbar.
34448 * @param {Boolean} removeEl True to remove the element
34450 destroy : function(removeEl){
34452 this.shim.remove();
34455 this.proxy.parentNode.removeChild(this.proxy);
34463 * @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.
34465 Roo.bootstrap.SplitBar.createProxy = function(dir){
34466 var proxy = new Roo.Element(document.createElement("div"));
34467 proxy.unselectable();
34468 var cls = 'roo-splitbar-proxy';
34469 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34470 document.body.appendChild(proxy.dom);
34475 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34476 * Default Adapter. It assumes the splitter and resizing element are not positioned
34477 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34479 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34482 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34483 // do nothing for now
34484 init : function(s){
34488 * Called before drag operations to get the current size of the resizing element.
34489 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34491 getElementSize : function(s){
34492 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34493 return s.resizingEl.getWidth();
34495 return s.resizingEl.getHeight();
34500 * Called after drag operations to set the size of the resizing element.
34501 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34502 * @param {Number} newSize The new size to set
34503 * @param {Function} onComplete A function to be invoked when resizing is complete
34505 setElementSize : function(s, newSize, onComplete){
34506 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34508 s.resizingEl.setWidth(newSize);
34510 onComplete(s, newSize);
34513 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34518 s.resizingEl.setHeight(newSize);
34520 onComplete(s, newSize);
34523 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34530 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34531 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34532 * Adapter that moves the splitter element to align with the resized sizing element.
34533 * Used with an absolute positioned SplitBar.
34534 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34535 * document.body, make sure you assign an id to the body element.
34537 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34538 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34539 this.container = Roo.get(container);
34542 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34543 init : function(s){
34544 this.basic.init(s);
34547 getElementSize : function(s){
34548 return this.basic.getElementSize(s);
34551 setElementSize : function(s, newSize, onComplete){
34552 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34555 moveSplitter : function(s){
34556 var yes = Roo.bootstrap.SplitBar;
34557 switch(s.placement){
34559 s.el.setX(s.resizingEl.getRight());
34562 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34565 s.el.setY(s.resizingEl.getBottom());
34568 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34575 * Orientation constant - Create a vertical SplitBar
34579 Roo.bootstrap.SplitBar.VERTICAL = 1;
34582 * Orientation constant - Create a horizontal SplitBar
34586 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34589 * Placement constant - The resizing element is to the left of the splitter element
34593 Roo.bootstrap.SplitBar.LEFT = 1;
34596 * Placement constant - The resizing element is to the right of the splitter element
34600 Roo.bootstrap.SplitBar.RIGHT = 2;
34603 * Placement constant - The resizing element is positioned above the splitter element
34607 Roo.bootstrap.SplitBar.TOP = 3;
34610 * Placement constant - The resizing element is positioned under splitter element
34614 Roo.bootstrap.SplitBar.BOTTOM = 4;
34615 Roo.namespace("Roo.bootstrap.layout");/*
34617 * Ext JS Library 1.1.1
34618 * Copyright(c) 2006-2007, Ext JS, LLC.
34620 * Originally Released Under LGPL - original licence link has changed is not relivant.
34623 * <script type="text/javascript">
34627 * @class Roo.bootstrap.layout.Manager
34628 * @extends Roo.bootstrap.Component
34629 * Base class for layout managers.
34631 Roo.bootstrap.layout.Manager = function(config)
34633 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34639 /** false to disable window resize monitoring @type Boolean */
34640 this.monitorWindowResize = true;
34645 * Fires when a layout is performed.
34646 * @param {Roo.LayoutManager} this
34650 * @event regionresized
34651 * Fires when the user resizes a region.
34652 * @param {Roo.LayoutRegion} region The resized region
34653 * @param {Number} newSize The new size (width for east/west, height for north/south)
34655 "regionresized" : true,
34657 * @event regioncollapsed
34658 * Fires when a region is collapsed.
34659 * @param {Roo.LayoutRegion} region The collapsed region
34661 "regioncollapsed" : true,
34663 * @event regionexpanded
34664 * Fires when a region is expanded.
34665 * @param {Roo.LayoutRegion} region The expanded region
34667 "regionexpanded" : true
34669 this.updating = false;
34672 this.el = Roo.get(config.el);
34678 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34683 monitorWindowResize : true,
34689 onRender : function(ct, position)
34692 this.el = Roo.get(ct);
34695 //this.fireEvent('render',this);
34699 initEvents: function()
34703 // ie scrollbar fix
34704 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34705 document.body.scroll = "no";
34706 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34707 this.el.position('relative');
34709 this.id = this.el.id;
34710 this.el.addClass("roo-layout-container");
34711 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34712 if(this.el.dom != document.body ) {
34713 this.el.on('resize', this.layout,this);
34714 this.el.on('show', this.layout,this);
34720 * Returns true if this layout is currently being updated
34721 * @return {Boolean}
34723 isUpdating : function(){
34724 return this.updating;
34728 * Suspend the LayoutManager from doing auto-layouts while
34729 * making multiple add or remove calls
34731 beginUpdate : function(){
34732 this.updating = true;
34736 * Restore auto-layouts and optionally disable the manager from performing a layout
34737 * @param {Boolean} noLayout true to disable a layout update
34739 endUpdate : function(noLayout){
34740 this.updating = false;
34746 layout: function(){
34750 onRegionResized : function(region, newSize){
34751 this.fireEvent("regionresized", region, newSize);
34755 onRegionCollapsed : function(region){
34756 this.fireEvent("regioncollapsed", region);
34759 onRegionExpanded : function(region){
34760 this.fireEvent("regionexpanded", region);
34764 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34765 * performs box-model adjustments.
34766 * @return {Object} The size as an object {width: (the width), height: (the height)}
34768 getViewSize : function()
34771 if(this.el.dom != document.body){
34772 size = this.el.getSize();
34774 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34776 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34777 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34782 * Returns the Element this layout is bound to.
34783 * @return {Roo.Element}
34785 getEl : function(){
34790 * Returns the specified region.
34791 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34792 * @return {Roo.LayoutRegion}
34794 getRegion : function(target){
34795 return this.regions[target.toLowerCase()];
34798 onWindowResize : function(){
34799 if(this.monitorWindowResize){
34806 * Ext JS Library 1.1.1
34807 * Copyright(c) 2006-2007, Ext JS, LLC.
34809 * Originally Released Under LGPL - original licence link has changed is not relivant.
34812 * <script type="text/javascript">
34815 * @class Roo.bootstrap.layout.Border
34816 * @extends Roo.bootstrap.layout.Manager
34817 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34818 * please see: examples/bootstrap/nested.html<br><br>
34820 <b>The container the layout is rendered into can be either the body element or any other element.
34821 If it is not the body element, the container needs to either be an absolute positioned element,
34822 or you will need to add "position:relative" to the css of the container. You will also need to specify
34823 the container size if it is not the body element.</b>
34826 * Create a new Border
34827 * @param {Object} config Configuration options
34829 Roo.bootstrap.layout.Border = function(config){
34830 config = config || {};
34831 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34835 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34836 if(config[region]){
34837 config[region].region = region;
34838 this.addRegion(config[region]);
34844 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34846 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34848 * Creates and adds a new region if it doesn't already exist.
34849 * @param {String} target The target region key (north, south, east, west or center).
34850 * @param {Object} config The regions config object
34851 * @return {BorderLayoutRegion} The new region
34853 addRegion : function(config)
34855 if(!this.regions[config.region]){
34856 var r = this.factory(config);
34857 this.bindRegion(r);
34859 return this.regions[config.region];
34863 bindRegion : function(r){
34864 this.regions[r.config.region] = r;
34866 r.on("visibilitychange", this.layout, this);
34867 r.on("paneladded", this.layout, this);
34868 r.on("panelremoved", this.layout, this);
34869 r.on("invalidated", this.layout, this);
34870 r.on("resized", this.onRegionResized, this);
34871 r.on("collapsed", this.onRegionCollapsed, this);
34872 r.on("expanded", this.onRegionExpanded, this);
34876 * Performs a layout update.
34878 layout : function()
34880 if(this.updating) {
34884 // render all the rebions if they have not been done alreayd?
34885 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34886 if(this.regions[region] && !this.regions[region].bodyEl){
34887 this.regions[region].onRender(this.el)
34891 var size = this.getViewSize();
34892 var w = size.width;
34893 var h = size.height;
34898 //var x = 0, y = 0;
34900 var rs = this.regions;
34901 var north = rs["north"];
34902 var south = rs["south"];
34903 var west = rs["west"];
34904 var east = rs["east"];
34905 var center = rs["center"];
34906 //if(this.hideOnLayout){ // not supported anymore
34907 //c.el.setStyle("display", "none");
34909 if(north && north.isVisible()){
34910 var b = north.getBox();
34911 var m = north.getMargins();
34912 b.width = w - (m.left+m.right);
34915 centerY = b.height + b.y + m.bottom;
34916 centerH -= centerY;
34917 north.updateBox(this.safeBox(b));
34919 if(south && south.isVisible()){
34920 var b = south.getBox();
34921 var m = south.getMargins();
34922 b.width = w - (m.left+m.right);
34924 var totalHeight = (b.height + m.top + m.bottom);
34925 b.y = h - totalHeight + m.top;
34926 centerH -= totalHeight;
34927 south.updateBox(this.safeBox(b));
34929 if(west && west.isVisible()){
34930 var b = west.getBox();
34931 var m = west.getMargins();
34932 b.height = centerH - (m.top+m.bottom);
34934 b.y = centerY + m.top;
34935 var totalWidth = (b.width + m.left + m.right);
34936 centerX += totalWidth;
34937 centerW -= totalWidth;
34938 west.updateBox(this.safeBox(b));
34940 if(east && east.isVisible()){
34941 var b = east.getBox();
34942 var m = east.getMargins();
34943 b.height = centerH - (m.top+m.bottom);
34944 var totalWidth = (b.width + m.left + m.right);
34945 b.x = w - totalWidth + m.left;
34946 b.y = centerY + m.top;
34947 centerW -= totalWidth;
34948 east.updateBox(this.safeBox(b));
34951 var m = center.getMargins();
34953 x: centerX + m.left,
34954 y: centerY + m.top,
34955 width: centerW - (m.left+m.right),
34956 height: centerH - (m.top+m.bottom)
34958 //if(this.hideOnLayout){
34959 //center.el.setStyle("display", "block");
34961 center.updateBox(this.safeBox(centerBox));
34964 this.fireEvent("layout", this);
34968 safeBox : function(box){
34969 box.width = Math.max(0, box.width);
34970 box.height = Math.max(0, box.height);
34975 * Adds a ContentPanel (or subclass) to this layout.
34976 * @param {String} target The target region key (north, south, east, west or center).
34977 * @param {Roo.ContentPanel} panel The panel to add
34978 * @return {Roo.ContentPanel} The added panel
34980 add : function(target, panel){
34982 target = target.toLowerCase();
34983 return this.regions[target].add(panel);
34987 * Remove a ContentPanel (or subclass) to this layout.
34988 * @param {String} target The target region key (north, south, east, west or center).
34989 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34990 * @return {Roo.ContentPanel} The removed panel
34992 remove : function(target, panel){
34993 target = target.toLowerCase();
34994 return this.regions[target].remove(panel);
34998 * Searches all regions for a panel with the specified id
34999 * @param {String} panelId
35000 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35002 findPanel : function(panelId){
35003 var rs = this.regions;
35004 for(var target in rs){
35005 if(typeof rs[target] != "function"){
35006 var p = rs[target].getPanel(panelId);
35016 * Searches all regions for a panel with the specified id and activates (shows) it.
35017 * @param {String/ContentPanel} panelId The panels id or the panel itself
35018 * @return {Roo.ContentPanel} The shown panel or null
35020 showPanel : function(panelId) {
35021 var rs = this.regions;
35022 for(var target in rs){
35023 var r = rs[target];
35024 if(typeof r != "function"){
35025 if(r.hasPanel(panelId)){
35026 return r.showPanel(panelId);
35034 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35035 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35038 restoreState : function(provider){
35040 provider = Roo.state.Manager;
35042 var sm = new Roo.LayoutStateManager();
35043 sm.init(this, provider);
35049 * Adds a xtype elements to the layout.
35053 xtype : 'ContentPanel',
35060 xtype : 'NestedLayoutPanel',
35066 items : [ ... list of content panels or nested layout panels.. ]
35070 * @param {Object} cfg Xtype definition of item to add.
35072 addxtype : function(cfg)
35074 // basically accepts a pannel...
35075 // can accept a layout region..!?!?
35076 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35079 // theory? children can only be panels??
35081 //if (!cfg.xtype.match(/Panel$/)) {
35086 if (typeof(cfg.region) == 'undefined') {
35087 Roo.log("Failed to add Panel, region was not set");
35091 var region = cfg.region;
35097 xitems = cfg.items;
35104 case 'Content': // ContentPanel (el, cfg)
35105 case 'Scroll': // ContentPanel (el, cfg)
35107 cfg.autoCreate = true;
35108 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35110 // var el = this.el.createChild();
35111 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35114 this.add(region, ret);
35118 case 'TreePanel': // our new panel!
35119 cfg.el = this.el.createChild();
35120 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35121 this.add(region, ret);
35126 // create a new Layout (which is a Border Layout...
35128 var clayout = cfg.layout;
35129 clayout.el = this.el.createChild();
35130 clayout.items = clayout.items || [];
35134 // replace this exitems with the clayout ones..
35135 xitems = clayout.items;
35137 // force background off if it's in center...
35138 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35139 cfg.background = false;
35141 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35144 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35145 //console.log('adding nested layout panel ' + cfg.toSource());
35146 this.add(region, ret);
35147 nb = {}; /// find first...
35152 // needs grid and region
35154 //var el = this.getRegion(region).el.createChild();
35156 *var el = this.el.createChild();
35157 // create the grid first...
35158 cfg.grid.container = el;
35159 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35162 if (region == 'center' && this.active ) {
35163 cfg.background = false;
35166 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35168 this.add(region, ret);
35170 if (cfg.background) {
35171 // render grid on panel activation (if panel background)
35172 ret.on('activate', function(gp) {
35173 if (!gp.grid.rendered) {
35174 // gp.grid.render(el);
35178 // cfg.grid.render(el);
35184 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35185 // it was the old xcomponent building that caused this before.
35186 // espeically if border is the top element in the tree.
35196 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35198 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35199 this.add(region, ret);
35203 throw "Can not add '" + cfg.xtype + "' to Border";
35209 this.beginUpdate();
35213 Roo.each(xitems, function(i) {
35214 region = nb && i.region ? i.region : false;
35216 var add = ret.addxtype(i);
35219 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35220 if (!i.background) {
35221 abn[region] = nb[region] ;
35228 // make the last non-background panel active..
35229 //if (nb) { Roo.log(abn); }
35232 for(var r in abn) {
35233 region = this.getRegion(r);
35235 // tried using nb[r], but it does not work..
35237 region.showPanel(abn[r]);
35248 factory : function(cfg)
35251 var validRegions = Roo.bootstrap.layout.Border.regions;
35253 var target = cfg.region;
35256 var r = Roo.bootstrap.layout;
35260 return new r.North(cfg);
35262 return new r.South(cfg);
35264 return new r.East(cfg);
35266 return new r.West(cfg);
35268 return new r.Center(cfg);
35270 throw 'Layout region "'+target+'" not supported.';
35277 * Ext JS Library 1.1.1
35278 * Copyright(c) 2006-2007, Ext JS, LLC.
35280 * Originally Released Under LGPL - original licence link has changed is not relivant.
35283 * <script type="text/javascript">
35287 * @class Roo.bootstrap.layout.Basic
35288 * @extends Roo.util.Observable
35289 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35290 * and does not have a titlebar, tabs or any other features. All it does is size and position
35291 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35292 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35293 * @cfg {string} region the region that it inhabits..
35294 * @cfg {bool} skipConfig skip config?
35298 Roo.bootstrap.layout.Basic = function(config){
35300 this.mgr = config.mgr;
35302 this.position = config.region;
35304 var skipConfig = config.skipConfig;
35308 * @scope Roo.BasicLayoutRegion
35312 * @event beforeremove
35313 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35314 * @param {Roo.LayoutRegion} this
35315 * @param {Roo.ContentPanel} panel The panel
35316 * @param {Object} e The cancel event object
35318 "beforeremove" : true,
35320 * @event invalidated
35321 * Fires when the layout for this region is changed.
35322 * @param {Roo.LayoutRegion} this
35324 "invalidated" : true,
35326 * @event visibilitychange
35327 * Fires when this region is shown or hidden
35328 * @param {Roo.LayoutRegion} this
35329 * @param {Boolean} visibility true or false
35331 "visibilitychange" : true,
35333 * @event paneladded
35334 * Fires when a panel is added.
35335 * @param {Roo.LayoutRegion} this
35336 * @param {Roo.ContentPanel} panel The panel
35338 "paneladded" : true,
35340 * @event panelremoved
35341 * Fires when a panel is removed.
35342 * @param {Roo.LayoutRegion} this
35343 * @param {Roo.ContentPanel} panel The panel
35345 "panelremoved" : true,
35347 * @event beforecollapse
35348 * Fires when this region before collapse.
35349 * @param {Roo.LayoutRegion} this
35351 "beforecollapse" : true,
35354 * Fires when this region is collapsed.
35355 * @param {Roo.LayoutRegion} this
35357 "collapsed" : true,
35360 * Fires when this region is expanded.
35361 * @param {Roo.LayoutRegion} this
35366 * Fires when this region is slid into view.
35367 * @param {Roo.LayoutRegion} this
35369 "slideshow" : true,
35372 * Fires when this region slides out of view.
35373 * @param {Roo.LayoutRegion} this
35375 "slidehide" : true,
35377 * @event panelactivated
35378 * Fires when a panel is activated.
35379 * @param {Roo.LayoutRegion} this
35380 * @param {Roo.ContentPanel} panel The activated panel
35382 "panelactivated" : true,
35385 * Fires when the user resizes this region.
35386 * @param {Roo.LayoutRegion} this
35387 * @param {Number} newSize The new size (width for east/west, height for north/south)
35391 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35392 this.panels = new Roo.util.MixedCollection();
35393 this.panels.getKey = this.getPanelId.createDelegate(this);
35395 this.activePanel = null;
35396 // ensure listeners are added...
35398 if (config.listeners || config.events) {
35399 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35400 listeners : config.listeners || {},
35401 events : config.events || {}
35405 if(skipConfig !== true){
35406 this.applyConfig(config);
35410 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35412 getPanelId : function(p){
35416 applyConfig : function(config){
35417 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35418 this.config = config;
35423 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35424 * the width, for horizontal (north, south) the height.
35425 * @param {Number} newSize The new width or height
35427 resizeTo : function(newSize){
35428 var el = this.el ? this.el :
35429 (this.activePanel ? this.activePanel.getEl() : null);
35431 switch(this.position){
35434 el.setWidth(newSize);
35435 this.fireEvent("resized", this, newSize);
35439 el.setHeight(newSize);
35440 this.fireEvent("resized", this, newSize);
35446 getBox : function(){
35447 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35450 getMargins : function(){
35451 return this.margins;
35454 updateBox : function(box){
35456 var el = this.activePanel.getEl();
35457 el.dom.style.left = box.x + "px";
35458 el.dom.style.top = box.y + "px";
35459 this.activePanel.setSize(box.width, box.height);
35463 * Returns the container element for this region.
35464 * @return {Roo.Element}
35466 getEl : function(){
35467 return this.activePanel;
35471 * Returns true if this region is currently visible.
35472 * @return {Boolean}
35474 isVisible : function(){
35475 return this.activePanel ? true : false;
35478 setActivePanel : function(panel){
35479 panel = this.getPanel(panel);
35480 if(this.activePanel && this.activePanel != panel){
35481 this.activePanel.setActiveState(false);
35482 this.activePanel.getEl().setLeftTop(-10000,-10000);
35484 this.activePanel = panel;
35485 panel.setActiveState(true);
35487 panel.setSize(this.box.width, this.box.height);
35489 this.fireEvent("panelactivated", this, panel);
35490 this.fireEvent("invalidated");
35494 * Show the specified panel.
35495 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35496 * @return {Roo.ContentPanel} The shown panel or null
35498 showPanel : function(panel){
35499 panel = this.getPanel(panel);
35501 this.setActivePanel(panel);
35507 * Get the active panel for this region.
35508 * @return {Roo.ContentPanel} The active panel or null
35510 getActivePanel : function(){
35511 return this.activePanel;
35515 * Add the passed ContentPanel(s)
35516 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35517 * @return {Roo.ContentPanel} The panel added (if only one was added)
35519 add : function(panel){
35520 if(arguments.length > 1){
35521 for(var i = 0, len = arguments.length; i < len; i++) {
35522 this.add(arguments[i]);
35526 if(this.hasPanel(panel)){
35527 this.showPanel(panel);
35530 var el = panel.getEl();
35531 if(el.dom.parentNode != this.mgr.el.dom){
35532 this.mgr.el.dom.appendChild(el.dom);
35534 if(panel.setRegion){
35535 panel.setRegion(this);
35537 this.panels.add(panel);
35538 el.setStyle("position", "absolute");
35539 if(!panel.background){
35540 this.setActivePanel(panel);
35541 if(this.config.initialSize && this.panels.getCount()==1){
35542 this.resizeTo(this.config.initialSize);
35545 this.fireEvent("paneladded", this, panel);
35550 * Returns true if the panel is in this region.
35551 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35552 * @return {Boolean}
35554 hasPanel : function(panel){
35555 if(typeof panel == "object"){ // must be panel obj
35556 panel = panel.getId();
35558 return this.getPanel(panel) ? true : false;
35562 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35563 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35564 * @param {Boolean} preservePanel Overrides the config preservePanel option
35565 * @return {Roo.ContentPanel} The panel that was removed
35567 remove : function(panel, preservePanel){
35568 panel = this.getPanel(panel);
35573 this.fireEvent("beforeremove", this, panel, e);
35574 if(e.cancel === true){
35577 var panelId = panel.getId();
35578 this.panels.removeKey(panelId);
35583 * Returns the panel specified or null if it's not in this region.
35584 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35585 * @return {Roo.ContentPanel}
35587 getPanel : function(id){
35588 if(typeof id == "object"){ // must be panel obj
35591 return this.panels.get(id);
35595 * Returns this regions position (north/south/east/west/center).
35598 getPosition: function(){
35599 return this.position;
35603 * Ext JS Library 1.1.1
35604 * Copyright(c) 2006-2007, Ext JS, LLC.
35606 * Originally Released Under LGPL - original licence link has changed is not relivant.
35609 * <script type="text/javascript">
35613 * @class Roo.bootstrap.layout.Region
35614 * @extends Roo.bootstrap.layout.Basic
35615 * This class represents a region in a layout manager.
35617 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35618 * @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})
35619 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35620 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35621 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35622 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35623 * @cfg {String} title The title for the region (overrides panel titles)
35624 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35625 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35626 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35627 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35628 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35629 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35630 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35631 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35632 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35633 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35635 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35636 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35637 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35638 * @cfg {Number} width For East/West panels
35639 * @cfg {Number} height For North/South panels
35640 * @cfg {Boolean} split To show the splitter
35641 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35643 * @cfg {string} cls Extra CSS classes to add to region
35645 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35646 * @cfg {string} region the region that it inhabits..
35649 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35650 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35652 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35653 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35654 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35656 Roo.bootstrap.layout.Region = function(config)
35658 this.applyConfig(config);
35660 var mgr = config.mgr;
35661 var pos = config.region;
35662 config.skipConfig = true;
35663 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35666 this.onRender(mgr.el);
35669 this.visible = true;
35670 this.collapsed = false;
35671 this.unrendered_panels = [];
35674 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35676 position: '', // set by wrapper (eg. north/south etc..)
35677 unrendered_panels : null, // unrendered panels.
35678 createBody : function(){
35679 /** This region's body element
35680 * @type Roo.Element */
35681 this.bodyEl = this.el.createChild({
35683 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35687 onRender: function(ctr, pos)
35689 var dh = Roo.DomHelper;
35690 /** This region's container element
35691 * @type Roo.Element */
35692 this.el = dh.append(ctr.dom, {
35694 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35696 /** This region's title element
35697 * @type Roo.Element */
35699 this.titleEl = dh.append(this.el.dom,
35702 unselectable: "on",
35703 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35705 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35706 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35709 this.titleEl.enableDisplayMode();
35710 /** This region's title text element
35711 * @type HTMLElement */
35712 this.titleTextEl = this.titleEl.dom.firstChild;
35713 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35715 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35716 this.closeBtn.enableDisplayMode();
35717 this.closeBtn.on("click", this.closeClicked, this);
35718 this.closeBtn.hide();
35720 this.createBody(this.config);
35721 if(this.config.hideWhenEmpty){
35723 this.on("paneladded", this.validateVisibility, this);
35724 this.on("panelremoved", this.validateVisibility, this);
35726 if(this.autoScroll){
35727 this.bodyEl.setStyle("overflow", "auto");
35729 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35731 //if(c.titlebar !== false){
35732 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35733 this.titleEl.hide();
35735 this.titleEl.show();
35736 if(this.config.title){
35737 this.titleTextEl.innerHTML = this.config.title;
35741 if(this.config.collapsed){
35742 this.collapse(true);
35744 if(this.config.hidden){
35748 if (this.unrendered_panels && this.unrendered_panels.length) {
35749 for (var i =0;i< this.unrendered_panels.length; i++) {
35750 this.add(this.unrendered_panels[i]);
35752 this.unrendered_panels = null;
35758 applyConfig : function(c)
35761 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35762 var dh = Roo.DomHelper;
35763 if(c.titlebar !== false){
35764 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35765 this.collapseBtn.on("click", this.collapse, this);
35766 this.collapseBtn.enableDisplayMode();
35768 if(c.showPin === true || this.showPin){
35769 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35770 this.stickBtn.enableDisplayMode();
35771 this.stickBtn.on("click", this.expand, this);
35772 this.stickBtn.hide();
35777 /** This region's collapsed element
35778 * @type Roo.Element */
35781 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35782 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35785 if(c.floatable !== false){
35786 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35787 this.collapsedEl.on("click", this.collapseClick, this);
35790 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35791 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35792 id: "message", unselectable: "on", style:{"float":"left"}});
35793 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35795 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35796 this.expandBtn.on("click", this.expand, this);
35800 if(this.collapseBtn){
35801 this.collapseBtn.setVisible(c.collapsible == true);
35804 this.cmargins = c.cmargins || this.cmargins ||
35805 (this.position == "west" || this.position == "east" ?
35806 {top: 0, left: 2, right:2, bottom: 0} :
35807 {top: 2, left: 0, right:0, bottom: 2});
35809 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35812 this.bottomTabs = c.tabPosition != "top";
35814 this.autoScroll = c.autoScroll || false;
35819 this.duration = c.duration || .30;
35820 this.slideDuration = c.slideDuration || .45;
35825 * Returns true if this region is currently visible.
35826 * @return {Boolean}
35828 isVisible : function(){
35829 return this.visible;
35833 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35834 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35836 //setCollapsedTitle : function(title){
35837 // title = title || " ";
35838 // if(this.collapsedTitleTextEl){
35839 // this.collapsedTitleTextEl.innerHTML = title;
35843 getBox : function(){
35845 // if(!this.collapsed){
35846 b = this.el.getBox(false, true);
35848 // b = this.collapsedEl.getBox(false, true);
35853 getMargins : function(){
35854 return this.margins;
35855 //return this.collapsed ? this.cmargins : this.margins;
35858 highlight : function(){
35859 this.el.addClass("x-layout-panel-dragover");
35862 unhighlight : function(){
35863 this.el.removeClass("x-layout-panel-dragover");
35866 updateBox : function(box)
35868 if (!this.bodyEl) {
35869 return; // not rendered yet..
35873 if(!this.collapsed){
35874 this.el.dom.style.left = box.x + "px";
35875 this.el.dom.style.top = box.y + "px";
35876 this.updateBody(box.width, box.height);
35878 this.collapsedEl.dom.style.left = box.x + "px";
35879 this.collapsedEl.dom.style.top = box.y + "px";
35880 this.collapsedEl.setSize(box.width, box.height);
35883 this.tabs.autoSizeTabs();
35887 updateBody : function(w, h)
35890 this.el.setWidth(w);
35891 w -= this.el.getBorderWidth("rl");
35892 if(this.config.adjustments){
35893 w += this.config.adjustments[0];
35896 if(h !== null && h > 0){
35897 this.el.setHeight(h);
35898 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35899 h -= this.el.getBorderWidth("tb");
35900 if(this.config.adjustments){
35901 h += this.config.adjustments[1];
35903 this.bodyEl.setHeight(h);
35905 h = this.tabs.syncHeight(h);
35908 if(this.panelSize){
35909 w = w !== null ? w : this.panelSize.width;
35910 h = h !== null ? h : this.panelSize.height;
35912 if(this.activePanel){
35913 var el = this.activePanel.getEl();
35914 w = w !== null ? w : el.getWidth();
35915 h = h !== null ? h : el.getHeight();
35916 this.panelSize = {width: w, height: h};
35917 this.activePanel.setSize(w, h);
35919 if(Roo.isIE && this.tabs){
35920 this.tabs.el.repaint();
35925 * Returns the container element for this region.
35926 * @return {Roo.Element}
35928 getEl : function(){
35933 * Hides this region.
35936 //if(!this.collapsed){
35937 this.el.dom.style.left = "-2000px";
35940 // this.collapsedEl.dom.style.left = "-2000px";
35941 // this.collapsedEl.hide();
35943 this.visible = false;
35944 this.fireEvent("visibilitychange", this, false);
35948 * Shows this region if it was previously hidden.
35951 //if(!this.collapsed){
35954 // this.collapsedEl.show();
35956 this.visible = true;
35957 this.fireEvent("visibilitychange", this, true);
35960 closeClicked : function(){
35961 if(this.activePanel){
35962 this.remove(this.activePanel);
35966 collapseClick : function(e){
35968 e.stopPropagation();
35971 e.stopPropagation();
35977 * Collapses this region.
35978 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35981 collapse : function(skipAnim, skipCheck = false){
35982 if(this.collapsed) {
35986 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35988 this.collapsed = true;
35990 this.split.el.hide();
35992 if(this.config.animate && skipAnim !== true){
35993 this.fireEvent("invalidated", this);
35994 this.animateCollapse();
35996 this.el.setLocation(-20000,-20000);
35998 this.collapsedEl.show();
35999 this.fireEvent("collapsed", this);
36000 this.fireEvent("invalidated", this);
36006 animateCollapse : function(){
36011 * Expands this region if it was previously collapsed.
36012 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36013 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36016 expand : function(e, skipAnim){
36018 e.stopPropagation();
36020 if(!this.collapsed || this.el.hasActiveFx()) {
36024 this.afterSlideIn();
36027 this.collapsed = false;
36028 if(this.config.animate && skipAnim !== true){
36029 this.animateExpand();
36033 this.split.el.show();
36035 this.collapsedEl.setLocation(-2000,-2000);
36036 this.collapsedEl.hide();
36037 this.fireEvent("invalidated", this);
36038 this.fireEvent("expanded", this);
36042 animateExpand : function(){
36046 initTabs : function()
36048 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36050 var ts = new Roo.bootstrap.panel.Tabs({
36051 el: this.bodyEl.dom,
36052 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36053 disableTooltips: this.config.disableTabTips,
36054 toolbar : this.config.toolbar
36057 if(this.config.hideTabs){
36058 ts.stripWrap.setDisplayed(false);
36061 ts.resizeTabs = this.config.resizeTabs === true;
36062 ts.minTabWidth = this.config.minTabWidth || 40;
36063 ts.maxTabWidth = this.config.maxTabWidth || 250;
36064 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36065 ts.monitorResize = false;
36066 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36067 ts.bodyEl.addClass('roo-layout-tabs-body');
36068 this.panels.each(this.initPanelAsTab, this);
36071 initPanelAsTab : function(panel){
36072 var ti = this.tabs.addTab(
36076 this.config.closeOnTab && panel.isClosable(),
36079 if(panel.tabTip !== undefined){
36080 ti.setTooltip(panel.tabTip);
36082 ti.on("activate", function(){
36083 this.setActivePanel(panel);
36086 if(this.config.closeOnTab){
36087 ti.on("beforeclose", function(t, e){
36089 this.remove(panel);
36093 panel.tabItem = ti;
36098 updatePanelTitle : function(panel, title)
36100 if(this.activePanel == panel){
36101 this.updateTitle(title);
36104 var ti = this.tabs.getTab(panel.getEl().id);
36106 if(panel.tabTip !== undefined){
36107 ti.setTooltip(panel.tabTip);
36112 updateTitle : function(title){
36113 if(this.titleTextEl && !this.config.title){
36114 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36118 setActivePanel : function(panel)
36120 panel = this.getPanel(panel);
36121 if(this.activePanel && this.activePanel != panel){
36122 if(this.activePanel.setActiveState(false) === false){
36126 this.activePanel = panel;
36127 panel.setActiveState(true);
36128 if(this.panelSize){
36129 panel.setSize(this.panelSize.width, this.panelSize.height);
36132 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36134 this.updateTitle(panel.getTitle());
36136 this.fireEvent("invalidated", this);
36138 this.fireEvent("panelactivated", this, panel);
36142 * Shows the specified panel.
36143 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36144 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36146 showPanel : function(panel)
36148 panel = this.getPanel(panel);
36151 var tab = this.tabs.getTab(panel.getEl().id);
36152 if(tab.isHidden()){
36153 this.tabs.unhideTab(tab.id);
36157 this.setActivePanel(panel);
36164 * Get the active panel for this region.
36165 * @return {Roo.ContentPanel} The active panel or null
36167 getActivePanel : function(){
36168 return this.activePanel;
36171 validateVisibility : function(){
36172 if(this.panels.getCount() < 1){
36173 this.updateTitle(" ");
36174 this.closeBtn.hide();
36177 if(!this.isVisible()){
36184 * Adds the passed ContentPanel(s) to this region.
36185 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36186 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36188 add : function(panel)
36190 if(arguments.length > 1){
36191 for(var i = 0, len = arguments.length; i < len; i++) {
36192 this.add(arguments[i]);
36197 // if we have not been rendered yet, then we can not really do much of this..
36198 if (!this.bodyEl) {
36199 this.unrendered_panels.push(panel);
36206 if(this.hasPanel(panel)){
36207 this.showPanel(panel);
36210 panel.setRegion(this);
36211 this.panels.add(panel);
36212 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36213 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36214 // and hide them... ???
36215 this.bodyEl.dom.appendChild(panel.getEl().dom);
36216 if(panel.background !== true){
36217 this.setActivePanel(panel);
36219 this.fireEvent("paneladded", this, panel);
36226 this.initPanelAsTab(panel);
36230 if(panel.background !== true){
36231 this.tabs.activate(panel.getEl().id);
36233 this.fireEvent("paneladded", this, panel);
36238 * Hides the tab for the specified panel.
36239 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36241 hidePanel : function(panel){
36242 if(this.tabs && (panel = this.getPanel(panel))){
36243 this.tabs.hideTab(panel.getEl().id);
36248 * Unhides the tab for a previously hidden panel.
36249 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36251 unhidePanel : function(panel){
36252 if(this.tabs && (panel = this.getPanel(panel))){
36253 this.tabs.unhideTab(panel.getEl().id);
36257 clearPanels : function(){
36258 while(this.panels.getCount() > 0){
36259 this.remove(this.panels.first());
36264 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36265 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36266 * @param {Boolean} preservePanel Overrides the config preservePanel option
36267 * @return {Roo.ContentPanel} The panel that was removed
36269 remove : function(panel, preservePanel)
36271 panel = this.getPanel(panel);
36276 this.fireEvent("beforeremove", this, panel, e);
36277 if(e.cancel === true){
36280 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36281 var panelId = panel.getId();
36282 this.panels.removeKey(panelId);
36284 document.body.appendChild(panel.getEl().dom);
36287 this.tabs.removeTab(panel.getEl().id);
36288 }else if (!preservePanel){
36289 this.bodyEl.dom.removeChild(panel.getEl().dom);
36291 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36292 var p = this.panels.first();
36293 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36294 tempEl.appendChild(p.getEl().dom);
36295 this.bodyEl.update("");
36296 this.bodyEl.dom.appendChild(p.getEl().dom);
36298 this.updateTitle(p.getTitle());
36300 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36301 this.setActivePanel(p);
36303 panel.setRegion(null);
36304 if(this.activePanel == panel){
36305 this.activePanel = null;
36307 if(this.config.autoDestroy !== false && preservePanel !== true){
36308 try{panel.destroy();}catch(e){}
36310 this.fireEvent("panelremoved", this, panel);
36315 * Returns the TabPanel component used by this region
36316 * @return {Roo.TabPanel}
36318 getTabs : function(){
36322 createTool : function(parentEl, className){
36323 var btn = Roo.DomHelper.append(parentEl, {
36325 cls: "x-layout-tools-button",
36328 cls: "roo-layout-tools-button-inner " + className,
36332 btn.addClassOnOver("roo-layout-tools-button-over");
36337 * Ext JS Library 1.1.1
36338 * Copyright(c) 2006-2007, Ext JS, LLC.
36340 * Originally Released Under LGPL - original licence link has changed is not relivant.
36343 * <script type="text/javascript">
36349 * @class Roo.SplitLayoutRegion
36350 * @extends Roo.LayoutRegion
36351 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36353 Roo.bootstrap.layout.Split = function(config){
36354 this.cursor = config.cursor;
36355 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36358 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36360 splitTip : "Drag to resize.",
36361 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36362 useSplitTips : false,
36364 applyConfig : function(config){
36365 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36368 onRender : function(ctr,pos) {
36370 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36371 if(!this.config.split){
36376 var splitEl = Roo.DomHelper.append(ctr.dom, {
36378 id: this.el.id + "-split",
36379 cls: "roo-layout-split roo-layout-split-"+this.position,
36382 /** The SplitBar for this region
36383 * @type Roo.SplitBar */
36384 // does not exist yet...
36385 Roo.log([this.position, this.orientation]);
36387 this.split = new Roo.bootstrap.SplitBar({
36388 dragElement : splitEl,
36389 resizingElement: this.el,
36390 orientation : this.orientation
36393 this.split.on("moved", this.onSplitMove, this);
36394 this.split.useShim = this.config.useShim === true;
36395 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36396 if(this.useSplitTips){
36397 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36399 //if(config.collapsible){
36400 // this.split.el.on("dblclick", this.collapse, this);
36403 if(typeof this.config.minSize != "undefined"){
36404 this.split.minSize = this.config.minSize;
36406 if(typeof this.config.maxSize != "undefined"){
36407 this.split.maxSize = this.config.maxSize;
36409 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36410 this.hideSplitter();
36415 getHMaxSize : function(){
36416 var cmax = this.config.maxSize || 10000;
36417 var center = this.mgr.getRegion("center");
36418 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36421 getVMaxSize : function(){
36422 var cmax = this.config.maxSize || 10000;
36423 var center = this.mgr.getRegion("center");
36424 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36427 onSplitMove : function(split, newSize){
36428 this.fireEvent("resized", this, newSize);
36432 * Returns the {@link Roo.SplitBar} for this region.
36433 * @return {Roo.SplitBar}
36435 getSplitBar : function(){
36440 this.hideSplitter();
36441 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36444 hideSplitter : function(){
36446 this.split.el.setLocation(-2000,-2000);
36447 this.split.el.hide();
36453 this.split.el.show();
36455 Roo.bootstrap.layout.Split.superclass.show.call(this);
36458 beforeSlide: function(){
36459 if(Roo.isGecko){// firefox overflow auto bug workaround
36460 this.bodyEl.clip();
36462 this.tabs.bodyEl.clip();
36464 if(this.activePanel){
36465 this.activePanel.getEl().clip();
36467 if(this.activePanel.beforeSlide){
36468 this.activePanel.beforeSlide();
36474 afterSlide : function(){
36475 if(Roo.isGecko){// firefox overflow auto bug workaround
36476 this.bodyEl.unclip();
36478 this.tabs.bodyEl.unclip();
36480 if(this.activePanel){
36481 this.activePanel.getEl().unclip();
36482 if(this.activePanel.afterSlide){
36483 this.activePanel.afterSlide();
36489 initAutoHide : function(){
36490 if(this.autoHide !== false){
36491 if(!this.autoHideHd){
36492 var st = new Roo.util.DelayedTask(this.slideIn, this);
36493 this.autoHideHd = {
36494 "mouseout": function(e){
36495 if(!e.within(this.el, true)){
36499 "mouseover" : function(e){
36505 this.el.on(this.autoHideHd);
36509 clearAutoHide : function(){
36510 if(this.autoHide !== false){
36511 this.el.un("mouseout", this.autoHideHd.mouseout);
36512 this.el.un("mouseover", this.autoHideHd.mouseover);
36516 clearMonitor : function(){
36517 Roo.get(document).un("click", this.slideInIf, this);
36520 // these names are backwards but not changed for compat
36521 slideOut : function(){
36522 if(this.isSlid || this.el.hasActiveFx()){
36525 this.isSlid = true;
36526 if(this.collapseBtn){
36527 this.collapseBtn.hide();
36529 this.closeBtnState = this.closeBtn.getStyle('display');
36530 this.closeBtn.hide();
36532 this.stickBtn.show();
36535 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36536 this.beforeSlide();
36537 this.el.setStyle("z-index", 10001);
36538 this.el.slideIn(this.getSlideAnchor(), {
36539 callback: function(){
36541 this.initAutoHide();
36542 Roo.get(document).on("click", this.slideInIf, this);
36543 this.fireEvent("slideshow", this);
36550 afterSlideIn : function(){
36551 this.clearAutoHide();
36552 this.isSlid = false;
36553 this.clearMonitor();
36554 this.el.setStyle("z-index", "");
36555 if(this.collapseBtn){
36556 this.collapseBtn.show();
36558 this.closeBtn.setStyle('display', this.closeBtnState);
36560 this.stickBtn.hide();
36562 this.fireEvent("slidehide", this);
36565 slideIn : function(cb){
36566 if(!this.isSlid || this.el.hasActiveFx()){
36570 this.isSlid = false;
36571 this.beforeSlide();
36572 this.el.slideOut(this.getSlideAnchor(), {
36573 callback: function(){
36574 this.el.setLeftTop(-10000, -10000);
36576 this.afterSlideIn();
36584 slideInIf : function(e){
36585 if(!e.within(this.el)){
36590 animateCollapse : function(){
36591 this.beforeSlide();
36592 this.el.setStyle("z-index", 20000);
36593 var anchor = this.getSlideAnchor();
36594 this.el.slideOut(anchor, {
36595 callback : function(){
36596 this.el.setStyle("z-index", "");
36597 this.collapsedEl.slideIn(anchor, {duration:.3});
36599 this.el.setLocation(-10000,-10000);
36601 this.fireEvent("collapsed", this);
36608 animateExpand : function(){
36609 this.beforeSlide();
36610 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36611 this.el.setStyle("z-index", 20000);
36612 this.collapsedEl.hide({
36615 this.el.slideIn(this.getSlideAnchor(), {
36616 callback : function(){
36617 this.el.setStyle("z-index", "");
36620 this.split.el.show();
36622 this.fireEvent("invalidated", this);
36623 this.fireEvent("expanded", this);
36651 getAnchor : function(){
36652 return this.anchors[this.position];
36655 getCollapseAnchor : function(){
36656 return this.canchors[this.position];
36659 getSlideAnchor : function(){
36660 return this.sanchors[this.position];
36663 getAlignAdj : function(){
36664 var cm = this.cmargins;
36665 switch(this.position){
36681 getExpandAdj : function(){
36682 var c = this.collapsedEl, cm = this.cmargins;
36683 switch(this.position){
36685 return [-(cm.right+c.getWidth()+cm.left), 0];
36688 return [cm.right+c.getWidth()+cm.left, 0];
36691 return [0, -(cm.top+cm.bottom+c.getHeight())];
36694 return [0, cm.top+cm.bottom+c.getHeight()];
36700 * Ext JS Library 1.1.1
36701 * Copyright(c) 2006-2007, Ext JS, LLC.
36703 * Originally Released Under LGPL - original licence link has changed is not relivant.
36706 * <script type="text/javascript">
36709 * These classes are private internal classes
36711 Roo.bootstrap.layout.Center = function(config){
36712 config.region = "center";
36713 Roo.bootstrap.layout.Region.call(this, config);
36714 this.visible = true;
36715 this.minWidth = config.minWidth || 20;
36716 this.minHeight = config.minHeight || 20;
36719 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36721 // center panel can't be hidden
36725 // center panel can't be hidden
36728 getMinWidth: function(){
36729 return this.minWidth;
36732 getMinHeight: function(){
36733 return this.minHeight;
36746 Roo.bootstrap.layout.North = function(config)
36748 config.region = 'north';
36749 config.cursor = 'n-resize';
36751 Roo.bootstrap.layout.Split.call(this, config);
36755 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36756 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36757 this.split.el.addClass("roo-layout-split-v");
36759 var size = config.initialSize || config.height;
36760 if(typeof size != "undefined"){
36761 this.el.setHeight(size);
36764 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36766 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36770 getBox : function(){
36771 if(this.collapsed){
36772 return this.collapsedEl.getBox();
36774 var box = this.el.getBox();
36776 box.height += this.split.el.getHeight();
36781 updateBox : function(box){
36782 if(this.split && !this.collapsed){
36783 box.height -= this.split.el.getHeight();
36784 this.split.el.setLeft(box.x);
36785 this.split.el.setTop(box.y+box.height);
36786 this.split.el.setWidth(box.width);
36788 if(this.collapsed){
36789 this.updateBody(box.width, null);
36791 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36799 Roo.bootstrap.layout.South = function(config){
36800 config.region = 'south';
36801 config.cursor = 's-resize';
36802 Roo.bootstrap.layout.Split.call(this, config);
36804 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36805 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36806 this.split.el.addClass("roo-layout-split-v");
36808 var size = config.initialSize || config.height;
36809 if(typeof size != "undefined"){
36810 this.el.setHeight(size);
36814 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36815 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36816 getBox : function(){
36817 if(this.collapsed){
36818 return this.collapsedEl.getBox();
36820 var box = this.el.getBox();
36822 var sh = this.split.el.getHeight();
36829 updateBox : function(box){
36830 if(this.split && !this.collapsed){
36831 var sh = this.split.el.getHeight();
36834 this.split.el.setLeft(box.x);
36835 this.split.el.setTop(box.y-sh);
36836 this.split.el.setWidth(box.width);
36838 if(this.collapsed){
36839 this.updateBody(box.width, null);
36841 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36845 Roo.bootstrap.layout.East = function(config){
36846 config.region = "east";
36847 config.cursor = "e-resize";
36848 Roo.bootstrap.layout.Split.call(this, config);
36850 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36851 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36852 this.split.el.addClass("roo-layout-split-h");
36854 var size = config.initialSize || config.width;
36855 if(typeof size != "undefined"){
36856 this.el.setWidth(size);
36859 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36860 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36861 getBox : function(){
36862 if(this.collapsed){
36863 return this.collapsedEl.getBox();
36865 var box = this.el.getBox();
36867 var sw = this.split.el.getWidth();
36874 updateBox : function(box){
36875 if(this.split && !this.collapsed){
36876 var sw = this.split.el.getWidth();
36878 this.split.el.setLeft(box.x);
36879 this.split.el.setTop(box.y);
36880 this.split.el.setHeight(box.height);
36883 if(this.collapsed){
36884 this.updateBody(null, box.height);
36886 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36890 Roo.bootstrap.layout.West = function(config){
36891 config.region = "west";
36892 config.cursor = "w-resize";
36894 Roo.bootstrap.layout.Split.call(this, config);
36896 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36897 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36898 this.split.el.addClass("roo-layout-split-h");
36902 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36903 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36905 onRender: function(ctr, pos)
36907 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36908 var size = this.config.initialSize || this.config.width;
36909 if(typeof size != "undefined"){
36910 this.el.setWidth(size);
36914 getBox : function(){
36915 if(this.collapsed){
36916 return this.collapsedEl.getBox();
36918 var box = this.el.getBox();
36920 box.width += this.split.el.getWidth();
36925 updateBox : function(box){
36926 if(this.split && !this.collapsed){
36927 var sw = this.split.el.getWidth();
36929 this.split.el.setLeft(box.x+box.width);
36930 this.split.el.setTop(box.y);
36931 this.split.el.setHeight(box.height);
36933 if(this.collapsed){
36934 this.updateBody(null, box.height);
36936 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36939 Roo.namespace("Roo.bootstrap.panel");/*
36941 * Ext JS Library 1.1.1
36942 * Copyright(c) 2006-2007, Ext JS, LLC.
36944 * Originally Released Under LGPL - original licence link has changed is not relivant.
36947 * <script type="text/javascript">
36950 * @class Roo.ContentPanel
36951 * @extends Roo.util.Observable
36952 * A basic ContentPanel element.
36953 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36954 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36955 * @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
36956 * @cfg {Boolean} closable True if the panel can be closed/removed
36957 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36958 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36959 * @cfg {Toolbar} toolbar A toolbar for this panel
36960 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36961 * @cfg {String} title The title for this panel
36962 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36963 * @cfg {String} url Calls {@link #setUrl} with this value
36964 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36965 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36966 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36967 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36968 * @cfg {Boolean} badges render the badges
36971 * Create a new ContentPanel.
36972 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36973 * @param {String/Object} config A string to set only the title or a config object
36974 * @param {String} content (optional) Set the HTML content for this panel
36975 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36977 Roo.bootstrap.panel.Content = function( config){
36979 this.tpl = config.tpl || false;
36981 var el = config.el;
36982 var content = config.content;
36984 if(config.autoCreate){ // xtype is available if this is called from factory
36987 this.el = Roo.get(el);
36988 if(!this.el && config && config.autoCreate){
36989 if(typeof config.autoCreate == "object"){
36990 if(!config.autoCreate.id){
36991 config.autoCreate.id = config.id||el;
36993 this.el = Roo.DomHelper.append(document.body,
36994 config.autoCreate, true);
36996 var elcfg = { tag: "div",
36997 cls: "roo-layout-inactive-content",
37001 elcfg.html = config.html;
37005 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37008 this.closable = false;
37009 this.loaded = false;
37010 this.active = false;
37013 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37015 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37017 this.wrapEl = this.el; //this.el.wrap();
37019 if (config.toolbar.items) {
37020 ti = config.toolbar.items ;
37021 delete config.toolbar.items ;
37025 this.toolbar.render(this.wrapEl, 'before');
37026 for(var i =0;i < ti.length;i++) {
37027 // Roo.log(['add child', items[i]]);
37028 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37030 this.toolbar.items = nitems;
37031 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37032 delete config.toolbar;
37036 // xtype created footer. - not sure if will work as we normally have to render first..
37037 if (this.footer && !this.footer.el && this.footer.xtype) {
37038 if (!this.wrapEl) {
37039 this.wrapEl = this.el.wrap();
37042 this.footer.container = this.wrapEl.createChild();
37044 this.footer = Roo.factory(this.footer, Roo);
37049 if(typeof config == "string"){
37050 this.title = config;
37052 Roo.apply(this, config);
37056 this.resizeEl = Roo.get(this.resizeEl, true);
37058 this.resizeEl = this.el;
37060 // handle view.xtype
37068 * Fires when this panel is activated.
37069 * @param {Roo.ContentPanel} this
37073 * @event deactivate
37074 * Fires when this panel is activated.
37075 * @param {Roo.ContentPanel} this
37077 "deactivate" : true,
37081 * Fires when this panel is resized if fitToFrame is true.
37082 * @param {Roo.ContentPanel} this
37083 * @param {Number} width The width after any component adjustments
37084 * @param {Number} height The height after any component adjustments
37090 * Fires when this tab is created
37091 * @param {Roo.ContentPanel} this
37102 if(this.autoScroll){
37103 this.resizeEl.setStyle("overflow", "auto");
37105 // fix randome scrolling
37106 //this.el.on('scroll', function() {
37107 // Roo.log('fix random scolling');
37108 // this.scrollTo('top',0);
37111 content = content || this.content;
37113 this.setContent(content);
37115 if(config && config.url){
37116 this.setUrl(this.url, this.params, this.loadOnce);
37121 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37123 if (this.view && typeof(this.view.xtype) != 'undefined') {
37124 this.view.el = this.el.appendChild(document.createElement("div"));
37125 this.view = Roo.factory(this.view);
37126 this.view.render && this.view.render(false, '');
37130 this.fireEvent('render', this);
37133 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37137 setRegion : function(region){
37138 this.region = region;
37139 this.setActiveClass(region && !this.background);
37143 setActiveClass: function(state)
37146 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37147 this.el.setStyle('position','relative');
37149 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37150 this.el.setStyle('position', 'absolute');
37155 * Returns the toolbar for this Panel if one was configured.
37156 * @return {Roo.Toolbar}
37158 getToolbar : function(){
37159 return this.toolbar;
37162 setActiveState : function(active)
37164 this.active = active;
37165 this.setActiveClass(active);
37167 if(this.fireEvent("deactivate", this) === false){
37172 this.fireEvent("activate", this);
37176 * Updates this panel's element
37177 * @param {String} content The new content
37178 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37180 setContent : function(content, loadScripts){
37181 this.el.update(content, loadScripts);
37184 ignoreResize : function(w, h){
37185 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37188 this.lastSize = {width: w, height: h};
37193 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37194 * @return {Roo.UpdateManager} The UpdateManager
37196 getUpdateManager : function(){
37197 return this.el.getUpdateManager();
37200 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37201 * @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:
37204 url: "your-url.php",
37205 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37206 callback: yourFunction,
37207 scope: yourObject, //(optional scope)
37210 text: "Loading...",
37215 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37216 * 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.
37217 * @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}
37218 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37219 * @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.
37220 * @return {Roo.ContentPanel} this
37223 var um = this.el.getUpdateManager();
37224 um.update.apply(um, arguments);
37230 * 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.
37231 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37232 * @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)
37233 * @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)
37234 * @return {Roo.UpdateManager} The UpdateManager
37236 setUrl : function(url, params, loadOnce){
37237 if(this.refreshDelegate){
37238 this.removeListener("activate", this.refreshDelegate);
37240 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37241 this.on("activate", this.refreshDelegate);
37242 return this.el.getUpdateManager();
37245 _handleRefresh : function(url, params, loadOnce){
37246 if(!loadOnce || !this.loaded){
37247 var updater = this.el.getUpdateManager();
37248 updater.update(url, params, this._setLoaded.createDelegate(this));
37252 _setLoaded : function(){
37253 this.loaded = true;
37257 * Returns this panel's id
37260 getId : function(){
37265 * Returns this panel's element - used by regiosn to add.
37266 * @return {Roo.Element}
37268 getEl : function(){
37269 return this.wrapEl || this.el;
37274 adjustForComponents : function(width, height)
37276 //Roo.log('adjustForComponents ');
37277 if(this.resizeEl != this.el){
37278 width -= this.el.getFrameWidth('lr');
37279 height -= this.el.getFrameWidth('tb');
37282 var te = this.toolbar.getEl();
37283 te.setWidth(width);
37284 height -= te.getHeight();
37287 var te = this.footer.getEl();
37288 te.setWidth(width);
37289 height -= te.getHeight();
37293 if(this.adjustments){
37294 width += this.adjustments[0];
37295 height += this.adjustments[1];
37297 return {"width": width, "height": height};
37300 setSize : function(width, height){
37301 if(this.fitToFrame && !this.ignoreResize(width, height)){
37302 if(this.fitContainer && this.resizeEl != this.el){
37303 this.el.setSize(width, height);
37305 var size = this.adjustForComponents(width, height);
37306 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37307 this.fireEvent('resize', this, size.width, size.height);
37312 * Returns this panel's title
37315 getTitle : function(){
37317 if (typeof(this.title) != 'object') {
37322 for (var k in this.title) {
37323 if (!this.title.hasOwnProperty(k)) {
37327 if (k.indexOf('-') >= 0) {
37328 var s = k.split('-');
37329 for (var i = 0; i<s.length; i++) {
37330 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37333 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37340 * Set this panel's title
37341 * @param {String} title
37343 setTitle : function(title){
37344 this.title = title;
37346 this.region.updatePanelTitle(this, title);
37351 * Returns true is this panel was configured to be closable
37352 * @return {Boolean}
37354 isClosable : function(){
37355 return this.closable;
37358 beforeSlide : function(){
37360 this.resizeEl.clip();
37363 afterSlide : function(){
37365 this.resizeEl.unclip();
37369 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37370 * Will fail silently if the {@link #setUrl} method has not been called.
37371 * This does not activate the panel, just updates its content.
37373 refresh : function(){
37374 if(this.refreshDelegate){
37375 this.loaded = false;
37376 this.refreshDelegate();
37381 * Destroys this panel
37383 destroy : function(){
37384 this.el.removeAllListeners();
37385 var tempEl = document.createElement("span");
37386 tempEl.appendChild(this.el.dom);
37387 tempEl.innerHTML = "";
37393 * form - if the content panel contains a form - this is a reference to it.
37394 * @type {Roo.form.Form}
37398 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37399 * This contains a reference to it.
37405 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37415 * @param {Object} cfg Xtype definition of item to add.
37419 getChildContainer: function () {
37420 return this.getEl();
37425 var ret = new Roo.factory(cfg);
37430 if (cfg.xtype.match(/^Form$/)) {
37433 //if (this.footer) {
37434 // el = this.footer.container.insertSibling(false, 'before');
37436 el = this.el.createChild();
37439 this.form = new Roo.form.Form(cfg);
37442 if ( this.form.allItems.length) {
37443 this.form.render(el.dom);
37447 // should only have one of theses..
37448 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37449 // views.. should not be just added - used named prop 'view''
37451 cfg.el = this.el.appendChild(document.createElement("div"));
37454 var ret = new Roo.factory(cfg);
37456 ret.render && ret.render(false, ''); // render blank..
37466 * @class Roo.bootstrap.panel.Grid
37467 * @extends Roo.bootstrap.panel.Content
37469 * Create a new GridPanel.
37470 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37471 * @param {Object} config A the config object
37477 Roo.bootstrap.panel.Grid = function(config)
37481 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37482 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37484 config.el = this.wrapper;
37485 //this.el = this.wrapper;
37487 if (config.container) {
37488 // ctor'ed from a Border/panel.grid
37491 this.wrapper.setStyle("overflow", "hidden");
37492 this.wrapper.addClass('roo-grid-container');
37497 if(config.toolbar){
37498 var tool_el = this.wrapper.createChild();
37499 this.toolbar = Roo.factory(config.toolbar);
37501 if (config.toolbar.items) {
37502 ti = config.toolbar.items ;
37503 delete config.toolbar.items ;
37507 this.toolbar.render(tool_el);
37508 for(var i =0;i < ti.length;i++) {
37509 // Roo.log(['add child', items[i]]);
37510 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37512 this.toolbar.items = nitems;
37514 delete config.toolbar;
37517 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37518 config.grid.scrollBody = true;;
37519 config.grid.monitorWindowResize = false; // turn off autosizing
37520 config.grid.autoHeight = false;
37521 config.grid.autoWidth = false;
37523 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37525 if (config.background) {
37526 // render grid on panel activation (if panel background)
37527 this.on('activate', function(gp) {
37528 if (!gp.grid.rendered) {
37529 gp.grid.render(this.wrapper);
37530 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37535 this.grid.render(this.wrapper);
37536 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37539 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37540 // ??? needed ??? config.el = this.wrapper;
37545 // xtype created footer. - not sure if will work as we normally have to render first..
37546 if (this.footer && !this.footer.el && this.footer.xtype) {
37548 var ctr = this.grid.getView().getFooterPanel(true);
37549 this.footer.dataSource = this.grid.dataSource;
37550 this.footer = Roo.factory(this.footer, Roo);
37551 this.footer.render(ctr);
37561 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37562 getId : function(){
37563 return this.grid.id;
37567 * Returns the grid for this panel
37568 * @return {Roo.bootstrap.Table}
37570 getGrid : function(){
37574 setSize : function(width, height){
37575 if(!this.ignoreResize(width, height)){
37576 var grid = this.grid;
37577 var size = this.adjustForComponents(width, height);
37578 var gridel = grid.getGridEl();
37579 gridel.setSize(size.width, size.height);
37581 var thd = grid.getGridEl().select('thead',true).first();
37582 var tbd = grid.getGridEl().select('tbody', true).first();
37584 tbd.setSize(width, height - thd.getHeight());
37593 beforeSlide : function(){
37594 this.grid.getView().scroller.clip();
37597 afterSlide : function(){
37598 this.grid.getView().scroller.unclip();
37601 destroy : function(){
37602 this.grid.destroy();
37604 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37609 * @class Roo.bootstrap.panel.Nest
37610 * @extends Roo.bootstrap.panel.Content
37612 * Create a new Panel, that can contain a layout.Border.
37615 * @param {Roo.BorderLayout} layout The layout for this panel
37616 * @param {String/Object} config A string to set only the title or a config object
37618 Roo.bootstrap.panel.Nest = function(config)
37620 // construct with only one argument..
37621 /* FIXME - implement nicer consturctors
37622 if (layout.layout) {
37624 layout = config.layout;
37625 delete config.layout;
37627 if (layout.xtype && !layout.getEl) {
37628 // then layout needs constructing..
37629 layout = Roo.factory(layout, Roo);
37633 config.el = config.layout.getEl();
37635 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37637 config.layout.monitorWindowResize = false; // turn off autosizing
37638 this.layout = config.layout;
37639 this.layout.getEl().addClass("roo-layout-nested-layout");
37646 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37648 setSize : function(width, height){
37649 if(!this.ignoreResize(width, height)){
37650 var size = this.adjustForComponents(width, height);
37651 var el = this.layout.getEl();
37652 if (size.height < 1) {
37653 el.setWidth(size.width);
37655 el.setSize(size.width, size.height);
37657 var touch = el.dom.offsetWidth;
37658 this.layout.layout();
37659 // ie requires a double layout on the first pass
37660 if(Roo.isIE && !this.initialized){
37661 this.initialized = true;
37662 this.layout.layout();
37667 // activate all subpanels if not currently active..
37669 setActiveState : function(active){
37670 this.active = active;
37671 this.setActiveClass(active);
37674 this.fireEvent("deactivate", this);
37678 this.fireEvent("activate", this);
37679 // not sure if this should happen before or after..
37680 if (!this.layout) {
37681 return; // should not happen..
37684 for (var r in this.layout.regions) {
37685 reg = this.layout.getRegion(r);
37686 if (reg.getActivePanel()) {
37687 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37688 reg.setActivePanel(reg.getActivePanel());
37691 if (!reg.panels.length) {
37694 reg.showPanel(reg.getPanel(0));
37703 * Returns the nested BorderLayout for this panel
37704 * @return {Roo.BorderLayout}
37706 getLayout : function(){
37707 return this.layout;
37711 * Adds a xtype elements to the layout of the nested panel
37715 xtype : 'ContentPanel',
37722 xtype : 'NestedLayoutPanel',
37728 items : [ ... list of content panels or nested layout panels.. ]
37732 * @param {Object} cfg Xtype definition of item to add.
37734 addxtype : function(cfg) {
37735 return this.layout.addxtype(cfg);
37740 * Ext JS Library 1.1.1
37741 * Copyright(c) 2006-2007, Ext JS, LLC.
37743 * Originally Released Under LGPL - original licence link has changed is not relivant.
37746 * <script type="text/javascript">
37749 * @class Roo.TabPanel
37750 * @extends Roo.util.Observable
37751 * A lightweight tab container.
37755 // basic tabs 1, built from existing content
37756 var tabs = new Roo.TabPanel("tabs1");
37757 tabs.addTab("script", "View Script");
37758 tabs.addTab("markup", "View Markup");
37759 tabs.activate("script");
37761 // more advanced tabs, built from javascript
37762 var jtabs = new Roo.TabPanel("jtabs");
37763 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37765 // set up the UpdateManager
37766 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37767 var updater = tab2.getUpdateManager();
37768 updater.setDefaultUrl("ajax1.htm");
37769 tab2.on('activate', updater.refresh, updater, true);
37771 // Use setUrl for Ajax loading
37772 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37773 tab3.setUrl("ajax2.htm", null, true);
37776 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37779 jtabs.activate("jtabs-1");
37782 * Create a new TabPanel.
37783 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37784 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37786 Roo.bootstrap.panel.Tabs = function(config){
37788 * The container element for this TabPanel.
37789 * @type Roo.Element
37791 this.el = Roo.get(config.el);
37794 if(typeof config == "boolean"){
37795 this.tabPosition = config ? "bottom" : "top";
37797 Roo.apply(this, config);
37801 if(this.tabPosition == "bottom"){
37802 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37803 this.el.addClass("roo-tabs-bottom");
37805 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37806 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37807 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37809 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37811 if(this.tabPosition != "bottom"){
37812 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37813 * @type Roo.Element
37815 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37816 this.el.addClass("roo-tabs-top");
37820 this.bodyEl.setStyle("position", "relative");
37822 this.active = null;
37823 this.activateDelegate = this.activate.createDelegate(this);
37828 * Fires when the active tab changes
37829 * @param {Roo.TabPanel} this
37830 * @param {Roo.TabPanelItem} activePanel The new active tab
37834 * @event beforetabchange
37835 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37836 * @param {Roo.TabPanel} this
37837 * @param {Object} e Set cancel to true on this object to cancel the tab change
37838 * @param {Roo.TabPanelItem} tab The tab being changed to
37840 "beforetabchange" : true
37843 Roo.EventManager.onWindowResize(this.onResize, this);
37844 this.cpad = this.el.getPadding("lr");
37845 this.hiddenCount = 0;
37848 // toolbar on the tabbar support...
37849 if (this.toolbar) {
37850 alert("no toolbar support yet");
37851 this.toolbar = false;
37853 var tcfg = this.toolbar;
37854 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37855 this.toolbar = new Roo.Toolbar(tcfg);
37856 if (Roo.isSafari) {
37857 var tbl = tcfg.container.child('table', true);
37858 tbl.setAttribute('width', '100%');
37866 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37869 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37871 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37873 tabPosition : "top",
37875 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37877 currentTabWidth : 0,
37879 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37883 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37887 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37889 preferredTabWidth : 175,
37891 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37893 resizeTabs : false,
37895 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37897 monitorResize : true,
37899 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37904 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37905 * @param {String} id The id of the div to use <b>or create</b>
37906 * @param {String} text The text for the tab
37907 * @param {String} content (optional) Content to put in the TabPanelItem body
37908 * @param {Boolean} closable (optional) True to create a close icon on the tab
37909 * @return {Roo.TabPanelItem} The created TabPanelItem
37911 addTab : function(id, text, content, closable, tpl)
37913 var item = new Roo.bootstrap.panel.TabItem({
37917 closable : closable,
37920 this.addTabItem(item);
37922 item.setContent(content);
37928 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37929 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37930 * @return {Roo.TabPanelItem}
37932 getTab : function(id){
37933 return this.items[id];
37937 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37938 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37940 hideTab : function(id){
37941 var t = this.items[id];
37944 this.hiddenCount++;
37945 this.autoSizeTabs();
37950 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37951 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37953 unhideTab : function(id){
37954 var t = this.items[id];
37956 t.setHidden(false);
37957 this.hiddenCount--;
37958 this.autoSizeTabs();
37963 * Adds an existing {@link Roo.TabPanelItem}.
37964 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37966 addTabItem : function(item){
37967 this.items[item.id] = item;
37968 this.items.push(item);
37969 // if(this.resizeTabs){
37970 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37971 // this.autoSizeTabs();
37973 // item.autoSize();
37978 * Removes a {@link Roo.TabPanelItem}.
37979 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37981 removeTab : function(id){
37982 var items = this.items;
37983 var tab = items[id];
37984 if(!tab) { return; }
37985 var index = items.indexOf(tab);
37986 if(this.active == tab && items.length > 1){
37987 var newTab = this.getNextAvailable(index);
37992 this.stripEl.dom.removeChild(tab.pnode.dom);
37993 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37994 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37996 items.splice(index, 1);
37997 delete this.items[tab.id];
37998 tab.fireEvent("close", tab);
37999 tab.purgeListeners();
38000 this.autoSizeTabs();
38003 getNextAvailable : function(start){
38004 var items = this.items;
38006 // look for a next tab that will slide over to
38007 // replace the one being removed
38008 while(index < items.length){
38009 var item = items[++index];
38010 if(item && !item.isHidden()){
38014 // if one isn't found select the previous tab (on the left)
38017 var item = items[--index];
38018 if(item && !item.isHidden()){
38026 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38027 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38029 disableTab : function(id){
38030 var tab = this.items[id];
38031 if(tab && this.active != tab){
38037 * Enables a {@link Roo.TabPanelItem} that is disabled.
38038 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38040 enableTab : function(id){
38041 var tab = this.items[id];
38046 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38047 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38048 * @return {Roo.TabPanelItem} The TabPanelItem.
38050 activate : function(id){
38051 var tab = this.items[id];
38055 if(tab == this.active || tab.disabled){
38059 this.fireEvent("beforetabchange", this, e, tab);
38060 if(e.cancel !== true && !tab.disabled){
38062 this.active.hide();
38064 this.active = this.items[id];
38065 this.active.show();
38066 this.fireEvent("tabchange", this, this.active);
38072 * Gets the active {@link Roo.TabPanelItem}.
38073 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38075 getActiveTab : function(){
38076 return this.active;
38080 * Updates the tab body element to fit the height of the container element
38081 * for overflow scrolling
38082 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38084 syncHeight : function(targetHeight){
38085 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38086 var bm = this.bodyEl.getMargins();
38087 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38088 this.bodyEl.setHeight(newHeight);
38092 onResize : function(){
38093 if(this.monitorResize){
38094 this.autoSizeTabs();
38099 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38101 beginUpdate : function(){
38102 this.updating = true;
38106 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38108 endUpdate : function(){
38109 this.updating = false;
38110 this.autoSizeTabs();
38114 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38116 autoSizeTabs : function(){
38117 var count = this.items.length;
38118 var vcount = count - this.hiddenCount;
38119 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38122 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38123 var availWidth = Math.floor(w / vcount);
38124 var b = this.stripBody;
38125 if(b.getWidth() > w){
38126 var tabs = this.items;
38127 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38128 if(availWidth < this.minTabWidth){
38129 /*if(!this.sleft){ // incomplete scrolling code
38130 this.createScrollButtons();
38133 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38136 if(this.currentTabWidth < this.preferredTabWidth){
38137 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38143 * Returns the number of tabs in this TabPanel.
38146 getCount : function(){
38147 return this.items.length;
38151 * Resizes all the tabs to the passed width
38152 * @param {Number} The new width
38154 setTabWidth : function(width){
38155 this.currentTabWidth = width;
38156 for(var i = 0, len = this.items.length; i < len; i++) {
38157 if(!this.items[i].isHidden()) {
38158 this.items[i].setWidth(width);
38164 * Destroys this TabPanel
38165 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38167 destroy : function(removeEl){
38168 Roo.EventManager.removeResizeListener(this.onResize, this);
38169 for(var i = 0, len = this.items.length; i < len; i++){
38170 this.items[i].purgeListeners();
38172 if(removeEl === true){
38173 this.el.update("");
38178 createStrip : function(container)
38180 var strip = document.createElement("nav");
38181 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38182 container.appendChild(strip);
38186 createStripList : function(strip)
38188 // div wrapper for retard IE
38189 // returns the "tr" element.
38190 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38191 //'<div class="x-tabs-strip-wrap">'+
38192 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38193 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38194 return strip.firstChild; //.firstChild.firstChild.firstChild;
38196 createBody : function(container)
38198 var body = document.createElement("div");
38199 Roo.id(body, "tab-body");
38200 //Roo.fly(body).addClass("x-tabs-body");
38201 Roo.fly(body).addClass("tab-content");
38202 container.appendChild(body);
38205 createItemBody :function(bodyEl, id){
38206 var body = Roo.getDom(id);
38208 body = document.createElement("div");
38211 //Roo.fly(body).addClass("x-tabs-item-body");
38212 Roo.fly(body).addClass("tab-pane");
38213 bodyEl.insertBefore(body, bodyEl.firstChild);
38217 createStripElements : function(stripEl, text, closable, tpl)
38219 var td = document.createElement("li"); // was td..
38222 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38225 stripEl.appendChild(td);
38227 td.className = "x-tabs-closable";
38228 if(!this.closeTpl){
38229 this.closeTpl = new Roo.Template(
38230 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38231 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38232 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38235 var el = this.closeTpl.overwrite(td, {"text": text});
38236 var close = el.getElementsByTagName("div")[0];
38237 var inner = el.getElementsByTagName("em")[0];
38238 return {"el": el, "close": close, "inner": inner};
38241 // not sure what this is..
38242 // if(!this.tabTpl){
38243 //this.tabTpl = new Roo.Template(
38244 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38245 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38247 // this.tabTpl = new Roo.Template(
38248 // '<a href="#">' +
38249 // '<span unselectable="on"' +
38250 // (this.disableTooltips ? '' : ' title="{text}"') +
38251 // ' >{text}</span></a>'
38257 var template = tpl || this.tabTpl || false;
38261 template = new Roo.Template(
38263 '<span unselectable="on"' +
38264 (this.disableTooltips ? '' : ' title="{text}"') +
38265 ' >{text}</span></a>'
38269 switch (typeof(template)) {
38273 template = new Roo.Template(template);
38279 var el = template.overwrite(td, {"text": text});
38281 var inner = el.getElementsByTagName("span")[0];
38283 return {"el": el, "inner": inner};
38291 * @class Roo.TabPanelItem
38292 * @extends Roo.util.Observable
38293 * Represents an individual item (tab plus body) in a TabPanel.
38294 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38295 * @param {String} id The id of this TabPanelItem
38296 * @param {String} text The text for the tab of this TabPanelItem
38297 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38299 Roo.bootstrap.panel.TabItem = function(config){
38301 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38302 * @type Roo.TabPanel
38304 this.tabPanel = config.panel;
38306 * The id for this TabPanelItem
38309 this.id = config.id;
38311 this.disabled = false;
38313 this.text = config.text;
38315 this.loaded = false;
38316 this.closable = config.closable;
38319 * The body element for this TabPanelItem.
38320 * @type Roo.Element
38322 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38323 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38324 this.bodyEl.setStyle("display", "block");
38325 this.bodyEl.setStyle("zoom", "1");
38326 //this.hideAction();
38328 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38330 this.el = Roo.get(els.el);
38331 this.inner = Roo.get(els.inner, true);
38332 this.textEl = Roo.get(this.el.dom.firstChild, true);
38333 this.pnode = Roo.get(els.el.parentNode, true);
38334 // this.el.on("mousedown", this.onTabMouseDown, this);
38335 this.el.on("click", this.onTabClick, this);
38337 if(config.closable){
38338 var c = Roo.get(els.close, true);
38339 c.dom.title = this.closeText;
38340 c.addClassOnOver("close-over");
38341 c.on("click", this.closeClick, this);
38347 * Fires when this tab becomes the active tab.
38348 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38349 * @param {Roo.TabPanelItem} this
38353 * @event beforeclose
38354 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38355 * @param {Roo.TabPanelItem} this
38356 * @param {Object} e Set cancel to true on this object to cancel the close.
38358 "beforeclose": true,
38361 * Fires when this tab is closed.
38362 * @param {Roo.TabPanelItem} this
38366 * @event deactivate
38367 * Fires when this tab is no longer the active tab.
38368 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38369 * @param {Roo.TabPanelItem} this
38371 "deactivate" : true
38373 this.hidden = false;
38375 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38378 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38380 purgeListeners : function(){
38381 Roo.util.Observable.prototype.purgeListeners.call(this);
38382 this.el.removeAllListeners();
38385 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38388 this.pnode.addClass("active");
38391 this.tabPanel.stripWrap.repaint();
38393 this.fireEvent("activate", this.tabPanel, this);
38397 * Returns true if this tab is the active tab.
38398 * @return {Boolean}
38400 isActive : function(){
38401 return this.tabPanel.getActiveTab() == this;
38405 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38408 this.pnode.removeClass("active");
38410 this.fireEvent("deactivate", this.tabPanel, this);
38413 hideAction : function(){
38414 this.bodyEl.hide();
38415 this.bodyEl.setStyle("position", "absolute");
38416 this.bodyEl.setLeft("-20000px");
38417 this.bodyEl.setTop("-20000px");
38420 showAction : function(){
38421 this.bodyEl.setStyle("position", "relative");
38422 this.bodyEl.setTop("");
38423 this.bodyEl.setLeft("");
38424 this.bodyEl.show();
38428 * Set the tooltip for the tab.
38429 * @param {String} tooltip The tab's tooltip
38431 setTooltip : function(text){
38432 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38433 this.textEl.dom.qtip = text;
38434 this.textEl.dom.removeAttribute('title');
38436 this.textEl.dom.title = text;
38440 onTabClick : function(e){
38441 e.preventDefault();
38442 this.tabPanel.activate(this.id);
38445 onTabMouseDown : function(e){
38446 e.preventDefault();
38447 this.tabPanel.activate(this.id);
38450 getWidth : function(){
38451 return this.inner.getWidth();
38454 setWidth : function(width){
38455 var iwidth = width - this.pnode.getPadding("lr");
38456 this.inner.setWidth(iwidth);
38457 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38458 this.pnode.setWidth(width);
38462 * Show or hide the tab
38463 * @param {Boolean} hidden True to hide or false to show.
38465 setHidden : function(hidden){
38466 this.hidden = hidden;
38467 this.pnode.setStyle("display", hidden ? "none" : "");
38471 * Returns true if this tab is "hidden"
38472 * @return {Boolean}
38474 isHidden : function(){
38475 return this.hidden;
38479 * Returns the text for this tab
38482 getText : function(){
38486 autoSize : function(){
38487 //this.el.beginMeasure();
38488 this.textEl.setWidth(1);
38490 * #2804 [new] Tabs in Roojs
38491 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38493 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38494 //this.el.endMeasure();
38498 * Sets the text for the tab (Note: this also sets the tooltip text)
38499 * @param {String} text The tab's text and tooltip
38501 setText : function(text){
38503 this.textEl.update(text);
38504 this.setTooltip(text);
38505 //if(!this.tabPanel.resizeTabs){
38506 // this.autoSize();
38510 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38512 activate : function(){
38513 this.tabPanel.activate(this.id);
38517 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38519 disable : function(){
38520 if(this.tabPanel.active != this){
38521 this.disabled = true;
38522 this.pnode.addClass("disabled");
38527 * Enables this TabPanelItem if it was previously disabled.
38529 enable : function(){
38530 this.disabled = false;
38531 this.pnode.removeClass("disabled");
38535 * Sets the content for this TabPanelItem.
38536 * @param {String} content The content
38537 * @param {Boolean} loadScripts true to look for and load scripts
38539 setContent : function(content, loadScripts){
38540 this.bodyEl.update(content, loadScripts);
38544 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38545 * @return {Roo.UpdateManager} The UpdateManager
38547 getUpdateManager : function(){
38548 return this.bodyEl.getUpdateManager();
38552 * Set a URL to be used to load the content for this TabPanelItem.
38553 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38554 * @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)
38555 * @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)
38556 * @return {Roo.UpdateManager} The UpdateManager
38558 setUrl : function(url, params, loadOnce){
38559 if(this.refreshDelegate){
38560 this.un('activate', this.refreshDelegate);
38562 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38563 this.on("activate", this.refreshDelegate);
38564 return this.bodyEl.getUpdateManager();
38568 _handleRefresh : function(url, params, loadOnce){
38569 if(!loadOnce || !this.loaded){
38570 var updater = this.bodyEl.getUpdateManager();
38571 updater.update(url, params, this._setLoaded.createDelegate(this));
38576 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38577 * Will fail silently if the setUrl method has not been called.
38578 * This does not activate the panel, just updates its content.
38580 refresh : function(){
38581 if(this.refreshDelegate){
38582 this.loaded = false;
38583 this.refreshDelegate();
38588 _setLoaded : function(){
38589 this.loaded = true;
38593 closeClick : function(e){
38596 this.fireEvent("beforeclose", this, o);
38597 if(o.cancel !== true){
38598 this.tabPanel.removeTab(this.id);
38602 * The text displayed in the tooltip for the close icon.
38605 closeText : "Close this tab"
38608 * This script refer to:
38609 * Title: International Telephone Input
38610 * Author: Jack O'Connor
38611 * Code version: v12.1.12
38612 * Availability: https://github.com/jackocnr/intl-tel-input.git
38615 Roo.bootstrap.PhoneInputData = function() {
38618 "Afghanistan (افغانستان)",
38623 "Albania (Shqipëri)",
38628 "Algeria (الجزائر)",
38653 "Antigua and Barbuda",
38663 "Armenia (Հայաստան)",
38679 "Austria (Österreich)",
38684 "Azerbaijan (Azərbaycan)",
38694 "Bahrain (البحرين)",
38699 "Bangladesh (বাংলাদেশ)",
38709 "Belarus (Беларусь)",
38714 "Belgium (België)",
38744 "Bosnia and Herzegovina (Босна и Херцеговина)",
38759 "British Indian Ocean Territory",
38764 "British Virgin Islands",
38774 "Bulgaria (България)",
38784 "Burundi (Uburundi)",
38789 "Cambodia (កម្ពុជា)",
38794 "Cameroon (Cameroun)",
38803 ["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"]
38806 "Cape Verde (Kabu Verdi)",
38811 "Caribbean Netherlands",
38822 "Central African Republic (République centrafricaine)",
38842 "Christmas Island",
38848 "Cocos (Keeling) Islands",
38859 "Comoros (جزر القمر)",
38864 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38869 "Congo (Republic) (Congo-Brazzaville)",
38889 "Croatia (Hrvatska)",
38910 "Czech Republic (Česká republika)",
38915 "Denmark (Danmark)",
38930 "Dominican Republic (República Dominicana)",
38934 ["809", "829", "849"]
38952 "Equatorial Guinea (Guinea Ecuatorial)",
38972 "Falkland Islands (Islas Malvinas)",
38977 "Faroe Islands (Føroyar)",
38998 "French Guiana (Guyane française)",
39003 "French Polynesia (Polynésie française)",
39018 "Georgia (საქართველო)",
39023 "Germany (Deutschland)",
39043 "Greenland (Kalaallit Nunaat)",
39080 "Guinea-Bissau (Guiné Bissau)",
39105 "Hungary (Magyarország)",
39110 "Iceland (Ísland)",
39130 "Iraq (العراق)",
39146 "Israel (ישראל)",
39173 "Jordan (الأردن)",
39178 "Kazakhstan (Казахстан)",
39199 "Kuwait (الكويت)",
39204 "Kyrgyzstan (Кыргызстан)",
39214 "Latvia (Latvija)",
39219 "Lebanon (لبنان)",
39234 "Libya (ليبيا)",
39244 "Lithuania (Lietuva)",
39259 "Macedonia (FYROM) (Македонија)",
39264 "Madagascar (Madagasikara)",
39294 "Marshall Islands",
39304 "Mauritania (موريتانيا)",
39309 "Mauritius (Moris)",
39330 "Moldova (Republica Moldova)",
39340 "Mongolia (Монгол)",
39345 "Montenegro (Crna Gora)",
39355 "Morocco (المغرب)",
39361 "Mozambique (Moçambique)",
39366 "Myanmar (Burma) (မြန်မာ)",
39371 "Namibia (Namibië)",
39386 "Netherlands (Nederland)",
39391 "New Caledonia (Nouvelle-Calédonie)",
39426 "North Korea (조선 민주주의 인민 공화국)",
39431 "Northern Mariana Islands",
39447 "Pakistan (پاکستان)",
39457 "Palestine (فلسطين)",
39467 "Papua New Guinea",
39509 "Réunion (La Réunion)",
39515 "Romania (România)",
39531 "Saint Barthélemy",
39542 "Saint Kitts and Nevis",
39552 "Saint Martin (Saint-Martin (partie française))",
39558 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39563 "Saint Vincent and the Grenadines",
39578 "São Tomé and Príncipe (São Tomé e Príncipe)",
39583 "Saudi Arabia (المملكة العربية السعودية)",
39588 "Senegal (Sénégal)",
39618 "Slovakia (Slovensko)",
39623 "Slovenia (Slovenija)",
39633 "Somalia (Soomaaliya)",
39643 "South Korea (대한민국)",
39648 "South Sudan (جنوب السودان)",
39658 "Sri Lanka (ශ්රී ලංකාව)",
39663 "Sudan (السودان)",
39673 "Svalbard and Jan Mayen",
39684 "Sweden (Sverige)",
39689 "Switzerland (Schweiz)",
39694 "Syria (سوريا)",
39739 "Trinidad and Tobago",
39744 "Tunisia (تونس)",
39749 "Turkey (Türkiye)",
39759 "Turks and Caicos Islands",
39769 "U.S. Virgin Islands",
39779 "Ukraine (Україна)",
39784 "United Arab Emirates (الإمارات العربية المتحدة)",
39806 "Uzbekistan (Oʻzbekiston)",
39816 "Vatican City (Città del Vaticano)",
39827 "Vietnam (Việt Nam)",
39832 "Wallis and Futuna (Wallis-et-Futuna)",
39837 "Western Sahara (الصحراء الغربية)",
39843 "Yemen (اليمن)",
39867 * This script refer to:
39868 * Title: International Telephone Input
39869 * Author: Jack O'Connor
39870 * Code version: v12.1.12
39871 * Availability: https://github.com/jackocnr/intl-tel-input.git
39875 * @class Roo.bootstrap.PhoneInput
39876 * @extends Roo.bootstrap.TriggerField
39877 * An input with International dial-code selection
39879 * @cfg {String} defaultDialCode default '+852'
39880 * @cfg {Array} preferedCountries default []
39883 * Create a new PhoneInput.
39884 * @param {Object} config Configuration options
39887 Roo.bootstrap.PhoneInput = function(config) {
39888 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39891 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39893 listWidth: undefined,
39895 selectedClass: 'active',
39897 invalidClass : "has-warning",
39899 validClass: 'has-success',
39901 allowed: '0123456789',
39906 * @cfg {String} defaultDialCode The default dial code when initializing the input
39908 defaultDialCode: '+852',
39911 * @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
39913 preferedCountries: false,
39915 getAutoCreate : function()
39917 var data = Roo.bootstrap.PhoneInputData();
39918 var align = this.labelAlign || this.parentLabelAlign();
39921 this.allCountries = [];
39922 this.dialCodeMapping = [];
39924 for (var i = 0; i < data.length; i++) {
39926 this.allCountries[i] = {
39930 priority: c[3] || 0,
39931 areaCodes: c[4] || null
39933 this.dialCodeMapping[c[2]] = {
39936 priority: c[3] || 0,
39937 areaCodes: c[4] || null
39949 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39950 maxlength: this.max_length,
39951 cls : 'form-control tel-input',
39952 autocomplete: 'new-password'
39955 var hiddenInput = {
39958 cls: 'hidden-tel-input'
39962 hiddenInput.name = this.name;
39965 if (this.disabled) {
39966 input.disabled = true;
39969 var flag_container = {
39986 cls: this.hasFeedback ? 'has-feedback' : '',
39992 cls: 'dial-code-holder',
39999 cls: 'roo-select2-container input-group',
40006 if (this.fieldLabel.length) {
40009 tooltip: 'This field is required'
40015 cls: 'control-label',
40021 html: this.fieldLabel
40024 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40030 if(this.indicatorpos == 'right') {
40031 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40038 if(align == 'left') {
40046 if(this.labelWidth > 12){
40047 label.style = "width: " + this.labelWidth + 'px';
40049 if(this.labelWidth < 13 && this.labelmd == 0){
40050 this.labelmd = this.labelWidth;
40052 if(this.labellg > 0){
40053 label.cls += ' col-lg-' + this.labellg;
40054 input.cls += ' col-lg-' + (12 - this.labellg);
40056 if(this.labelmd > 0){
40057 label.cls += ' col-md-' + this.labelmd;
40058 container.cls += ' col-md-' + (12 - this.labelmd);
40060 if(this.labelsm > 0){
40061 label.cls += ' col-sm-' + this.labelsm;
40062 container.cls += ' col-sm-' + (12 - this.labelsm);
40064 if(this.labelxs > 0){
40065 label.cls += ' col-xs-' + this.labelxs;
40066 container.cls += ' col-xs-' + (12 - this.labelxs);
40076 var settings = this;
40078 ['xs','sm','md','lg'].map(function(size){
40079 if (settings[size]) {
40080 cfg.cls += ' col-' + size + '-' + settings[size];
40084 this.store = new Roo.data.Store({
40085 proxy : new Roo.data.MemoryProxy({}),
40086 reader : new Roo.data.JsonReader({
40097 'name' : 'dialCode',
40101 'name' : 'priority',
40105 'name' : 'areaCodes',
40112 if(!this.preferedCountries) {
40113 this.preferedCountries = [
40120 var p = this.preferedCountries.reverse();
40123 for (var i = 0; i < p.length; i++) {
40124 for (var j = 0; j < this.allCountries.length; j++) {
40125 if(this.allCountries[j].iso2 == p[i]) {
40126 var t = this.allCountries[j];
40127 this.allCountries.splice(j,1);
40128 this.allCountries.unshift(t);
40134 this.store.proxy.data = {
40136 data: this.allCountries
40142 initEvents : function()
40145 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40147 this.indicator = this.indicatorEl();
40148 this.flag = this.flagEl();
40149 this.dialCodeHolder = this.dialCodeHolderEl();
40151 this.trigger = this.el.select('div.flag-box',true).first();
40152 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40157 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40158 _this.list.setWidth(lw);
40161 this.list.on('mouseover', this.onViewOver, this);
40162 this.list.on('mousemove', this.onViewMove, this);
40163 this.inputEl().on("keyup", this.onKeyUp, this);
40164 this.inputEl().on("keypress", this.onKeyPress, this);
40166 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40168 this.view = new Roo.View(this.list, this.tpl, {
40169 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40172 this.view.on('click', this.onViewClick, this);
40173 this.setValue(this.defaultDialCode);
40176 onTriggerClick : function(e)
40178 Roo.log('trigger click');
40183 if(this.isExpanded()){
40185 this.hasFocus = false;
40187 this.store.load({});
40188 this.hasFocus = true;
40193 isExpanded : function()
40195 return this.list.isVisible();
40198 collapse : function()
40200 if(!this.isExpanded()){
40204 Roo.get(document).un('mousedown', this.collapseIf, this);
40205 Roo.get(document).un('mousewheel', this.collapseIf, this);
40206 this.fireEvent('collapse', this);
40210 expand : function()
40214 if(this.isExpanded() || !this.hasFocus){
40218 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40219 this.list.setWidth(lw);
40222 this.restrictHeight();
40224 Roo.get(document).on('mousedown', this.collapseIf, this);
40225 Roo.get(document).on('mousewheel', this.collapseIf, this);
40227 this.fireEvent('expand', this);
40230 restrictHeight : function()
40232 this.list.alignTo(this.inputEl(), this.listAlign);
40233 this.list.alignTo(this.inputEl(), this.listAlign);
40236 onViewOver : function(e, t)
40238 if(this.inKeyMode){
40241 var item = this.view.findItemFromChild(t);
40244 var index = this.view.indexOf(item);
40245 this.select(index, false);
40250 onViewClick : function(view, doFocus, el, e)
40252 var index = this.view.getSelectedIndexes()[0];
40254 var r = this.store.getAt(index);
40257 this.onSelect(r, index);
40259 if(doFocus !== false && !this.blockFocus){
40260 this.inputEl().focus();
40264 onViewMove : function(e, t)
40266 this.inKeyMode = false;
40269 select : function(index, scrollIntoView)
40271 this.selectedIndex = index;
40272 this.view.select(index);
40273 if(scrollIntoView !== false){
40274 var el = this.view.getNode(index);
40276 this.list.scrollChildIntoView(el, false);
40281 createList : function()
40283 this.list = Roo.get(document.body).createChild({
40285 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40286 style: 'display:none'
40289 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40292 collapseIf : function(e)
40294 var in_combo = e.within(this.el);
40295 var in_list = e.within(this.list);
40296 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40298 if (in_combo || in_list || is_list) {
40304 onSelect : function(record, index)
40306 if(this.fireEvent('beforeselect', this, record, index) !== false){
40308 this.setFlagClass(record.data.iso2);
40309 this.setDialCode(record.data.dialCode);
40310 this.hasFocus = false;
40312 this.fireEvent('select', this, record, index);
40316 flagEl : function()
40318 var flag = this.el.select('div.flag',true).first();
40325 dialCodeHolderEl : function()
40327 var d = this.el.select('input.dial-code-holder',true).first();
40334 setDialCode : function(v)
40336 this.dialCodeHolder.dom.value = '+'+v;
40339 setFlagClass : function(n)
40341 this.flag.dom.className = 'flag '+n;
40344 getValue : function()
40346 var v = this.inputEl().getValue();
40347 if(this.dialCodeHolder) {
40348 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40353 setValue : function(v)
40355 var d = this.getDialCode(v);
40357 //invalid dial code
40358 if(v.length == 0 || !d || d.length == 0) {
40360 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40361 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40367 this.setFlagClass(this.dialCodeMapping[d].iso2);
40368 this.setDialCode(d);
40369 this.inputEl().dom.value = v.replace('+'+d,'');
40370 this.hiddenEl().dom.value = this.getValue();
40375 getDialCode : function(v)
40379 if (v.length == 0) {
40380 return this.dialCodeHolder.dom.value;
40384 if (v.charAt(0) != "+") {
40387 var numericChars = "";
40388 for (var i = 1; i < v.length; i++) {
40389 var c = v.charAt(i);
40392 if (this.dialCodeMapping[numericChars]) {
40393 dialCode = v.substr(1, i);
40395 if (numericChars.length == 4) {
40405 this.setValue(this.defaultDialCode);
40409 hiddenEl : function()
40411 return this.el.select('input.hidden-tel-input',true).first();
40414 // after setting val
40415 onKeyUp : function(e){
40416 this.setValue(this.getValue());
40419 onKeyPress : function(e){
40420 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40427 * @class Roo.bootstrap.MoneyField
40428 * @extends Roo.bootstrap.ComboBox
40429 * Bootstrap MoneyField class
40432 * Create a new MoneyField.
40433 * @param {Object} config Configuration options
40436 Roo.bootstrap.MoneyField = function(config) {
40438 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40442 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40445 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40447 allowDecimals : true,
40449 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40451 decimalSeparator : ".",
40453 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40455 decimalPrecision : 0,
40457 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40459 allowNegative : true,
40461 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40465 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40467 minValue : Number.NEGATIVE_INFINITY,
40469 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40471 maxValue : Number.MAX_VALUE,
40473 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40475 minText : "The minimum value for this field is {0}",
40477 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40479 maxText : "The maximum value for this field is {0}",
40481 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40482 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40484 nanText : "{0} is not a valid number",
40486 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40490 * @cfg {String} defaults currency of the MoneyField
40491 * value should be in lkey
40493 defaultCurrency : false,
40495 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40497 thousandsDelimiter : false,
40499 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40510 getAutoCreate : function()
40512 var align = this.labelAlign || this.parentLabelAlign();
40524 cls : 'form-control roo-money-amount-input',
40525 autocomplete: 'new-password'
40528 var hiddenInput = {
40532 cls: 'hidden-number-input'
40535 if(this.max_length) {
40536 input.maxlength = this.max_length;
40540 hiddenInput.name = this.name;
40543 if (this.disabled) {
40544 input.disabled = true;
40547 var clg = 12 - this.inputlg;
40548 var cmd = 12 - this.inputmd;
40549 var csm = 12 - this.inputsm;
40550 var cxs = 12 - this.inputxs;
40554 cls : 'row roo-money-field',
40558 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40562 cls: 'roo-select2-container input-group',
40566 cls : 'form-control roo-money-currency-input',
40567 autocomplete: 'new-password',
40569 name : this.currencyName
40573 cls : 'input-group-addon',
40587 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40591 cls: this.hasFeedback ? 'has-feedback' : '',
40602 if (this.fieldLabel.length) {
40605 tooltip: 'This field is required'
40611 cls: 'control-label',
40617 html: this.fieldLabel
40620 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40626 if(this.indicatorpos == 'right') {
40627 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40634 if(align == 'left') {
40642 if(this.labelWidth > 12){
40643 label.style = "width: " + this.labelWidth + 'px';
40645 if(this.labelWidth < 13 && this.labelmd == 0){
40646 this.labelmd = this.labelWidth;
40648 if(this.labellg > 0){
40649 label.cls += ' col-lg-' + this.labellg;
40650 input.cls += ' col-lg-' + (12 - this.labellg);
40652 if(this.labelmd > 0){
40653 label.cls += ' col-md-' + this.labelmd;
40654 container.cls += ' col-md-' + (12 - this.labelmd);
40656 if(this.labelsm > 0){
40657 label.cls += ' col-sm-' + this.labelsm;
40658 container.cls += ' col-sm-' + (12 - this.labelsm);
40660 if(this.labelxs > 0){
40661 label.cls += ' col-xs-' + this.labelxs;
40662 container.cls += ' col-xs-' + (12 - this.labelxs);
40673 var settings = this;
40675 ['xs','sm','md','lg'].map(function(size){
40676 if (settings[size]) {
40677 cfg.cls += ' col-' + size + '-' + settings[size];
40684 initEvents : function()
40686 this.indicator = this.indicatorEl();
40688 this.initCurrencyEvent();
40690 this.initNumberEvent();
40693 initCurrencyEvent : function()
40696 throw "can not find store for combo";
40699 this.store = Roo.factory(this.store, Roo.data);
40700 this.store.parent = this;
40704 this.triggerEl = this.el.select('.input-group-addon', true).first();
40706 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40711 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40712 _this.list.setWidth(lw);
40715 this.list.on('mouseover', this.onViewOver, this);
40716 this.list.on('mousemove', this.onViewMove, this);
40717 this.list.on('scroll', this.onViewScroll, this);
40720 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40723 this.view = new Roo.View(this.list, this.tpl, {
40724 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40727 this.view.on('click', this.onViewClick, this);
40729 this.store.on('beforeload', this.onBeforeLoad, this);
40730 this.store.on('load', this.onLoad, this);
40731 this.store.on('loadexception', this.onLoadException, this);
40733 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40734 "up" : function(e){
40735 this.inKeyMode = true;
40739 "down" : function(e){
40740 if(!this.isExpanded()){
40741 this.onTriggerClick();
40743 this.inKeyMode = true;
40748 "enter" : function(e){
40751 if(this.fireEvent("specialkey", this, e)){
40752 this.onViewClick(false);
40758 "esc" : function(e){
40762 "tab" : function(e){
40765 if(this.fireEvent("specialkey", this, e)){
40766 this.onViewClick(false);
40774 doRelay : function(foo, bar, hname){
40775 if(hname == 'down' || this.scope.isExpanded()){
40776 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40784 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40788 initNumberEvent : function(e)
40790 this.inputEl().on("keydown" , this.fireKey, this);
40791 this.inputEl().on("focus", this.onFocus, this);
40792 this.inputEl().on("blur", this.onBlur, this);
40794 this.inputEl().relayEvent('keyup', this);
40796 if(this.indicator){
40797 this.indicator.addClass('invisible');
40800 this.originalValue = this.getValue();
40802 if(this.validationEvent == 'keyup'){
40803 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40804 this.inputEl().on('keyup', this.filterValidation, this);
40806 else if(this.validationEvent !== false){
40807 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40810 if(this.selectOnFocus){
40811 this.on("focus", this.preFocus, this);
40814 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40815 this.inputEl().on("keypress", this.filterKeys, this);
40817 this.inputEl().relayEvent('keypress', this);
40820 var allowed = "0123456789";
40822 if(this.allowDecimals){
40823 allowed += this.decimalSeparator;
40826 if(this.allowNegative){
40830 if(this.thousandsDelimiter) {
40834 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40836 var keyPress = function(e){
40838 var k = e.getKey();
40840 var c = e.getCharCode();
40843 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40844 allowed.indexOf(String.fromCharCode(c)) === -1
40850 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40854 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40859 this.inputEl().on("keypress", keyPress, this);
40863 onTriggerClick : function(e)
40870 this.loadNext = false;
40872 if(this.isExpanded()){
40877 this.hasFocus = true;
40879 if(this.triggerAction == 'all') {
40880 this.doQuery(this.allQuery, true);
40884 this.doQuery(this.getRawValue());
40887 getCurrency : function()
40889 var v = this.currencyEl().getValue();
40894 restrictHeight : function()
40896 this.list.alignTo(this.currencyEl(), this.listAlign);
40897 this.list.alignTo(this.currencyEl(), this.listAlign);
40900 onViewClick : function(view, doFocus, el, e)
40902 var index = this.view.getSelectedIndexes()[0];
40904 var r = this.store.getAt(index);
40907 this.onSelect(r, index);
40911 onSelect : function(record, index){
40913 if(this.fireEvent('beforeselect', this, record, index) !== false){
40915 this.setFromCurrencyData(index > -1 ? record.data : false);
40919 this.fireEvent('select', this, record, index);
40923 setFromCurrencyData : function(o)
40927 this.lastCurrency = o;
40929 if (this.currencyField) {
40930 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40932 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40935 this.lastSelectionText = currency;
40937 //setting default currency
40938 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40939 this.setCurrency(this.defaultCurrency);
40943 this.setCurrency(currency);
40946 setFromData : function(o)
40950 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40952 this.setFromCurrencyData(c);
40957 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40959 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40962 this.setValue(value);
40966 setCurrency : function(v)
40968 this.currencyValue = v;
40971 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40976 setValue : function(v)
40978 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40984 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40986 this.inputEl().dom.value = (v == '') ? '' :
40987 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40989 if(!this.allowZero && v === '0') {
40990 this.hiddenEl().dom.value = '';
40991 this.inputEl().dom.value = '';
40998 getRawValue : function()
41000 var v = this.inputEl().getValue();
41005 getValue : function()
41007 return this.fixPrecision(this.parseValue(this.getRawValue()));
41010 parseValue : function(value)
41012 if(this.thousandsDelimiter) {
41014 r = new RegExp(",", "g");
41015 value = value.replace(r, "");
41018 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41019 return isNaN(value) ? '' : value;
41023 fixPrecision : function(value)
41025 if(this.thousandsDelimiter) {
41027 r = new RegExp(",", "g");
41028 value = value.replace(r, "");
41031 var nan = isNaN(value);
41033 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41034 return nan ? '' : value;
41036 return parseFloat(value).toFixed(this.decimalPrecision);
41039 decimalPrecisionFcn : function(v)
41041 return Math.floor(v);
41044 validateValue : function(value)
41046 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41050 var num = this.parseValue(value);
41053 this.markInvalid(String.format(this.nanText, value));
41057 if(num < this.minValue){
41058 this.markInvalid(String.format(this.minText, this.minValue));
41062 if(num > this.maxValue){
41063 this.markInvalid(String.format(this.maxText, this.maxValue));
41070 validate : function()
41072 if(this.disabled || this.allowBlank){
41077 var currency = this.getCurrency();
41079 if(this.validateValue(this.getRawValue()) && currency.length){
41084 this.markInvalid();
41088 getName: function()
41093 beforeBlur : function()
41099 var v = this.parseValue(this.getRawValue());
41106 onBlur : function()
41110 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41111 //this.el.removeClass(this.focusClass);
41114 this.hasFocus = false;
41116 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41120 var v = this.getValue();
41122 if(String(v) !== String(this.startValue)){
41123 this.fireEvent('change', this, v, this.startValue);
41126 this.fireEvent("blur", this);
41129 inputEl : function()
41131 return this.el.select('.roo-money-amount-input', true).first();
41134 currencyEl : function()
41136 return this.el.select('.roo-money-currency-input', true).first();
41139 hiddenEl : function()
41141 return this.el.select('input.hidden-number-input',true).first();