4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 Roo.log('start render...');
313 Roo.log(this[cntr](true));
315 if(this[cntr](true) === false){
319 cn.render && cn.render(this[cntr](true));
322 // then add the element..
330 if (typeof (tree.menu) != 'undefined') {
331 tree.menu.parentType = cn.xtype;
332 tree.menu.triggerEl = cn.el;
333 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
337 if (!tree.items || !tree.items.length) {
339 //Roo.log(["no children", this]);
344 var items = tree.items;
347 //Roo.log(items.length);
349 if (!skip_children) {
350 for(var i =0;i < items.length;i++) {
351 // Roo.log(['add child', items[i]]);
352 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
358 //Roo.log("fire childrenrendered");
360 cn.fireEvent('childrenrendered', this);
365 * Show a component - removes 'hidden' class
370 this.el.removeClass('hidden');
374 * Hide a component - adds 'hidden' class
378 if (this.el && !this.el.hasClass('hidden')) {
379 this.el.addClass('hidden');
392 * @class Roo.bootstrap.Body
393 * @extends Roo.bootstrap.Component
394 * Bootstrap Body class
398 * @param {Object} config The config object
401 Roo.bootstrap.Body = function(config){
403 config = config || {};
405 Roo.bootstrap.Body.superclass.constructor.call(this, config);
406 this.el = Roo.get(config.el ? config.el : document.body );
407 if (this.cls && this.cls.length) {
408 Roo.get(document.body).addClass(this.cls);
412 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
414 is_body : true,// just to make sure it's constructed?
419 onRender : function(ct, position)
421 /* Roo.log("Roo.bootstrap.Body - onRender");
422 if (this.cls && this.cls.length) {
423 Roo.get(document.body).addClass(this.cls);
442 * @class Roo.bootstrap.ButtonGroup
443 * @extends Roo.bootstrap.Component
444 * Bootstrap ButtonGroup class
445 * @cfg {String} size lg | sm | xs (default empty normal)
446 * @cfg {String} align vertical | justified (default none)
447 * @cfg {String} direction up | down (default down)
448 * @cfg {Boolean} toolbar false | true
449 * @cfg {Boolean} btn true | false
454 * @param {Object} config The config object
457 Roo.bootstrap.ButtonGroup = function(config){
458 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
461 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
469 getAutoCreate : function(){
475 cfg.html = this.html || cfg.html;
486 if (['vertical','justified'].indexOf(this.align)!==-1) {
487 cfg.cls = 'btn-group-' + this.align;
489 if (this.align == 'justified') {
490 console.log(this.items);
494 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
495 cfg.cls += ' btn-group-' + this.size;
498 if (this.direction == 'up') {
499 cfg.cls += ' dropup' ;
515 * @class Roo.bootstrap.Button
516 * @extends Roo.bootstrap.Component
517 * Bootstrap Button class
518 * @cfg {String} html The button content
519 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
520 * @cfg {String} size ( lg | sm | xs)
521 * @cfg {String} tag ( a | input | submit)
522 * @cfg {String} href empty or href
523 * @cfg {Boolean} disabled default false;
524 * @cfg {Boolean} isClose default false;
525 * @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)
526 * @cfg {String} badge text for badge
527 * @cfg {String} theme default
528 * @cfg {Boolean} inverse
529 * @cfg {Boolean} toggle
530 * @cfg {String} ontext text for on toggle state
531 * @cfg {String} offtext text for off toggle state
532 * @cfg {Boolean} defaulton
533 * @cfg {Boolean} preventDefault default true
534 * @cfg {Boolean} removeClass remove the standard class..
535 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
538 * Create a new button
539 * @param {Object} config The config object
543 Roo.bootstrap.Button = function(config){
544 Roo.bootstrap.Button.superclass.constructor.call(this, config);
545 this.weightClass = ["btn-default",
557 * When a butotn is pressed
558 * @param {Roo.bootstrap.Button} this
559 * @param {Roo.EventObject} e
564 * After the button has been toggles
565 * @param {Roo.EventObject} e
566 * @param {boolean} pressed (also available as button.pressed)
572 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
590 preventDefault: true,
599 getAutoCreate : function(){
607 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
608 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
613 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
615 if (this.toggle == true) {
618 cls: 'slider-frame roo-button',
623 'data-off-text':'OFF',
624 cls: 'slider-button',
630 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
631 cfg.cls += ' '+this.weight;
640 cfg["aria-hidden"] = true;
642 cfg.html = "×";
648 if (this.theme==='default') {
649 cfg.cls = 'btn roo-button';
651 //if (this.parentType != 'Navbar') {
652 this.weight = this.weight.length ? this.weight : 'default';
654 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
656 cfg.cls += ' btn-' + this.weight;
658 } else if (this.theme==='glow') {
661 cfg.cls = 'btn-glow roo-button';
663 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
665 cfg.cls += ' ' + this.weight;
671 this.cls += ' inverse';
676 cfg.cls += ' active';
680 cfg.disabled = 'disabled';
684 Roo.log('changing to ul' );
686 this.glyphicon = 'caret';
689 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
691 //gsRoo.log(this.parentType);
692 if (this.parentType === 'Navbar' && !this.parent().bar) {
693 Roo.log('changing to li?');
702 href : this.href || '#'
705 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
706 cfg.cls += ' dropdown';
713 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
715 if (this.glyphicon) {
716 cfg.html = ' ' + cfg.html;
721 cls: 'glyphicon glyphicon-' + this.glyphicon
731 // cfg.cls='btn roo-button';
735 var value = cfg.html;
740 cls: 'glyphicon glyphicon-' + this.glyphicon,
759 cfg.cls += ' dropdown';
760 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
763 if (cfg.tag !== 'a' && this.href !== '') {
764 throw "Tag must be a to set href.";
765 } else if (this.href.length > 0) {
766 cfg.href = this.href;
769 if(this.removeClass){
774 cfg.target = this.target;
779 initEvents: function() {
780 // Roo.log('init events?');
781 // Roo.log(this.el.dom);
784 if (typeof (this.menu) != 'undefined') {
785 this.menu.parentType = this.xtype;
786 this.menu.triggerEl = this.el;
787 this.addxtype(Roo.apply({}, this.menu));
791 if (this.el.hasClass('roo-button')) {
792 this.el.on('click', this.onClick, this);
794 this.el.select('.roo-button').on('click', this.onClick, this);
797 if(this.removeClass){
798 this.el.on('click', this.onClick, this);
801 this.el.enableDisplayMode();
804 onClick : function(e)
811 Roo.log('button on click ');
812 if(this.preventDefault){
815 if (this.pressed === true || this.pressed === false) {
816 this.pressed = !this.pressed;
817 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
818 this.fireEvent('toggle', this, e, this.pressed);
822 this.fireEvent('click', this, e);
826 * Enables this button
830 this.disabled = false;
831 this.el.removeClass('disabled');
835 * Disable this button
839 this.disabled = true;
840 this.el.addClass('disabled');
843 * sets the active state on/off,
844 * @param {Boolean} state (optional) Force a particular state
846 setActive : function(v) {
848 this.el[v ? 'addClass' : 'removeClass']('active');
851 * toggles the current active state
853 toggleActive : function()
855 var active = this.el.hasClass('active');
856 this.setActive(!active);
860 setText : function(str)
862 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
866 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
877 setWeight : function(str)
879 this.el.removeClass(this.weightClass);
880 this.el.addClass('btn-' + str);
894 * @class Roo.bootstrap.Column
895 * @extends Roo.bootstrap.Component
896 * Bootstrap Column class
897 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
898 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
899 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
900 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
901 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
902 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
903 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
904 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
907 * @cfg {Boolean} hidden (true|false) hide the element
908 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
909 * @cfg {String} fa (ban|check|...) font awesome icon
910 * @cfg {Number} fasize (1|2|....) font awsome size
912 * @cfg {String} icon (info-sign|check|...) glyphicon name
914 * @cfg {String} html content of column.
917 * Create a new Column
918 * @param {Object} config The config object
921 Roo.bootstrap.Column = function(config){
922 Roo.bootstrap.Column.superclass.constructor.call(this, config);
925 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
943 getAutoCreate : function(){
944 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
952 ['xs','sm','md','lg'].map(function(size){
953 //Roo.log( size + ':' + settings[size]);
955 if (settings[size+'off'] !== false) {
956 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
959 if (settings[size] === false) {
963 if (!settings[size]) { // 0 = hidden
964 cfg.cls += ' hidden-' + size;
967 cfg.cls += ' col-' + size + '-' + settings[size];
972 cfg.cls += ' hidden';
975 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
976 cfg.cls +=' alert alert-' + this.alert;
980 if (this.html.length) {
981 cfg.html = this.html;
985 if (this.fasize > 1) {
986 fasize = ' fa-' + this.fasize + 'x';
988 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
993 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1012 * @class Roo.bootstrap.Container
1013 * @extends Roo.bootstrap.Component
1014 * Bootstrap Container class
1015 * @cfg {Boolean} jumbotron is it a jumbotron element
1016 * @cfg {String} html content of element
1017 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1018 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1019 * @cfg {String} header content of header (for panel)
1020 * @cfg {String} footer content of footer (for panel)
1021 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1022 * @cfg {String} tag (header|aside|section) type of HTML tag.
1023 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1024 * @cfg {String} fa font awesome icon
1025 * @cfg {String} icon (info-sign|check|...) glyphicon name
1026 * @cfg {Boolean} hidden (true|false) hide the element
1027 * @cfg {Boolean} expandable (true|false) default false
1028 * @cfg {Boolean} expanded (true|false) default true
1029 * @cfg {String} rheader contet on the right of header
1030 * @cfg {Boolean} clickable (true|false) default false
1034 * Create a new Container
1035 * @param {Object} config The config object
1038 Roo.bootstrap.Container = function(config){
1039 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1045 * After the panel has been expand
1047 * @param {Roo.bootstrap.Container} this
1052 * After the panel has been collapsed
1054 * @param {Roo.bootstrap.Container} this
1059 * When a element is chick
1060 * @param {Roo.bootstrap.Container} this
1061 * @param {Roo.EventObject} e
1067 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1085 getChildContainer : function() {
1091 if (this.panel.length) {
1092 return this.el.select('.panel-body',true).first();
1099 getAutoCreate : function(){
1102 tag : this.tag || 'div',
1106 if (this.jumbotron) {
1107 cfg.cls = 'jumbotron';
1112 // - this is applied by the parent..
1114 // cfg.cls = this.cls + '';
1117 if (this.sticky.length) {
1119 var bd = Roo.get(document.body);
1120 if (!bd.hasClass('bootstrap-sticky')) {
1121 bd.addClass('bootstrap-sticky');
1122 Roo.select('html',true).setStyle('height', '100%');
1125 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1129 if (this.well.length) {
1130 switch (this.well) {
1133 cfg.cls +=' well well-' +this.well;
1142 cfg.cls += ' hidden';
1146 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1147 cfg.cls +=' alert alert-' + this.alert;
1152 if (this.panel.length) {
1153 cfg.cls += ' panel panel-' + this.panel;
1155 if (this.header.length) {
1159 if(this.expandable){
1161 cfg.cls = cfg.cls + ' expandable';
1165 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1173 cls : 'panel-title',
1174 html : (this.expandable ? ' ' : '') + this.header
1178 cls: 'panel-header-right',
1184 cls : 'panel-heading',
1185 style : this.expandable ? 'cursor: pointer' : '',
1193 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1198 if (this.footer.length) {
1200 cls : 'panel-footer',
1209 body.html = this.html || cfg.html;
1210 // prefix with the icons..
1212 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1215 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1220 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1221 cfg.cls = 'container';
1227 initEvents: function()
1229 if(this.expandable){
1230 var headerEl = this.headerEl();
1233 headerEl.on('click', this.onToggleClick, this);
1238 this.el.on('click', this.onClick, this);
1243 onToggleClick : function()
1245 var headerEl = this.headerEl();
1261 if(this.fireEvent('expand', this)) {
1263 this.expanded = true;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1267 this.el.select('.panel-body',true).first().removeClass('hide');
1269 var toggleEl = this.toggleEl();
1275 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1280 collapse : function()
1282 if(this.fireEvent('collapse', this)) {
1284 this.expanded = false;
1286 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1287 this.el.select('.panel-body',true).first().addClass('hide');
1289 var toggleEl = this.toggleEl();
1295 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1299 toggleEl : function()
1301 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1305 return this.el.select('.panel-heading .fa',true).first();
1308 headerEl : function()
1310 if(!this.el || !this.panel.length || !this.header.length){
1314 return this.el.select('.panel-heading',true).first()
1319 if(!this.el || !this.panel.length){
1323 return this.el.select('.panel-body',true).first()
1326 titleEl : function()
1328 if(!this.el || !this.panel.length || !this.header.length){
1332 return this.el.select('.panel-title',true).first();
1335 setTitle : function(v)
1337 var titleEl = this.titleEl();
1343 titleEl.dom.innerHTML = v;
1346 getTitle : function()
1349 var titleEl = this.titleEl();
1355 return titleEl.dom.innerHTML;
1358 setRightTitle : function(v)
1360 var t = this.el.select('.panel-header-right',true).first();
1366 t.dom.innerHTML = v;
1369 onClick : function(e)
1373 this.fireEvent('click', this, e);
1387 * @class Roo.bootstrap.Img
1388 * @extends Roo.bootstrap.Component
1389 * Bootstrap Img class
1390 * @cfg {Boolean} imgResponsive false | true
1391 * @cfg {String} border rounded | circle | thumbnail
1392 * @cfg {String} src image source
1393 * @cfg {String} alt image alternative text
1394 * @cfg {String} href a tag href
1395 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1396 * @cfg {String} xsUrl xs image source
1397 * @cfg {String} smUrl sm image source
1398 * @cfg {String} mdUrl md image source
1399 * @cfg {String} lgUrl lg image source
1402 * Create a new Input
1403 * @param {Object} config The config object
1406 Roo.bootstrap.Img = function(config){
1407 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1413 * The img click event for the img.
1414 * @param {Roo.EventObject} e
1420 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1422 imgResponsive: true,
1432 getAutoCreate : function()
1434 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1435 return this.createSingleImg();
1440 cls: 'roo-image-responsive-group',
1445 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1447 if(!_this[size + 'Url']){
1453 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1454 html: _this.html || cfg.html,
1455 src: _this[size + 'Url']
1458 img.cls += ' roo-image-responsive-' + size;
1460 var s = ['xs', 'sm', 'md', 'lg'];
1462 s.splice(s.indexOf(size), 1);
1464 Roo.each(s, function(ss){
1465 img.cls += ' hidden-' + ss;
1468 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1469 cfg.cls += ' img-' + _this.border;
1473 cfg.alt = _this.alt;
1486 a.target = _this.target;
1490 cfg.cn.push((_this.href) ? a : img);
1497 createSingleImg : function()
1501 cls: (this.imgResponsive) ? 'img-responsive' : '',
1503 src : 'about:blank' // just incase src get's set to undefined?!?
1506 cfg.html = this.html || cfg.html;
1508 cfg.src = this.src || cfg.src;
1510 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1511 cfg.cls += ' img-' + this.border;
1528 a.target = this.target;
1533 return (this.href) ? a : cfg;
1536 initEvents: function()
1539 this.el.on('click', this.onClick, this);
1544 onClick : function(e)
1546 Roo.log('img onclick');
1547 this.fireEvent('click', this, e);
1550 * Sets the url of the image - used to update it
1551 * @param {String} url the url of the image
1554 setSrc : function(url)
1558 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1559 this.el.dom.src = url;
1563 this.el.select('img', true).first().dom.src = url;
1579 * @class Roo.bootstrap.Link
1580 * @extends Roo.bootstrap.Component
1581 * Bootstrap Link Class
1582 * @cfg {String} alt image alternative text
1583 * @cfg {String} href a tag href
1584 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1585 * @cfg {String} html the content of the link.
1586 * @cfg {String} anchor name for the anchor link
1587 * @cfg {String} fa - favicon
1589 * @cfg {Boolean} preventDefault (true | false) default false
1593 * Create a new Input
1594 * @param {Object} config The config object
1597 Roo.bootstrap.Link = function(config){
1598 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1604 * The img click event for the img.
1605 * @param {Roo.EventObject} e
1611 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1615 preventDefault: false,
1621 getAutoCreate : function()
1623 var html = this.html || '';
1625 if (this.fa !== false) {
1626 html = '<i class="fa fa-' + this.fa + '"></i>';
1631 // anchor's do not require html/href...
1632 if (this.anchor === false) {
1634 cfg.href = this.href || '#';
1636 cfg.name = this.anchor;
1637 if (this.html !== false || this.fa !== false) {
1640 if (this.href !== false) {
1641 cfg.href = this.href;
1645 if(this.alt !== false){
1650 if(this.target !== false) {
1651 cfg.target = this.target;
1657 initEvents: function() {
1659 if(!this.href || this.preventDefault){
1660 this.el.on('click', this.onClick, this);
1664 onClick : function(e)
1666 if(this.preventDefault){
1669 //Roo.log('img onclick');
1670 this.fireEvent('click', this, e);
1683 * @class Roo.bootstrap.Header
1684 * @extends Roo.bootstrap.Component
1685 * Bootstrap Header class
1686 * @cfg {String} html content of header
1687 * @cfg {Number} level (1|2|3|4|5|6) default 1
1690 * Create a new Header
1691 * @param {Object} config The config object
1695 Roo.bootstrap.Header = function(config){
1696 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1699 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1707 getAutoCreate : function(){
1712 tag: 'h' + (1 *this.level),
1713 html: this.html || ''
1725 * Ext JS Library 1.1.1
1726 * Copyright(c) 2006-2007, Ext JS, LLC.
1728 * Originally Released Under LGPL - original licence link has changed is not relivant.
1731 * <script type="text/javascript">
1735 * @class Roo.bootstrap.MenuMgr
1736 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1739 Roo.bootstrap.MenuMgr = function(){
1740 var menus, active, groups = {}, attached = false, lastShow = new Date();
1742 // private - called when first menu is created
1745 active = new Roo.util.MixedCollection();
1746 Roo.get(document).addKeyListener(27, function(){
1747 if(active.length > 0){
1755 if(active && active.length > 0){
1756 var c = active.clone();
1766 if(active.length < 1){
1767 Roo.get(document).un("mouseup", onMouseDown);
1775 var last = active.last();
1776 lastShow = new Date();
1779 Roo.get(document).on("mouseup", onMouseDown);
1784 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1785 m.parentMenu.activeChild = m;
1786 }else if(last && last.isVisible()){
1787 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1792 function onBeforeHide(m){
1794 m.activeChild.hide();
1796 if(m.autoHideTimer){
1797 clearTimeout(m.autoHideTimer);
1798 delete m.autoHideTimer;
1803 function onBeforeShow(m){
1804 var pm = m.parentMenu;
1805 if(!pm && !m.allowOtherMenus){
1807 }else if(pm && pm.activeChild && active != m){
1808 pm.activeChild.hide();
1812 // private this should really trigger on mouseup..
1813 function onMouseDown(e){
1814 Roo.log("on Mouse Up");
1816 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1817 Roo.log("MenuManager hideAll");
1826 function onBeforeCheck(mi, state){
1828 var g = groups[mi.group];
1829 for(var i = 0, l = g.length; i < l; i++){
1831 g[i].setChecked(false);
1840 * Hides all menus that are currently visible
1842 hideAll : function(){
1847 register : function(menu){
1851 menus[menu.id] = menu;
1852 menu.on("beforehide", onBeforeHide);
1853 menu.on("hide", onHide);
1854 menu.on("beforeshow", onBeforeShow);
1855 menu.on("show", onShow);
1857 if(g && menu.events["checkchange"]){
1861 groups[g].push(menu);
1862 menu.on("checkchange", onCheck);
1867 * Returns a {@link Roo.menu.Menu} object
1868 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1869 * be used to generate and return a new Menu instance.
1871 get : function(menu){
1872 if(typeof menu == "string"){ // menu id
1874 }else if(menu.events){ // menu instance
1877 /*else if(typeof menu.length == 'number'){ // array of menu items?
1878 return new Roo.bootstrap.Menu({items:menu});
1879 }else{ // otherwise, must be a config
1880 return new Roo.bootstrap.Menu(menu);
1887 unregister : function(menu){
1888 delete menus[menu.id];
1889 menu.un("beforehide", onBeforeHide);
1890 menu.un("hide", onHide);
1891 menu.un("beforeshow", onBeforeShow);
1892 menu.un("show", onShow);
1894 if(g && menu.events["checkchange"]){
1895 groups[g].remove(menu);
1896 menu.un("checkchange", onCheck);
1901 registerCheckable : function(menuItem){
1902 var g = menuItem.group;
1907 groups[g].push(menuItem);
1908 menuItem.on("beforecheckchange", onBeforeCheck);
1913 unregisterCheckable : function(menuItem){
1914 var g = menuItem.group;
1916 groups[g].remove(menuItem);
1917 menuItem.un("beforecheckchange", onBeforeCheck);
1929 * @class Roo.bootstrap.Menu
1930 * @extends Roo.bootstrap.Component
1931 * Bootstrap Menu class - container for MenuItems
1932 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1933 * @cfg {bool} hidden if the menu should be hidden when rendered.
1934 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1935 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1939 * @param {Object} config The config object
1943 Roo.bootstrap.Menu = function(config){
1944 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1945 if (this.registerMenu && this.type != 'treeview') {
1946 Roo.bootstrap.MenuMgr.register(this);
1951 * Fires before this menu is displayed
1952 * @param {Roo.menu.Menu} this
1957 * Fires before this menu is hidden
1958 * @param {Roo.menu.Menu} this
1963 * Fires after this menu is displayed
1964 * @param {Roo.menu.Menu} this
1969 * Fires after this menu is hidden
1970 * @param {Roo.menu.Menu} this
1975 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1976 * @param {Roo.menu.Menu} this
1977 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1978 * @param {Roo.EventObject} e
1983 * Fires when the mouse is hovering over this menu
1984 * @param {Roo.menu.Menu} this
1985 * @param {Roo.EventObject} e
1986 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1991 * Fires when the mouse exits this menu
1992 * @param {Roo.menu.Menu} this
1993 * @param {Roo.EventObject} e
1994 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1999 * Fires when a menu item contained in this menu is clicked
2000 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2001 * @param {Roo.EventObject} e
2005 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2008 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2012 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2015 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2017 registerMenu : true,
2019 menuItems :false, // stores the menu items..
2029 getChildContainer : function() {
2033 getAutoCreate : function(){
2035 //if (['right'].indexOf(this.align)!==-1) {
2036 // cfg.cn[1].cls += ' pull-right'
2042 cls : 'dropdown-menu' ,
2043 style : 'z-index:1000'
2047 if (this.type === 'submenu') {
2048 cfg.cls = 'submenu active';
2050 if (this.type === 'treeview') {
2051 cfg.cls = 'treeview-menu';
2056 initEvents : function() {
2058 // Roo.log("ADD event");
2059 // Roo.log(this.triggerEl.dom);
2061 this.triggerEl.on('click', this.onTriggerClick, this);
2063 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2065 this.triggerEl.addClass('dropdown-toggle');
2068 this.el.on('touchstart' , this.onTouch, this);
2070 this.el.on('click' , this.onClick, this);
2072 this.el.on("mouseover", this.onMouseOver, this);
2073 this.el.on("mouseout", this.onMouseOut, this);
2077 findTargetItem : function(e)
2079 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2083 //Roo.log(t); Roo.log(t.id);
2085 //Roo.log(this.menuitems);
2086 return this.menuitems.get(t.id);
2088 //return this.items.get(t.menuItemId);
2094 onTouch : function(e)
2096 Roo.log("menu.onTouch");
2097 //e.stopEvent(); this make the user popdown broken
2101 onClick : function(e)
2103 Roo.log("menu.onClick");
2105 var t = this.findTargetItem(e);
2106 if(!t || t.isContainer){
2111 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2112 if(t == this.activeItem && t.shouldDeactivate(e)){
2113 this.activeItem.deactivate();
2114 delete this.activeItem;
2118 this.setActiveItem(t, true);
2126 Roo.log('pass click event');
2130 this.fireEvent("click", this, t, e);
2134 if(!t.href.length || t.href == '#'){
2135 (function() { _this.hide(); }).defer(100);
2140 onMouseOver : function(e){
2141 var t = this.findTargetItem(e);
2144 // if(t.canActivate && !t.disabled){
2145 // this.setActiveItem(t, true);
2149 this.fireEvent("mouseover", this, e, t);
2151 isVisible : function(){
2152 return !this.hidden;
2154 onMouseOut : function(e){
2155 var t = this.findTargetItem(e);
2158 // if(t == this.activeItem && t.shouldDeactivate(e)){
2159 // this.activeItem.deactivate();
2160 // delete this.activeItem;
2163 this.fireEvent("mouseout", this, e, t);
2168 * Displays this menu relative to another element
2169 * @param {String/HTMLElement/Roo.Element} element The element to align to
2170 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2171 * the element (defaults to this.defaultAlign)
2172 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2174 show : function(el, pos, parentMenu){
2175 this.parentMenu = parentMenu;
2179 this.fireEvent("beforeshow", this);
2180 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2183 * Displays this menu at a specific xy position
2184 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2185 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2187 showAt : function(xy, parentMenu, /* private: */_e){
2188 this.parentMenu = parentMenu;
2193 this.fireEvent("beforeshow", this);
2194 //xy = this.el.adjustForConstraints(xy);
2198 this.hideMenuItems();
2199 this.hidden = false;
2200 this.triggerEl.addClass('open');
2202 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2203 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2206 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2211 this.fireEvent("show", this);
2217 this.doFocus.defer(50, this);
2221 doFocus : function(){
2223 this.focusEl.focus();
2228 * Hides this menu and optionally all parent menus
2229 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2231 hide : function(deep)
2234 this.hideMenuItems();
2235 if(this.el && this.isVisible()){
2236 this.fireEvent("beforehide", this);
2237 if(this.activeItem){
2238 this.activeItem.deactivate();
2239 this.activeItem = null;
2241 this.triggerEl.removeClass('open');;
2243 this.fireEvent("hide", this);
2245 if(deep === true && this.parentMenu){
2246 this.parentMenu.hide(true);
2250 onTriggerClick : function(e)
2252 Roo.log('trigger click');
2254 var target = e.getTarget();
2256 Roo.log(target.nodeName.toLowerCase());
2258 if(target.nodeName.toLowerCase() === 'i'){
2264 onTriggerPress : function(e)
2266 Roo.log('trigger press');
2267 //Roo.log(e.getTarget());
2268 // Roo.log(this.triggerEl.dom);
2270 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2271 var pel = Roo.get(e.getTarget());
2272 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2273 Roo.log('is treeview or dropdown?');
2277 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2281 if (this.isVisible()) {
2286 this.show(this.triggerEl, false, false);
2289 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2296 hideMenuItems : function()
2298 Roo.log("hide Menu Items");
2302 //$(backdrop).remove()
2303 this.el.select('.open',true).each(function(aa) {
2305 aa.removeClass('open');
2306 //var parent = getParent($(this))
2307 //var relatedTarget = { relatedTarget: this }
2309 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2310 //if (e.isDefaultPrevented()) return
2311 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2314 addxtypeChild : function (tree, cntr) {
2315 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2317 this.menuitems.add(comp);
2338 * @class Roo.bootstrap.MenuItem
2339 * @extends Roo.bootstrap.Component
2340 * Bootstrap MenuItem class
2341 * @cfg {String} html the menu label
2342 * @cfg {String} href the link
2343 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2344 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2345 * @cfg {Boolean} active used on sidebars to highlight active itesm
2346 * @cfg {String} fa favicon to show on left of menu item.
2347 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2351 * Create a new MenuItem
2352 * @param {Object} config The config object
2356 Roo.bootstrap.MenuItem = function(config){
2357 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2362 * The raw click event for the entire grid.
2363 * @param {Roo.bootstrap.MenuItem} this
2364 * @param {Roo.EventObject} e
2370 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2374 preventDefault: false,
2375 isContainer : false,
2379 getAutoCreate : function(){
2381 if(this.isContainer){
2384 cls: 'dropdown-menu-item'
2398 if (this.fa !== false) {
2401 cls : 'fa fa-' + this.fa
2410 cls: 'dropdown-menu-item',
2413 if (this.parent().type == 'treeview') {
2414 cfg.cls = 'treeview-menu';
2417 cfg.cls += ' active';
2422 anc.href = this.href || cfg.cn[0].href ;
2423 ctag.html = this.html || cfg.cn[0].html ;
2427 initEvents: function()
2429 if (this.parent().type == 'treeview') {
2430 this.el.select('a').on('click', this.onClick, this);
2434 this.menu.parentType = this.xtype;
2435 this.menu.triggerEl = this.el;
2436 this.menu = this.addxtype(Roo.apply({}, this.menu));
2440 onClick : function(e)
2442 Roo.log('item on click ');
2444 if(this.preventDefault){
2447 //this.parent().hideMenuItems();
2449 this.fireEvent('click', this, e);
2468 * @class Roo.bootstrap.MenuSeparator
2469 * @extends Roo.bootstrap.Component
2470 * Bootstrap MenuSeparator class
2473 * Create a new MenuItem
2474 * @param {Object} config The config object
2478 Roo.bootstrap.MenuSeparator = function(config){
2479 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2482 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2484 getAutoCreate : function(){
2503 * @class Roo.bootstrap.Modal
2504 * @extends Roo.bootstrap.Component
2505 * Bootstrap Modal class
2506 * @cfg {String} title Title of dialog
2507 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2508 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2509 * @cfg {Boolean} specificTitle default false
2510 * @cfg {Array} buttons Array of buttons or standard button set..
2511 * @cfg {String} buttonPosition (left|right|center) default right
2512 * @cfg {Boolean} animate default true
2513 * @cfg {Boolean} allow_close default true
2514 * @cfg {Boolean} fitwindow default false
2515 * @cfg {String} size (sm|lg) default empty
2519 * Create a new Modal Dialog
2520 * @param {Object} config The config object
2523 Roo.bootstrap.Modal = function(config){
2524 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2529 * The raw btnclick event for the button
2530 * @param {Roo.EventObject} e
2535 * Fire when dialog resize
2536 * @param {Roo.bootstrap.Modal} this
2537 * @param {Roo.EventObject} e
2541 this.buttons = this.buttons || [];
2544 this.tmpl = Roo.factory(this.tmpl);
2549 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2551 title : 'test dialog',
2561 specificTitle: false,
2563 buttonPosition: 'right',
2582 onRender : function(ct, position)
2584 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2587 var cfg = Roo.apply({}, this.getAutoCreate());
2590 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2592 //if (!cfg.name.length) {
2596 cfg.cls += ' ' + this.cls;
2599 cfg.style = this.style;
2601 this.el = Roo.get(document.body).createChild(cfg, position);
2603 //var type = this.el.dom.type;
2606 if(this.tabIndex !== undefined){
2607 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2610 this.dialogEl = this.el.select('.modal-dialog',true).first();
2611 this.bodyEl = this.el.select('.modal-body',true).first();
2612 this.closeEl = this.el.select('.modal-header .close', true).first();
2613 this.headerEl = this.el.select('.modal-header',true).first();
2614 this.titleEl = this.el.select('.modal-title',true).first();
2615 this.footerEl = this.el.select('.modal-footer',true).first();
2617 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2618 this.maskEl.enableDisplayMode("block");
2620 //this.el.addClass("x-dlg-modal");
2622 if (this.buttons.length) {
2623 Roo.each(this.buttons, function(bb) {
2624 var b = Roo.apply({}, bb);
2625 b.xns = b.xns || Roo.bootstrap;
2626 b.xtype = b.xtype || 'Button';
2627 if (typeof(b.listeners) == 'undefined') {
2628 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2631 var btn = Roo.factory(b);
2633 btn.render(this.el.select('.modal-footer div').first());
2637 // render the children.
2640 if(typeof(this.items) != 'undefined'){
2641 var items = this.items;
2644 for(var i =0;i < items.length;i++) {
2645 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2649 this.items = nitems;
2651 // where are these used - they used to be body/close/footer
2655 //this.el.addClass([this.fieldClass, this.cls]);
2659 getAutoCreate : function(){
2664 html : this.html || ''
2669 cls : 'modal-title',
2673 if(this.specificTitle){
2679 if (this.allow_close) {
2691 if(this.size.length){
2692 size = 'modal-' + this.size;
2697 style : 'display: none',
2700 cls: "modal-dialog " + size,
2703 cls : "modal-content",
2706 cls : 'modal-header',
2711 cls : 'modal-footer',
2715 cls: 'btn-' + this.buttonPosition
2732 modal.cls += ' fade';
2738 getChildContainer : function() {
2743 getButtonContainer : function() {
2744 return this.el.select('.modal-footer div',true).first();
2747 initEvents : function()
2749 if (this.allow_close) {
2750 this.closeEl.on('click', this.hide, this);
2752 Roo.EventManager.onWindowResize(this.resize, this, true);
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 if (this.fitwindow) {
2761 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2762 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2767 setSize : function(w,h)
2777 if (!this.rendered) {
2781 this.el.setStyle('display', 'block');
2783 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2786 this.el.addClass('in');
2789 this.el.addClass('in');
2793 // not sure how we can show data in here..
2795 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2798 Roo.get(document.body).addClass("x-body-masked");
2800 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2801 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2806 this.fireEvent('show', this);
2808 // set zindex here - otherwise it appears to be ignored...
2809 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2812 this.items.forEach( function(e) {
2813 e.layout ? e.layout() : false;
2821 if(this.fireEvent("beforehide", this) !== false){
2823 Roo.get(document.body).removeClass("x-body-masked");
2824 this.el.removeClass('in');
2825 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2827 if(this.animate){ // why
2829 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2831 this.el.setStyle('display', 'none');
2833 this.fireEvent('hide', this);
2837 addButton : function(str, cb)
2841 var b = Roo.apply({}, { html : str } );
2842 b.xns = b.xns || Roo.bootstrap;
2843 b.xtype = b.xtype || 'Button';
2844 if (typeof(b.listeners) == 'undefined') {
2845 b.listeners = { click : cb.createDelegate(this) };
2848 var btn = Roo.factory(b);
2850 btn.render(this.el.select('.modal-footer div').first());
2856 setDefaultButton : function(btn)
2858 //this.el.select('.modal-footer').()
2862 resizeTo: function(w,h)
2866 this.dialogEl.setWidth(w);
2867 if (this.diff === false) {
2868 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2871 this.bodyEl.setHeight(h-this.diff);
2873 this.fireEvent('resize', this);
2876 setContentSize : function(w, h)
2880 onButtonClick: function(btn,e)
2883 this.fireEvent('btnclick', btn.name, e);
2886 * Set the title of the Dialog
2887 * @param {String} str new Title
2889 setTitle: function(str) {
2890 this.titleEl.dom.innerHTML = str;
2893 * Set the body of the Dialog
2894 * @param {String} str new Title
2896 setBody: function(str) {
2897 this.bodyEl.dom.innerHTML = str;
2900 * Set the body of the Dialog using the template
2901 * @param {Obj} data - apply this data to the template and replace the body contents.
2903 applyBody: function(obj)
2906 Roo.log("Error - using apply Body without a template");
2909 this.tmpl.overwrite(this.bodyEl, obj);
2915 Roo.apply(Roo.bootstrap.Modal, {
2917 * Button config that displays a single OK button
2926 * Button config that displays Yes and No buttons
2942 * Button config that displays OK and Cancel buttons
2957 * Button config that displays Yes, No and Cancel buttons
2981 * messagebox - can be used as a replace
2985 * @class Roo.MessageBox
2986 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2990 Roo.Msg.alert('Status', 'Changes saved successfully.');
2992 // Prompt for user data:
2993 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2995 // process text value...
2999 // Show a dialog using config options:
3001 title:'Save Changes?',
3002 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3003 buttons: Roo.Msg.YESNOCANCEL,
3010 Roo.bootstrap.MessageBox = function(){
3011 var dlg, opt, mask, waitTimer;
3012 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3013 var buttons, activeTextEl, bwidth;
3017 var handleButton = function(button){
3019 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3023 var handleHide = function(){
3025 dlg.el.removeClass(opt.cls);
3028 // Roo.TaskMgr.stop(waitTimer);
3029 // waitTimer = null;
3034 var updateButtons = function(b){
3037 buttons["ok"].hide();
3038 buttons["cancel"].hide();
3039 buttons["yes"].hide();
3040 buttons["no"].hide();
3041 //dlg.footer.dom.style.display = 'none';
3044 dlg.footerEl.dom.style.display = '';
3045 for(var k in buttons){
3046 if(typeof buttons[k] != "function"){
3049 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3050 width += buttons[k].el.getWidth()+15;
3060 var handleEsc = function(d, k, e){
3061 if(opt && opt.closable !== false){
3071 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3072 * @return {Roo.BasicDialog} The BasicDialog element
3074 getDialog : function(){
3076 dlg = new Roo.bootstrap.Modal( {
3079 //constraintoviewport:false,
3081 //collapsible : false,
3086 //buttonAlign:"center",
3087 closeClick : function(){
3088 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3091 handleButton("cancel");
3096 dlg.on("hide", handleHide);
3098 //dlg.addKeyListener(27, handleEsc);
3100 this.buttons = buttons;
3101 var bt = this.buttonText;
3102 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3103 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3104 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3105 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3107 bodyEl = dlg.bodyEl.createChild({
3109 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3110 '<textarea class="roo-mb-textarea"></textarea>' +
3111 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3113 msgEl = bodyEl.dom.firstChild;
3114 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3115 textboxEl.enableDisplayMode();
3116 textboxEl.addKeyListener([10,13], function(){
3117 if(dlg.isVisible() && opt && opt.buttons){
3120 }else if(opt.buttons.yes){
3121 handleButton("yes");
3125 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3126 textareaEl.enableDisplayMode();
3127 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3128 progressEl.enableDisplayMode();
3130 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3131 var pf = progressEl.dom.firstChild;
3133 pp = Roo.get(pf.firstChild);
3134 pp.setHeight(pf.offsetHeight);
3142 * Updates the message box body text
3143 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3144 * the XHTML-compliant non-breaking space character '&#160;')
3145 * @return {Roo.MessageBox} This message box
3147 updateText : function(text)
3149 if(!dlg.isVisible() && !opt.width){
3150 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3151 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3153 msgEl.innerHTML = text || ' ';
3155 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3156 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3158 Math.min(opt.width || cw , this.maxWidth),
3159 Math.max(opt.minWidth || this.minWidth, bwidth)
3162 activeTextEl.setWidth(w);
3164 if(dlg.isVisible()){
3165 dlg.fixedcenter = false;
3167 // to big, make it scroll. = But as usual stupid IE does not support
3170 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3171 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3172 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3174 bodyEl.dom.style.height = '';
3175 bodyEl.dom.style.overflowY = '';
3178 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3180 bodyEl.dom.style.overflowX = '';
3183 dlg.setContentSize(w, bodyEl.getHeight());
3184 if(dlg.isVisible()){
3185 dlg.fixedcenter = true;
3191 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3192 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3193 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3194 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3195 * @return {Roo.MessageBox} This message box
3197 updateProgress : function(value, text){
3199 this.updateText(text);
3202 if (pp) { // weird bug on my firefox - for some reason this is not defined
3203 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3204 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3210 * Returns true if the message box is currently displayed
3211 * @return {Boolean} True if the message box is visible, else false
3213 isVisible : function(){
3214 return dlg && dlg.isVisible();
3218 * Hides the message box if it is displayed
3221 if(this.isVisible()){
3227 * Displays a new message box, or reinitializes an existing message box, based on the config options
3228 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3229 * The following config object properties are supported:
3231 Property Type Description
3232 ---------- --------------- ------------------------------------------------------------------------------------
3233 animEl String/Element An id or Element from which the message box should animate as it opens and
3234 closes (defaults to undefined)
3235 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3236 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3237 closable Boolean False to hide the top-right close button (defaults to true). Note that
3238 progress and wait dialogs will ignore this property and always hide the
3239 close button as they can only be closed programmatically.
3240 cls String A custom CSS class to apply to the message box element
3241 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3242 displayed (defaults to 75)
3243 fn Function A callback function to execute after closing the dialog. The arguments to the
3244 function will be btn (the name of the button that was clicked, if applicable,
3245 e.g. "ok"), and text (the value of the active text field, if applicable).
3246 Progress and wait dialogs will ignore this option since they do not respond to
3247 user actions and can only be closed programmatically, so any required function
3248 should be called by the same code after it closes the dialog.
3249 icon String A CSS class that provides a background image to be used as an icon for
3250 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3251 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3252 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3253 modal Boolean False to allow user interaction with the page while the message box is
3254 displayed (defaults to true)
3255 msg String A string that will replace the existing message box body text (defaults
3256 to the XHTML-compliant non-breaking space character ' ')
3257 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3258 progress Boolean True to display a progress bar (defaults to false)
3259 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3260 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3261 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3262 title String The title text
3263 value String The string value to set into the active textbox element if displayed
3264 wait Boolean True to display a progress bar (defaults to false)
3265 width Number The width of the dialog in pixels
3272 msg: 'Please enter your address:',
3274 buttons: Roo.MessageBox.OKCANCEL,
3277 animEl: 'addAddressBtn'
3280 * @param {Object} config Configuration options
3281 * @return {Roo.MessageBox} This message box
3283 show : function(options)
3286 // this causes nightmares if you show one dialog after another
3287 // especially on callbacks..
3289 if(this.isVisible()){
3292 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3293 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3294 Roo.log("New Dialog Message:" + options.msg )
3295 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3296 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3299 var d = this.getDialog();
3301 d.setTitle(opt.title || " ");
3302 d.closeEl.setDisplayed(opt.closable !== false);
3303 activeTextEl = textboxEl;
3304 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3309 textareaEl.setHeight(typeof opt.multiline == "number" ?
3310 opt.multiline : this.defaultTextHeight);
3311 activeTextEl = textareaEl;
3320 progressEl.setDisplayed(opt.progress === true);
3321 this.updateProgress(0);
3322 activeTextEl.dom.value = opt.value || "";
3324 dlg.setDefaultButton(activeTextEl);
3326 var bs = opt.buttons;
3330 }else if(bs && bs.yes){
3331 db = buttons["yes"];
3333 dlg.setDefaultButton(db);
3335 bwidth = updateButtons(opt.buttons);
3336 this.updateText(opt.msg);
3338 d.el.addClass(opt.cls);
3340 d.proxyDrag = opt.proxyDrag === true;
3341 d.modal = opt.modal !== false;
3342 d.mask = opt.modal !== false ? mask : false;
3344 // force it to the end of the z-index stack so it gets a cursor in FF
3345 document.body.appendChild(dlg.el.dom);
3346 d.animateTarget = null;
3347 d.show(options.animEl);
3353 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3354 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3355 * and closing the message box when the process is complete.
3356 * @param {String} title The title bar text
3357 * @param {String} msg The message box body text
3358 * @return {Roo.MessageBox} This message box
3360 progress : function(title, msg){
3367 minWidth: this.minProgressWidth,
3374 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3375 * If a callback function is passed it will be called after the user clicks the button, and the
3376 * id of the button that was clicked will be passed as the only parameter to the callback
3377 * (could also be the top-right close button).
3378 * @param {String} title The title bar text
3379 * @param {String} msg The message box body text
3380 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3381 * @param {Object} scope (optional) The scope of the callback function
3382 * @return {Roo.MessageBox} This message box
3384 alert : function(title, msg, fn, scope)
3399 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3400 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3401 * You are responsible for closing the message box when the process is complete.
3402 * @param {String} msg The message box body text
3403 * @param {String} title (optional) The title bar text
3404 * @return {Roo.MessageBox} This message box
3406 wait : function(msg, title){
3417 waitTimer = Roo.TaskMgr.start({
3419 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3427 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3428 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3429 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3430 * @param {String} title The title bar text
3431 * @param {String} msg The message box body text
3432 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3433 * @param {Object} scope (optional) The scope of the callback function
3434 * @return {Roo.MessageBox} This message box
3436 confirm : function(title, msg, fn, scope){
3440 buttons: this.YESNO,
3449 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3450 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3451 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3452 * (could also be the top-right close button) and the text that was entered will be passed as the two
3453 * parameters to the callback.
3454 * @param {String} title The title bar text
3455 * @param {String} msg The message box body text
3456 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3457 * @param {Object} scope (optional) The scope of the callback function
3458 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3459 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3460 * @return {Roo.MessageBox} This message box
3462 prompt : function(title, msg, fn, scope, multiline){
3466 buttons: this.OKCANCEL,
3471 multiline: multiline,
3478 * Button config that displays a single OK button
3483 * Button config that displays Yes and No buttons
3486 YESNO : {yes:true, no:true},
3488 * Button config that displays OK and Cancel buttons
3491 OKCANCEL : {ok:true, cancel:true},
3493 * Button config that displays Yes, No and Cancel buttons
3496 YESNOCANCEL : {yes:true, no:true, cancel:true},
3499 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3502 defaultTextHeight : 75,
3504 * The maximum width in pixels of the message box (defaults to 600)
3509 * The minimum width in pixels of the message box (defaults to 100)
3514 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3515 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3518 minProgressWidth : 250,
3520 * An object containing the default button text strings that can be overriden for localized language support.
3521 * Supported properties are: ok, cancel, yes and no.
3522 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3535 * Shorthand for {@link Roo.MessageBox}
3537 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3538 Roo.Msg = Roo.Msg || Roo.MessageBox;
3547 * @class Roo.bootstrap.Navbar
3548 * @extends Roo.bootstrap.Component
3549 * Bootstrap Navbar class
3552 * Create a new Navbar
3553 * @param {Object} config The config object
3557 Roo.bootstrap.Navbar = function(config){
3558 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3562 * @event beforetoggle
3563 * Fire before toggle the menu
3564 * @param {Roo.EventObject} e
3566 "beforetoggle" : true
3570 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3579 getAutoCreate : function(){
3582 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3586 initEvents :function ()
3588 //Roo.log(this.el.select('.navbar-toggle',true));
3589 this.el.select('.navbar-toggle',true).on('click', function() {
3590 if(this.fireEvent('beforetoggle', this) !== false){
3591 this.el.select('.navbar-collapse',true).toggleClass('in');
3601 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3603 var size = this.el.getSize();
3604 this.maskEl.setSize(size.width, size.height);
3605 this.maskEl.enableDisplayMode("block");
3614 getChildContainer : function()
3616 if (this.el.select('.collapse').getCount()) {
3617 return this.el.select('.collapse',true).first();
3650 * @class Roo.bootstrap.NavSimplebar
3651 * @extends Roo.bootstrap.Navbar
3652 * Bootstrap Sidebar class
3654 * @cfg {Boolean} inverse is inverted color
3656 * @cfg {String} type (nav | pills | tabs)
3657 * @cfg {Boolean} arrangement stacked | justified
3658 * @cfg {String} align (left | right) alignment
3660 * @cfg {Boolean} main (true|false) main nav bar? default false
3661 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3663 * @cfg {String} tag (header|footer|nav|div) default is nav
3669 * Create a new Sidebar
3670 * @param {Object} config The config object
3674 Roo.bootstrap.NavSimplebar = function(config){
3675 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3678 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3694 getAutoCreate : function(){
3698 tag : this.tag || 'div',
3711 this.type = this.type || 'nav';
3712 if (['tabs','pills'].indexOf(this.type)!==-1) {
3713 cfg.cn[0].cls += ' nav-' + this.type
3717 if (this.type!=='nav') {
3718 Roo.log('nav type must be nav/tabs/pills')
3720 cfg.cn[0].cls += ' navbar-nav'
3726 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3727 cfg.cn[0].cls += ' nav-' + this.arrangement;
3731 if (this.align === 'right') {
3732 cfg.cn[0].cls += ' navbar-right';
3736 cfg.cls += ' navbar-inverse';
3763 * @class Roo.bootstrap.NavHeaderbar
3764 * @extends Roo.bootstrap.NavSimplebar
3765 * Bootstrap Sidebar class
3767 * @cfg {String} brand what is brand
3768 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3769 * @cfg {String} brand_href href of the brand
3770 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3771 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3772 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3773 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3776 * Create a new Sidebar
3777 * @param {Object} config The config object
3781 Roo.bootstrap.NavHeaderbar = function(config){
3782 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3786 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3793 desktopCenter : false,
3796 getAutoCreate : function(){
3799 tag: this.nav || 'nav',
3806 if (this.desktopCenter) {
3807 cn.push({cls : 'container', cn : []});
3814 cls: 'navbar-header',
3819 cls: 'navbar-toggle',
3820 'data-toggle': 'collapse',
3825 html: 'Toggle navigation'
3847 cls: 'collapse navbar-collapse',
3851 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3853 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3854 cfg.cls += ' navbar-' + this.position;
3856 // tag can override this..
3858 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3861 if (this.brand !== '') {
3864 href: this.brand_href ? this.brand_href : '#',
3865 cls: 'navbar-brand',
3873 cfg.cls += ' main-nav';
3881 getHeaderChildContainer : function()
3883 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3884 return this.el.select('.navbar-header',true).first();
3887 return this.getChildContainer();
3891 initEvents : function()
3893 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3895 if (this.autohide) {
3900 Roo.get(document).on('scroll',function(e) {
3901 var ns = Roo.get(document).getScroll().top;
3902 var os = prevScroll;
3906 ft.removeClass('slideDown');
3907 ft.addClass('slideUp');
3910 ft.removeClass('slideUp');
3911 ft.addClass('slideDown');
3932 * @class Roo.bootstrap.NavSidebar
3933 * @extends Roo.bootstrap.Navbar
3934 * Bootstrap Sidebar class
3937 * Create a new Sidebar
3938 * @param {Object} config The config object
3942 Roo.bootstrap.NavSidebar = function(config){
3943 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3946 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3948 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3950 getAutoCreate : function(){
3955 cls: 'sidebar sidebar-nav'
3977 * @class Roo.bootstrap.NavGroup
3978 * @extends Roo.bootstrap.Component
3979 * Bootstrap NavGroup class
3980 * @cfg {String} align (left|right)
3981 * @cfg {Boolean} inverse
3982 * @cfg {String} type (nav|pills|tab) default nav
3983 * @cfg {String} navId - reference Id for navbar.
3987 * Create a new nav group
3988 * @param {Object} config The config object
3991 Roo.bootstrap.NavGroup = function(config){
3992 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3995 Roo.bootstrap.NavGroup.register(this);
3999 * Fires when the active item changes
4000 * @param {Roo.bootstrap.NavGroup} this
4001 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4002 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4009 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4020 getAutoCreate : function()
4022 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4029 if (['tabs','pills'].indexOf(this.type)!==-1) {
4030 cfg.cls += ' nav-' + this.type
4032 if (this.type!=='nav') {
4033 Roo.log('nav type must be nav/tabs/pills')
4035 cfg.cls += ' navbar-nav'
4038 if (this.parent() && this.parent().sidebar) {
4041 cls: 'dashboard-menu sidebar-menu'
4047 if (this.form === true) {
4053 if (this.align === 'right') {
4054 cfg.cls += ' navbar-right';
4056 cfg.cls += ' navbar-left';
4060 if (this.align === 'right') {
4061 cfg.cls += ' navbar-right';
4065 cfg.cls += ' navbar-inverse';
4073 * sets the active Navigation item
4074 * @param {Roo.bootstrap.NavItem} the new current navitem
4076 setActiveItem : function(item)
4079 Roo.each(this.navItems, function(v){
4084 v.setActive(false, true);
4091 item.setActive(true, true);
4092 this.fireEvent('changed', this, item, prev);
4097 * gets the active Navigation item
4098 * @return {Roo.bootstrap.NavItem} the current navitem
4100 getActive : function()
4104 Roo.each(this.navItems, function(v){
4115 indexOfNav : function()
4119 Roo.each(this.navItems, function(v,i){
4130 * adds a Navigation item
4131 * @param {Roo.bootstrap.NavItem} the navitem to add
4133 addItem : function(cfg)
4135 var cn = new Roo.bootstrap.NavItem(cfg);
4137 cn.parentId = this.id;
4138 cn.onRender(this.el, null);
4142 * register a Navigation item
4143 * @param {Roo.bootstrap.NavItem} the navitem to add
4145 register : function(item)
4147 this.navItems.push( item);
4148 item.navId = this.navId;
4153 * clear all the Navigation item
4156 clearAll : function()
4159 this.el.dom.innerHTML = '';
4162 getNavItem: function(tabId)
4165 Roo.each(this.navItems, function(e) {
4166 if (e.tabId == tabId) {
4176 setActiveNext : function()
4178 var i = this.indexOfNav(this.getActive());
4179 if (i > this.navItems.length) {
4182 this.setActiveItem(this.navItems[i+1]);
4184 setActivePrev : function()
4186 var i = this.indexOfNav(this.getActive());
4190 this.setActiveItem(this.navItems[i-1]);
4192 clearWasActive : function(except) {
4193 Roo.each(this.navItems, function(e) {
4194 if (e.tabId != except.tabId && e.was_active) {
4195 e.was_active = false;
4202 getWasActive : function ()
4205 Roo.each(this.navItems, function(e) {
4220 Roo.apply(Roo.bootstrap.NavGroup, {
4224 * register a Navigation Group
4225 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4227 register : function(navgrp)
4229 this.groups[navgrp.navId] = navgrp;
4233 * fetch a Navigation Group based on the navigation ID
4234 * @param {string} the navgroup to add
4235 * @returns {Roo.bootstrap.NavGroup} the navgroup
4237 get: function(navId) {
4238 if (typeof(this.groups[navId]) == 'undefined') {
4240 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4242 return this.groups[navId] ;
4257 * @class Roo.bootstrap.NavItem
4258 * @extends Roo.bootstrap.Component
4259 * Bootstrap Navbar.NavItem class
4260 * @cfg {String} href link to
4261 * @cfg {String} html content of button
4262 * @cfg {String} badge text inside badge
4263 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4264 * @cfg {String} glyphicon name of glyphicon
4265 * @cfg {String} icon name of font awesome icon
4266 * @cfg {Boolean} active Is item active
4267 * @cfg {Boolean} disabled Is item disabled
4269 * @cfg {Boolean} preventDefault (true | false) default false
4270 * @cfg {String} tabId the tab that this item activates.
4271 * @cfg {String} tagtype (a|span) render as a href or span?
4272 * @cfg {Boolean} animateRef (true|false) link to element default false
4275 * Create a new Navbar Item
4276 * @param {Object} config The config object
4278 Roo.bootstrap.NavItem = function(config){
4279 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4284 * The raw click event for the entire grid.
4285 * @param {Roo.EventObject} e
4290 * Fires when the active item active state changes
4291 * @param {Roo.bootstrap.NavItem} this
4292 * @param {boolean} state the new state
4298 * Fires when scroll to element
4299 * @param {Roo.bootstrap.NavItem} this
4300 * @param {Object} options
4301 * @param {Roo.EventObject} e
4309 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4317 preventDefault : false,
4324 getAutoCreate : function(){
4333 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4335 if (this.disabled) {
4336 cfg.cls += ' disabled';
4339 if (this.href || this.html || this.glyphicon || this.icon) {
4343 href : this.href || "#",
4344 html: this.html || ''
4349 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4352 if(this.glyphicon) {
4353 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4358 cfg.cn[0].html += " <span class='caret'></span>";
4362 if (this.badge !== '') {
4364 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4372 initEvents: function()
4374 if (typeof (this.menu) != 'undefined') {
4375 this.menu.parentType = this.xtype;
4376 this.menu.triggerEl = this.el;
4377 this.menu = this.addxtype(Roo.apply({}, this.menu));
4380 this.el.select('a',true).on('click', this.onClick, this);
4382 if(this.tagtype == 'span'){
4383 this.el.select('span',true).on('click', this.onClick, this);
4386 // at this point parent should be available..
4387 this.parent().register(this);
4390 onClick : function(e)
4392 if (e.getTarget('.dropdown-menu-item')) {
4393 // did you click on a menu itemm.... - then don't trigger onclick..
4398 this.preventDefault ||
4401 Roo.log("NavItem - prevent Default?");
4405 if (this.disabled) {
4409 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4410 if (tg && tg.transition) {
4411 Roo.log("waiting for the transitionend");
4417 //Roo.log("fire event clicked");
4418 if(this.fireEvent('click', this, e) === false){
4422 if(this.tagtype == 'span'){
4426 //Roo.log(this.href);
4427 var ael = this.el.select('a',true).first();
4430 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4431 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4432 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4433 return; // ignore... - it's a 'hash' to another page.
4435 Roo.log("NavItem - prevent Default?");
4437 this.scrollToElement(e);
4441 var p = this.parent();
4443 if (['tabs','pills'].indexOf(p.type)!==-1) {
4444 if (typeof(p.setActiveItem) !== 'undefined') {
4445 p.setActiveItem(this);
4449 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4450 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4451 // remove the collapsed menu expand...
4452 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4456 isActive: function () {
4459 setActive : function(state, fire, is_was_active)
4461 if (this.active && !state && this.navId) {
4462 this.was_active = true;
4463 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4465 nv.clearWasActive(this);
4469 this.active = state;
4472 this.el.removeClass('active');
4473 } else if (!this.el.hasClass('active')) {
4474 this.el.addClass('active');
4477 this.fireEvent('changed', this, state);
4480 // show a panel if it's registered and related..
4482 if (!this.navId || !this.tabId || !state || is_was_active) {
4486 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4490 var pan = tg.getPanelByName(this.tabId);
4494 // if we can not flip to new panel - go back to old nav highlight..
4495 if (false == tg.showPanel(pan)) {
4496 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4498 var onav = nv.getWasActive();
4500 onav.setActive(true, false, true);
4509 // this should not be here...
4510 setDisabled : function(state)
4512 this.disabled = state;
4514 this.el.removeClass('disabled');
4515 } else if (!this.el.hasClass('disabled')) {
4516 this.el.addClass('disabled');
4522 * Fetch the element to display the tooltip on.
4523 * @return {Roo.Element} defaults to this.el
4525 tooltipEl : function()
4527 return this.el.select('' + this.tagtype + '', true).first();
4530 scrollToElement : function(e)
4532 var c = document.body;
4535 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4537 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4538 c = document.documentElement;
4541 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4547 var o = target.calcOffsetsTo(c);
4554 this.fireEvent('scrollto', this, options, e);
4556 Roo.get(c).scrollTo('top', options.value, true);
4569 * <span> icon </span>
4570 * <span> text </span>
4571 * <span>badge </span>
4575 * @class Roo.bootstrap.NavSidebarItem
4576 * @extends Roo.bootstrap.NavItem
4577 * Bootstrap Navbar.NavSidebarItem class
4578 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4579 * {Boolean} open is the menu open
4580 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4581 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4582 * {String} buttonSize (sm|md|lg)the extra classes for the button
4583 * {Boolean} showArrow show arrow next to the text (default true)
4585 * Create a new Navbar Button
4586 * @param {Object} config The config object
4588 Roo.bootstrap.NavSidebarItem = function(config){
4589 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4594 * The raw click event for the entire grid.
4595 * @param {Roo.EventObject} e
4600 * Fires when the active item active state changes
4601 * @param {Roo.bootstrap.NavSidebarItem} this
4602 * @param {boolean} state the new state
4610 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4612 badgeWeight : 'default',
4618 buttonWeight : 'default',
4624 getAutoCreate : function(){
4629 href : this.href || '#',
4635 if(this.buttonView){
4638 href : this.href || '#',
4639 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4652 cfg.cls += ' active';
4655 if (this.disabled) {
4656 cfg.cls += ' disabled';
4659 cfg.cls += ' open x-open';
4662 if (this.glyphicon || this.icon) {
4663 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4664 a.cn.push({ tag : 'i', cls : c }) ;
4667 if(!this.buttonView){
4670 html : this.html || ''
4677 if (this.badge !== '') {
4678 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4684 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4687 a.cls += ' dropdown-toggle treeview' ;
4693 initEvents : function()
4695 if (typeof (this.menu) != 'undefined') {
4696 this.menu.parentType = this.xtype;
4697 this.menu.triggerEl = this.el;
4698 this.menu = this.addxtype(Roo.apply({}, this.menu));
4701 this.el.on('click', this.onClick, this);
4703 if(this.badge !== ''){
4704 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4709 onClick : function(e)
4716 if(this.preventDefault){
4720 this.fireEvent('click', this);
4723 disable : function()
4725 this.setDisabled(true);
4730 this.setDisabled(false);
4733 setDisabled : function(state)
4735 if(this.disabled == state){
4739 this.disabled = state;
4742 this.el.addClass('disabled');
4746 this.el.removeClass('disabled');
4751 setActive : function(state)
4753 if(this.active == state){
4757 this.active = state;
4760 this.el.addClass('active');
4764 this.el.removeClass('active');
4769 isActive: function ()
4774 setBadge : function(str)
4780 this.badgeEl.dom.innerHTML = str;
4797 * @class Roo.bootstrap.Row
4798 * @extends Roo.bootstrap.Component
4799 * Bootstrap Row class (contains columns...)
4803 * @param {Object} config The config object
4806 Roo.bootstrap.Row = function(config){
4807 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4810 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4812 getAutoCreate : function(){
4831 * @class Roo.bootstrap.Element
4832 * @extends Roo.bootstrap.Component
4833 * Bootstrap Element class
4834 * @cfg {String} html contents of the element
4835 * @cfg {String} tag tag of the element
4836 * @cfg {String} cls class of the element
4837 * @cfg {Boolean} preventDefault (true|false) default false
4838 * @cfg {Boolean} clickable (true|false) default false
4841 * Create a new Element
4842 * @param {Object} config The config object
4845 Roo.bootstrap.Element = function(config){
4846 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4852 * When a element is chick
4853 * @param {Roo.bootstrap.Element} this
4854 * @param {Roo.EventObject} e
4860 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4865 preventDefault: false,
4868 getAutoCreate : function(){
4879 initEvents: function()
4881 Roo.bootstrap.Element.superclass.initEvents.call(this);
4884 this.el.on('click', this.onClick, this);
4889 onClick : function(e)
4891 if(this.preventDefault){
4895 this.fireEvent('click', this, e);
4898 getValue : function()
4900 return this.el.dom.innerHTML;
4903 setValue : function(value)
4905 this.el.dom.innerHTML = value;
4920 * @class Roo.bootstrap.Pagination
4921 * @extends Roo.bootstrap.Component
4922 * Bootstrap Pagination class
4923 * @cfg {String} size xs | sm | md | lg
4924 * @cfg {Boolean} inverse false | true
4927 * Create a new Pagination
4928 * @param {Object} config The config object
4931 Roo.bootstrap.Pagination = function(config){
4932 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4935 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4941 getAutoCreate : function(){
4947 cfg.cls += ' inverse';
4953 cfg.cls += " " + this.cls;
4971 * @class Roo.bootstrap.PaginationItem
4972 * @extends Roo.bootstrap.Component
4973 * Bootstrap PaginationItem class
4974 * @cfg {String} html text
4975 * @cfg {String} href the link
4976 * @cfg {Boolean} preventDefault (true | false) default true
4977 * @cfg {Boolean} active (true | false) default false
4978 * @cfg {Boolean} disabled default false
4982 * Create a new PaginationItem
4983 * @param {Object} config The config object
4987 Roo.bootstrap.PaginationItem = function(config){
4988 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4993 * The raw click event for the entire grid.
4994 * @param {Roo.EventObject} e
5000 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5004 preventDefault: true,
5009 getAutoCreate : function(){
5015 href : this.href ? this.href : '#',
5016 html : this.html ? this.html : ''
5026 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5030 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5036 initEvents: function() {
5038 this.el.on('click', this.onClick, this);
5041 onClick : function(e)
5043 Roo.log('PaginationItem on click ');
5044 if(this.preventDefault){
5052 this.fireEvent('click', this, e);
5068 * @class Roo.bootstrap.Slider
5069 * @extends Roo.bootstrap.Component
5070 * Bootstrap Slider class
5073 * Create a new Slider
5074 * @param {Object} config The config object
5077 Roo.bootstrap.Slider = function(config){
5078 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5081 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5083 getAutoCreate : function(){
5087 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5091 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5103 * Ext JS Library 1.1.1
5104 * Copyright(c) 2006-2007, Ext JS, LLC.
5106 * Originally Released Under LGPL - original licence link has changed is not relivant.
5109 * <script type="text/javascript">
5114 * @class Roo.grid.ColumnModel
5115 * @extends Roo.util.Observable
5116 * This is the default implementation of a ColumnModel used by the Grid. It defines
5117 * the columns in the grid.
5120 var colModel = new Roo.grid.ColumnModel([
5121 {header: "Ticker", width: 60, sortable: true, locked: true},
5122 {header: "Company Name", width: 150, sortable: true},
5123 {header: "Market Cap.", width: 100, sortable: true},
5124 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5125 {header: "Employees", width: 100, sortable: true, resizable: false}
5130 * The config options listed for this class are options which may appear in each
5131 * individual column definition.
5132 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5134 * @param {Object} config An Array of column config objects. See this class's
5135 * config objects for details.
5137 Roo.grid.ColumnModel = function(config){
5139 * The config passed into the constructor
5141 this.config = config;
5144 // if no id, create one
5145 // if the column does not have a dataIndex mapping,
5146 // map it to the order it is in the config
5147 for(var i = 0, len = config.length; i < len; i++){
5149 if(typeof c.dataIndex == "undefined"){
5152 if(typeof c.renderer == "string"){
5153 c.renderer = Roo.util.Format[c.renderer];
5155 if(typeof c.id == "undefined"){
5158 if(c.editor && c.editor.xtype){
5159 c.editor = Roo.factory(c.editor, Roo.grid);
5161 if(c.editor && c.editor.isFormField){
5162 c.editor = new Roo.grid.GridEditor(c.editor);
5164 this.lookup[c.id] = c;
5168 * The width of columns which have no width specified (defaults to 100)
5171 this.defaultWidth = 100;
5174 * Default sortable of columns which have no sortable specified (defaults to false)
5177 this.defaultSortable = false;
5181 * @event widthchange
5182 * Fires when the width of a column changes.
5183 * @param {ColumnModel} this
5184 * @param {Number} columnIndex The column index
5185 * @param {Number} newWidth The new width
5187 "widthchange": true,
5189 * @event headerchange
5190 * Fires when the text of a header changes.
5191 * @param {ColumnModel} this
5192 * @param {Number} columnIndex The column index
5193 * @param {Number} newText The new header text
5195 "headerchange": true,
5197 * @event hiddenchange
5198 * Fires when a column is hidden or "unhidden".
5199 * @param {ColumnModel} this
5200 * @param {Number} columnIndex The column index
5201 * @param {Boolean} hidden true if hidden, false otherwise
5203 "hiddenchange": true,
5205 * @event columnmoved
5206 * Fires when a column is moved.
5207 * @param {ColumnModel} this
5208 * @param {Number} oldIndex
5209 * @param {Number} newIndex
5211 "columnmoved" : true,
5213 * @event columlockchange
5214 * Fires when a column's locked state is changed
5215 * @param {ColumnModel} this
5216 * @param {Number} colIndex
5217 * @param {Boolean} locked true if locked
5219 "columnlockchange" : true
5221 Roo.grid.ColumnModel.superclass.constructor.call(this);
5223 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5225 * @cfg {String} header The header text to display in the Grid view.
5228 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5229 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5230 * specified, the column's index is used as an index into the Record's data Array.
5233 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5234 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5237 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5238 * Defaults to the value of the {@link #defaultSortable} property.
5239 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5242 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5245 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5248 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5251 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5254 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5255 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5256 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5257 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5260 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5263 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5266 * @cfg {String} cursor (Optional)
5269 * @cfg {String} tooltip (Optional)
5272 * @cfg {Number} xs (Optional)
5275 * @cfg {Number} sm (Optional)
5278 * @cfg {Number} md (Optional)
5281 * @cfg {Number} lg (Optional)
5284 * Returns the id of the column at the specified index.
5285 * @param {Number} index The column index
5286 * @return {String} the id
5288 getColumnId : function(index){
5289 return this.config[index].id;
5293 * Returns the column for a specified id.
5294 * @param {String} id The column id
5295 * @return {Object} the column
5297 getColumnById : function(id){
5298 return this.lookup[id];
5303 * Returns the column for a specified dataIndex.
5304 * @param {String} dataIndex The column dataIndex
5305 * @return {Object|Boolean} the column or false if not found
5307 getColumnByDataIndex: function(dataIndex){
5308 var index = this.findColumnIndex(dataIndex);
5309 return index > -1 ? this.config[index] : false;
5313 * Returns the index for a specified column id.
5314 * @param {String} id The column id
5315 * @return {Number} the index, or -1 if not found
5317 getIndexById : function(id){
5318 for(var i = 0, len = this.config.length; i < len; i++){
5319 if(this.config[i].id == id){
5327 * Returns the index for a specified column dataIndex.
5328 * @param {String} dataIndex The column dataIndex
5329 * @return {Number} the index, or -1 if not found
5332 findColumnIndex : function(dataIndex){
5333 for(var i = 0, len = this.config.length; i < len; i++){
5334 if(this.config[i].dataIndex == dataIndex){
5342 moveColumn : function(oldIndex, newIndex){
5343 var c = this.config[oldIndex];
5344 this.config.splice(oldIndex, 1);
5345 this.config.splice(newIndex, 0, c);
5346 this.dataMap = null;
5347 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5350 isLocked : function(colIndex){
5351 return this.config[colIndex].locked === true;
5354 setLocked : function(colIndex, value, suppressEvent){
5355 if(this.isLocked(colIndex) == value){
5358 this.config[colIndex].locked = value;
5360 this.fireEvent("columnlockchange", this, colIndex, value);
5364 getTotalLockedWidth : function(){
5366 for(var i = 0; i < this.config.length; i++){
5367 if(this.isLocked(i) && !this.isHidden(i)){
5368 this.totalWidth += this.getColumnWidth(i);
5374 getLockedCount : function(){
5375 for(var i = 0, len = this.config.length; i < len; i++){
5376 if(!this.isLocked(i)){
5381 return this.config.length;
5385 * Returns the number of columns.
5388 getColumnCount : function(visibleOnly){
5389 if(visibleOnly === true){
5391 for(var i = 0, len = this.config.length; i < len; i++){
5392 if(!this.isHidden(i)){
5398 return this.config.length;
5402 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5403 * @param {Function} fn
5404 * @param {Object} scope (optional)
5405 * @return {Array} result
5407 getColumnsBy : function(fn, scope){
5409 for(var i = 0, len = this.config.length; i < len; i++){
5410 var c = this.config[i];
5411 if(fn.call(scope||this, c, i) === true){
5419 * Returns true if the specified column is sortable.
5420 * @param {Number} col The column index
5423 isSortable : function(col){
5424 if(typeof this.config[col].sortable == "undefined"){
5425 return this.defaultSortable;
5427 return this.config[col].sortable;
5431 * Returns the rendering (formatting) function defined for the column.
5432 * @param {Number} col The column index.
5433 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5435 getRenderer : function(col){
5436 if(!this.config[col].renderer){
5437 return Roo.grid.ColumnModel.defaultRenderer;
5439 return this.config[col].renderer;
5443 * Sets the rendering (formatting) function for a column.
5444 * @param {Number} col The column index
5445 * @param {Function} fn The function to use to process the cell's raw data
5446 * to return HTML markup for the grid view. The render function is called with
5447 * the following parameters:<ul>
5448 * <li>Data value.</li>
5449 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5450 * <li>css A CSS style string to apply to the table cell.</li>
5451 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5452 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5453 * <li>Row index</li>
5454 * <li>Column index</li>
5455 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5457 setRenderer : function(col, fn){
5458 this.config[col].renderer = fn;
5462 * Returns the width for the specified column.
5463 * @param {Number} col The column index
5466 getColumnWidth : function(col){
5467 return this.config[col].width * 1 || this.defaultWidth;
5471 * Sets the width for a column.
5472 * @param {Number} col The column index
5473 * @param {Number} width The new width
5475 setColumnWidth : function(col, width, suppressEvent){
5476 this.config[col].width = width;
5477 this.totalWidth = null;
5479 this.fireEvent("widthchange", this, col, width);
5484 * Returns the total width of all columns.
5485 * @param {Boolean} includeHidden True to include hidden column widths
5488 getTotalWidth : function(includeHidden){
5489 if(!this.totalWidth){
5490 this.totalWidth = 0;
5491 for(var i = 0, len = this.config.length; i < len; i++){
5492 if(includeHidden || !this.isHidden(i)){
5493 this.totalWidth += this.getColumnWidth(i);
5497 return this.totalWidth;
5501 * Returns the header for the specified column.
5502 * @param {Number} col The column index
5505 getColumnHeader : function(col){
5506 return this.config[col].header;
5510 * Sets the header for a column.
5511 * @param {Number} col The column index
5512 * @param {String} header The new header
5514 setColumnHeader : function(col, header){
5515 this.config[col].header = header;
5516 this.fireEvent("headerchange", this, col, header);
5520 * Returns the tooltip for the specified column.
5521 * @param {Number} col The column index
5524 getColumnTooltip : function(col){
5525 return this.config[col].tooltip;
5528 * Sets the tooltip for a column.
5529 * @param {Number} col The column index
5530 * @param {String} tooltip The new tooltip
5532 setColumnTooltip : function(col, tooltip){
5533 this.config[col].tooltip = tooltip;
5537 * Returns the dataIndex for the specified column.
5538 * @param {Number} col The column index
5541 getDataIndex : function(col){
5542 return this.config[col].dataIndex;
5546 * Sets the dataIndex for a column.
5547 * @param {Number} col The column index
5548 * @param {Number} dataIndex The new dataIndex
5550 setDataIndex : function(col, dataIndex){
5551 this.config[col].dataIndex = dataIndex;
5557 * Returns true if the cell is editable.
5558 * @param {Number} colIndex The column index
5559 * @param {Number} rowIndex The row index - this is nto actually used..?
5562 isCellEditable : function(colIndex, rowIndex){
5563 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5567 * Returns the editor defined for the cell/column.
5568 * return false or null to disable editing.
5569 * @param {Number} colIndex The column index
5570 * @param {Number} rowIndex The row index
5573 getCellEditor : function(colIndex, rowIndex){
5574 return this.config[colIndex].editor;
5578 * Sets if a column is editable.
5579 * @param {Number} col The column index
5580 * @param {Boolean} editable True if the column is editable
5582 setEditable : function(col, editable){
5583 this.config[col].editable = editable;
5588 * Returns true if the column is hidden.
5589 * @param {Number} colIndex The column index
5592 isHidden : function(colIndex){
5593 return this.config[colIndex].hidden;
5598 * Returns true if the column width cannot be changed
5600 isFixed : function(colIndex){
5601 return this.config[colIndex].fixed;
5605 * Returns true if the column can be resized
5608 isResizable : function(colIndex){
5609 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5612 * Sets if a column is hidden.
5613 * @param {Number} colIndex The column index
5614 * @param {Boolean} hidden True if the column is hidden
5616 setHidden : function(colIndex, hidden){
5617 this.config[colIndex].hidden = hidden;
5618 this.totalWidth = null;
5619 this.fireEvent("hiddenchange", this, colIndex, hidden);
5623 * Sets the editor for a column.
5624 * @param {Number} col The column index
5625 * @param {Object} editor The editor object
5627 setEditor : function(col, editor){
5628 this.config[col].editor = editor;
5632 Roo.grid.ColumnModel.defaultRenderer = function(value)
5634 if(typeof value == "object") {
5637 if(typeof value == "string" && value.length < 1){
5641 return String.format("{0}", value);
5644 // Alias for backwards compatibility
5645 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5648 * Ext JS Library 1.1.1
5649 * Copyright(c) 2006-2007, Ext JS, LLC.
5651 * Originally Released Under LGPL - original licence link has changed is not relivant.
5654 * <script type="text/javascript">
5658 * @class Roo.LoadMask
5659 * A simple utility class for generically masking elements while loading data. If the element being masked has
5660 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5661 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5662 * element's UpdateManager load indicator and will be destroyed after the initial load.
5664 * Create a new LoadMask
5665 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5666 * @param {Object} config The config object
5668 Roo.LoadMask = function(el, config){
5669 this.el = Roo.get(el);
5670 Roo.apply(this, config);
5672 this.store.on('beforeload', this.onBeforeLoad, this);
5673 this.store.on('load', this.onLoad, this);
5674 this.store.on('loadexception', this.onLoadException, this);
5675 this.removeMask = false;
5677 var um = this.el.getUpdateManager();
5678 um.showLoadIndicator = false; // disable the default indicator
5679 um.on('beforeupdate', this.onBeforeLoad, this);
5680 um.on('update', this.onLoad, this);
5681 um.on('failure', this.onLoad, this);
5682 this.removeMask = true;
5686 Roo.LoadMask.prototype = {
5688 * @cfg {Boolean} removeMask
5689 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5690 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5694 * The text to display in a centered loading message box (defaults to 'Loading...')
5698 * @cfg {String} msgCls
5699 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5701 msgCls : 'x-mask-loading',
5704 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5710 * Disables the mask to prevent it from being displayed
5712 disable : function(){
5713 this.disabled = true;
5717 * Enables the mask so that it can be displayed
5719 enable : function(){
5720 this.disabled = false;
5723 onLoadException : function()
5727 if (typeof(arguments[3]) != 'undefined') {
5728 Roo.MessageBox.alert("Error loading",arguments[3]);
5732 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5733 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5740 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5745 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5749 onBeforeLoad : function(){
5751 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5756 destroy : function(){
5758 this.store.un('beforeload', this.onBeforeLoad, this);
5759 this.store.un('load', this.onLoad, this);
5760 this.store.un('loadexception', this.onLoadException, this);
5762 var um = this.el.getUpdateManager();
5763 um.un('beforeupdate', this.onBeforeLoad, this);
5764 um.un('update', this.onLoad, this);
5765 um.un('failure', this.onLoad, this);
5776 * @class Roo.bootstrap.Table
5777 * @extends Roo.bootstrap.Component
5778 * Bootstrap Table class
5779 * @cfg {String} cls table class
5780 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5781 * @cfg {String} bgcolor Specifies the background color for a table
5782 * @cfg {Number} border Specifies whether the table cells should have borders or not
5783 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5784 * @cfg {Number} cellspacing Specifies the space between cells
5785 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5786 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5787 * @cfg {String} sortable Specifies that the table should be sortable
5788 * @cfg {String} summary Specifies a summary of the content of a table
5789 * @cfg {Number} width Specifies the width of a table
5790 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5792 * @cfg {boolean} striped Should the rows be alternative striped
5793 * @cfg {boolean} bordered Add borders to the table
5794 * @cfg {boolean} hover Add hover highlighting
5795 * @cfg {boolean} condensed Format condensed
5796 * @cfg {boolean} responsive Format condensed
5797 * @cfg {Boolean} loadMask (true|false) default false
5798 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5799 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5800 * @cfg {Boolean} rowSelection (true|false) default false
5801 * @cfg {Boolean} cellSelection (true|false) default false
5802 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5803 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5804 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5808 * Create a new Table
5809 * @param {Object} config The config object
5812 Roo.bootstrap.Table = function(config){
5813 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5818 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5819 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5820 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5821 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5823 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5825 this.sm.grid = this;
5826 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5827 this.sm = this.selModel;
5828 this.sm.xmodule = this.xmodule || false;
5831 if (this.cm && typeof(this.cm.config) == 'undefined') {
5832 this.colModel = new Roo.grid.ColumnModel(this.cm);
5833 this.cm = this.colModel;
5834 this.cm.xmodule = this.xmodule || false;
5837 this.store= Roo.factory(this.store, Roo.data);
5838 this.ds = this.store;
5839 this.ds.xmodule = this.xmodule || false;
5842 if (this.footer && this.store) {
5843 this.footer.dataSource = this.ds;
5844 this.footer = Roo.factory(this.footer);
5851 * Fires when a cell is clicked
5852 * @param {Roo.bootstrap.Table} this
5853 * @param {Roo.Element} el
5854 * @param {Number} rowIndex
5855 * @param {Number} columnIndex
5856 * @param {Roo.EventObject} e
5860 * @event celldblclick
5861 * Fires when a cell is double clicked
5862 * @param {Roo.bootstrap.Table} this
5863 * @param {Roo.Element} el
5864 * @param {Number} rowIndex
5865 * @param {Number} columnIndex
5866 * @param {Roo.EventObject} e
5868 "celldblclick" : true,
5871 * Fires when a row is clicked
5872 * @param {Roo.bootstrap.Table} this
5873 * @param {Roo.Element} el
5874 * @param {Number} rowIndex
5875 * @param {Roo.EventObject} e
5879 * @event rowdblclick
5880 * Fires when a row is double clicked
5881 * @param {Roo.bootstrap.Table} this
5882 * @param {Roo.Element} el
5883 * @param {Number} rowIndex
5884 * @param {Roo.EventObject} e
5886 "rowdblclick" : true,
5889 * Fires when a mouseover occur
5890 * @param {Roo.bootstrap.Table} this
5891 * @param {Roo.Element} el
5892 * @param {Number} rowIndex
5893 * @param {Number} columnIndex
5894 * @param {Roo.EventObject} e
5899 * Fires when a mouseout occur
5900 * @param {Roo.bootstrap.Table} this
5901 * @param {Roo.Element} el
5902 * @param {Number} rowIndex
5903 * @param {Number} columnIndex
5904 * @param {Roo.EventObject} e
5909 * Fires when a row is rendered, so you can change add a style to it.
5910 * @param {Roo.bootstrap.Table} this
5911 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5915 * @event rowsrendered
5916 * Fires when all the rows have been rendered
5917 * @param {Roo.bootstrap.Table} this
5919 'rowsrendered' : true,
5921 * @event contextmenu
5922 * The raw contextmenu event for the entire grid.
5923 * @param {Roo.EventObject} e
5925 "contextmenu" : true,
5927 * @event rowcontextmenu
5928 * Fires when a row is right clicked
5929 * @param {Roo.bootstrap.Table} this
5930 * @param {Number} rowIndex
5931 * @param {Roo.EventObject} e
5933 "rowcontextmenu" : true,
5935 * @event cellcontextmenu
5936 * Fires when a cell is right clicked
5937 * @param {Roo.bootstrap.Table} this
5938 * @param {Number} rowIndex
5939 * @param {Number} cellIndex
5940 * @param {Roo.EventObject} e
5942 "cellcontextmenu" : true,
5944 * @event headercontextmenu
5945 * Fires when a header is right clicked
5946 * @param {Roo.bootstrap.Table} this
5947 * @param {Number} columnIndex
5948 * @param {Roo.EventObject} e
5950 "headercontextmenu" : true
5954 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5980 rowSelection : false,
5981 cellSelection : false,
5984 // Roo.Element - the tbody
5986 // Roo.Element - thead element
5989 container: false, // used by gridpanel...
5993 getAutoCreate : function()
5995 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6002 if (this.scrollBody) {
6003 cfg.cls += ' table-body-fixed';
6006 cfg.cls += ' table-striped';
6010 cfg.cls += ' table-hover';
6012 if (this.bordered) {
6013 cfg.cls += ' table-bordered';
6015 if (this.condensed) {
6016 cfg.cls += ' table-condensed';
6018 if (this.responsive) {
6019 cfg.cls += ' table-responsive';
6023 cfg.cls+= ' ' +this.cls;
6026 // this lot should be simplifed...
6029 cfg.align=this.align;
6032 cfg.bgcolor=this.bgcolor;
6035 cfg.border=this.border;
6037 if (this.cellpadding) {
6038 cfg.cellpadding=this.cellpadding;
6040 if (this.cellspacing) {
6041 cfg.cellspacing=this.cellspacing;
6044 cfg.frame=this.frame;
6047 cfg.rules=this.rules;
6049 if (this.sortable) {
6050 cfg.sortable=this.sortable;
6053 cfg.summary=this.summary;
6056 cfg.width=this.width;
6059 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6062 if(this.store || this.cm){
6063 if(this.headerShow){
6064 cfg.cn.push(this.renderHeader());
6067 cfg.cn.push(this.renderBody());
6069 if(this.footerShow){
6070 cfg.cn.push(this.renderFooter());
6072 // where does this come from?
6073 //cfg.cls+= ' TableGrid';
6076 return { cn : [ cfg ] };
6079 initEvents : function()
6081 if(!this.store || !this.cm){
6084 if (this.selModel) {
6085 this.selModel.initEvents();
6089 //Roo.log('initEvents with ds!!!!');
6091 this.mainBody = this.el.select('tbody', true).first();
6092 this.mainHead = this.el.select('thead', true).first();
6099 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6100 e.on('click', _this.sort, _this);
6103 this.mainBody.on("click", this.onClick, this);
6104 this.mainBody.on("dblclick", this.onDblClick, this);
6106 // why is this done????? = it breaks dialogs??
6107 //this.parent().el.setStyle('position', 'relative');
6111 this.footer.parentId = this.id;
6112 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6115 this.el.select('tfoot tr td').first().addClass('hide');
6119 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6121 this.store.on('load', this.onLoad, this);
6122 this.store.on('beforeload', this.onBeforeLoad, this);
6123 this.store.on('update', this.onUpdate, this);
6124 this.store.on('add', this.onAdd, this);
6125 this.store.on("clear", this.clear, this);
6127 this.el.on("contextmenu", this.onContextMenu, this);
6129 this.mainBody.on('scroll', this.onBodyScroll, this);
6134 onContextMenu : function(e, t)
6136 this.processEvent("contextmenu", e);
6139 processEvent : function(name, e)
6141 if (name != 'touchstart' ) {
6142 this.fireEvent(name, e);
6145 var t = e.getTarget();
6147 var cell = Roo.get(t);
6153 if(cell.findParent('tfoot', false, true)){
6157 if(cell.findParent('thead', false, true)){
6159 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6160 cell = Roo.get(t).findParent('th', false, true);
6162 Roo.log("failed to find th in thead?");
6163 Roo.log(e.getTarget());
6168 var cellIndex = cell.dom.cellIndex;
6170 var ename = name == 'touchstart' ? 'click' : name;
6171 this.fireEvent("header" + ename, this, cellIndex, e);
6176 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6177 cell = Roo.get(t).findParent('td', false, true);
6179 Roo.log("failed to find th in tbody?");
6180 Roo.log(e.getTarget());
6185 var row = cell.findParent('tr', false, true);
6186 var cellIndex = cell.dom.cellIndex;
6187 var rowIndex = row.dom.rowIndex - 1;
6191 this.fireEvent("row" + name, this, rowIndex, e);
6195 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6201 onMouseover : function(e, el)
6203 var cell = Roo.get(el);
6209 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6210 cell = cell.findParent('td', false, true);
6213 var row = cell.findParent('tr', false, true);
6214 var cellIndex = cell.dom.cellIndex;
6215 var rowIndex = row.dom.rowIndex - 1; // start from 0
6217 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6221 onMouseout : function(e, el)
6223 var cell = Roo.get(el);
6229 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6230 cell = cell.findParent('td', false, true);
6233 var row = cell.findParent('tr', false, true);
6234 var cellIndex = cell.dom.cellIndex;
6235 var rowIndex = row.dom.rowIndex - 1; // start from 0
6237 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6241 onClick : function(e, el)
6243 var cell = Roo.get(el);
6245 if(!cell || (!this.cellSelection && !this.rowSelection)){
6249 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6250 cell = cell.findParent('td', false, true);
6253 if(!cell || typeof(cell) == 'undefined'){
6257 var row = cell.findParent('tr', false, true);
6259 if(!row || typeof(row) == 'undefined'){
6263 var cellIndex = cell.dom.cellIndex;
6264 var rowIndex = this.getRowIndex(row);
6266 // why??? - should these not be based on SelectionModel?
6267 if(this.cellSelection){
6268 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6271 if(this.rowSelection){
6272 this.fireEvent('rowclick', this, row, rowIndex, e);
6278 onDblClick : function(e,el)
6280 var cell = Roo.get(el);
6282 if(!cell || (!this.cellSelection && !this.rowSelection)){
6286 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6287 cell = cell.findParent('td', false, true);
6290 if(!cell || typeof(cell) == 'undefined'){
6294 var row = cell.findParent('tr', false, true);
6296 if(!row || typeof(row) == 'undefined'){
6300 var cellIndex = cell.dom.cellIndex;
6301 var rowIndex = this.getRowIndex(row);
6303 if(this.cellSelection){
6304 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6307 if(this.rowSelection){
6308 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6312 sort : function(e,el)
6314 var col = Roo.get(el);
6316 if(!col.hasClass('sortable')){
6320 var sort = col.attr('sort');
6323 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6327 this.store.sortInfo = {field : sort, direction : dir};
6330 Roo.log("calling footer first");
6331 this.footer.onClick('first');
6334 this.store.load({ params : { start : 0 } });
6338 renderHeader : function()
6346 this.totalWidth = 0;
6348 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6350 var config = cm.config[i];
6355 html: cm.getColumnHeader(i)
6360 if(typeof(config.sortable) != 'undefined' && config.sortable){
6362 c.html = '<i class="glyphicon"></i>' + c.html;
6365 if(typeof(config.lgHeader) != 'undefined'){
6366 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6369 if(typeof(config.mdHeader) != 'undefined'){
6370 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6373 if(typeof(config.smHeader) != 'undefined'){
6374 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6377 if(typeof(config.xsHeader) != 'undefined'){
6378 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6385 if(typeof(config.tooltip) != 'undefined'){
6386 c.tooltip = config.tooltip;
6389 if(typeof(config.colspan) != 'undefined'){
6390 c.colspan = config.colspan;
6393 if(typeof(config.hidden) != 'undefined' && config.hidden){
6394 c.style += ' display:none;';
6397 if(typeof(config.dataIndex) != 'undefined'){
6398 c.sort = config.dataIndex;
6403 if(typeof(config.align) != 'undefined' && config.align.length){
6404 c.style += ' text-align:' + config.align + ';';
6407 if(typeof(config.width) != 'undefined'){
6408 c.style += ' width:' + config.width + 'px;';
6409 this.totalWidth += config.width;
6411 this.totalWidth += 100; // assume minimum of 100 per column?
6414 if(typeof(config.cls) != 'undefined'){
6415 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6418 ['xs','sm','md','lg'].map(function(size){
6420 if(typeof(config[size]) == 'undefined'){
6424 if (!config[size]) { // 0 = hidden
6425 c.cls += ' hidden-' + size;
6429 c.cls += ' col-' + size + '-' + config[size];
6439 renderBody : function()
6449 colspan : this.cm.getColumnCount()
6459 renderFooter : function()
6469 colspan : this.cm.getColumnCount()
6483 // Roo.log('ds onload');
6488 var ds = this.store;
6490 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6491 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6492 if (_this.store.sortInfo) {
6494 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6495 e.select('i', true).addClass(['glyphicon-arrow-up']);
6498 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6499 e.select('i', true).addClass(['glyphicon-arrow-down']);
6504 var tbody = this.mainBody;
6506 if(ds.getCount() > 0){
6507 ds.data.each(function(d,rowIndex){
6508 var row = this.renderRow(cm, ds, rowIndex);
6510 tbody.createChild(row);
6514 if(row.cellObjects.length){
6515 Roo.each(row.cellObjects, function(r){
6516 _this.renderCellObject(r);
6523 Roo.each(this.el.select('tbody td', true).elements, function(e){
6524 e.on('mouseover', _this.onMouseover, _this);
6527 Roo.each(this.el.select('tbody td', true).elements, function(e){
6528 e.on('mouseout', _this.onMouseout, _this);
6530 this.fireEvent('rowsrendered', this);
6531 //if(this.loadMask){
6532 // this.maskEl.hide();
6539 onUpdate : function(ds,record)
6541 this.refreshRow(record);
6545 onRemove : function(ds, record, index, isUpdate){
6546 if(isUpdate !== true){
6547 this.fireEvent("beforerowremoved", this, index, record);
6549 var bt = this.mainBody.dom;
6551 var rows = this.el.select('tbody > tr', true).elements;
6553 if(typeof(rows[index]) != 'undefined'){
6554 bt.removeChild(rows[index].dom);
6557 // if(bt.rows[index]){
6558 // bt.removeChild(bt.rows[index]);
6561 if(isUpdate !== true){
6562 //this.stripeRows(index);
6563 //this.syncRowHeights(index, index);
6565 this.fireEvent("rowremoved", this, index, record);
6569 onAdd : function(ds, records, rowIndex)
6571 //Roo.log('on Add called');
6572 // - note this does not handle multiple adding very well..
6573 var bt = this.mainBody.dom;
6574 for (var i =0 ; i < records.length;i++) {
6575 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6576 //Roo.log(records[i]);
6577 //Roo.log(this.store.getAt(rowIndex+i));
6578 this.insertRow(this.store, rowIndex + i, false);
6585 refreshRow : function(record){
6586 var ds = this.store, index;
6587 if(typeof record == 'number'){
6589 record = ds.getAt(index);
6591 index = ds.indexOf(record);
6593 this.insertRow(ds, index, true);
6595 this.onRemove(ds, record, index+1, true);
6597 //this.syncRowHeights(index, index);
6599 this.fireEvent("rowupdated", this, index, record);
6602 insertRow : function(dm, rowIndex, isUpdate){
6605 this.fireEvent("beforerowsinserted", this, rowIndex);
6607 //var s = this.getScrollState();
6608 var row = this.renderRow(this.cm, this.store, rowIndex);
6609 // insert before rowIndex..
6610 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6614 if(row.cellObjects.length){
6615 Roo.each(row.cellObjects, function(r){
6616 _this.renderCellObject(r);
6621 this.fireEvent("rowsinserted", this, rowIndex);
6622 //this.syncRowHeights(firstRow, lastRow);
6623 //this.stripeRows(firstRow);
6630 getRowDom : function(rowIndex)
6632 var rows = this.el.select('tbody > tr', true).elements;
6634 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6637 // returns the object tree for a tr..
6640 renderRow : function(cm, ds, rowIndex)
6643 var d = ds.getAt(rowIndex);
6650 var cellObjects = [];
6652 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6653 var config = cm.config[i];
6655 var renderer = cm.getRenderer(i);
6659 if(typeof(renderer) !== 'undefined'){
6660 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6662 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6663 // and are rendered into the cells after the row is rendered - using the id for the element.
6665 if(typeof(value) === 'object'){
6675 rowIndex : rowIndex,
6680 this.fireEvent('rowclass', this, rowcfg);
6684 cls : rowcfg.rowClass,
6686 html: (typeof(value) === 'object') ? '' : value
6693 if(typeof(config.colspan) != 'undefined'){
6694 td.colspan = config.colspan;
6697 if(typeof(config.hidden) != 'undefined' && config.hidden){
6698 td.style += ' display:none;';
6701 if(typeof(config.align) != 'undefined' && config.align.length){
6702 td.style += ' text-align:' + config.align + ';';
6705 if(typeof(config.width) != 'undefined'){
6706 td.style += ' width:' + config.width + 'px;';
6709 if(typeof(config.cursor) != 'undefined'){
6710 td.style += ' cursor:' + config.cursor + ';';
6713 if(typeof(config.cls) != 'undefined'){
6714 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6717 ['xs','sm','md','lg'].map(function(size){
6719 if(typeof(config[size]) == 'undefined'){
6723 if (!config[size]) { // 0 = hidden
6724 td.cls += ' hidden-' + size;
6728 td.cls += ' col-' + size + '-' + config[size];
6736 row.cellObjects = cellObjects;
6744 onBeforeLoad : function()
6746 //Roo.log('ds onBeforeLoad');
6750 //if(this.loadMask){
6751 // this.maskEl.show();
6759 this.el.select('tbody', true).first().dom.innerHTML = '';
6762 * Show or hide a row.
6763 * @param {Number} rowIndex to show or hide
6764 * @param {Boolean} state hide
6766 setRowVisibility : function(rowIndex, state)
6768 var bt = this.mainBody.dom;
6770 var rows = this.el.select('tbody > tr', true).elements;
6772 if(typeof(rows[rowIndex]) == 'undefined'){
6775 rows[rowIndex].dom.style.display = state ? '' : 'none';
6779 getSelectionModel : function(){
6781 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6783 return this.selModel;
6786 * Render the Roo.bootstrap object from renderder
6788 renderCellObject : function(r)
6792 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6794 var t = r.cfg.render(r.container);
6797 Roo.each(r.cfg.cn, function(c){
6799 container: t.getChildContainer(),
6802 _this.renderCellObject(child);
6807 getRowIndex : function(row)
6811 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6822 * Returns the grid's underlying element = used by panel.Grid
6823 * @return {Element} The element
6825 getGridEl : function(){
6829 * Forces a resize - used by panel.Grid
6830 * @return {Element} The element
6832 autoSize : function()
6834 //var ctr = Roo.get(this.container.dom.parentElement);
6835 var ctr = Roo.get(this.el.dom);
6837 var thd = this.getGridEl().select('thead',true).first();
6838 var tbd = this.getGridEl().select('tbody', true).first();
6839 var tfd = this.getGridEl().select('tfoot', true).first();
6841 var cw = ctr.getWidth();
6845 tbd.setSize(ctr.getWidth(),
6846 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6848 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6851 cw = Math.max(cw, this.totalWidth);
6852 this.getGridEl().select('tr',true).setWidth(cw);
6853 // resize 'expandable coloumn?
6855 return; // we doe not have a view in this design..
6858 onBodyScroll: function()
6860 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6861 this.mainHead.setStyle({
6862 'position' : 'relative',
6863 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6868 var scrollHeight = this.mainBody.dom.scrollHeight;
6870 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6872 var height = this.mainBody.getHeight();
6874 if(scrollHeight - height == scrollTop) {
6876 var total = this.ds.getTotalCount();
6878 if(this.footer.cursor + this.footer.pageSize < total){
6880 this.footer.ds.load({
6882 start : this.footer.cursor + this.footer.pageSize,
6883 limit : this.footer.pageSize
6904 * @class Roo.bootstrap.TableCell
6905 * @extends Roo.bootstrap.Component
6906 * Bootstrap TableCell class
6907 * @cfg {String} html cell contain text
6908 * @cfg {String} cls cell class
6909 * @cfg {String} tag cell tag (td|th) default td
6910 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6911 * @cfg {String} align Aligns the content in a cell
6912 * @cfg {String} axis Categorizes cells
6913 * @cfg {String} bgcolor Specifies the background color of a cell
6914 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6915 * @cfg {Number} colspan Specifies the number of columns a cell should span
6916 * @cfg {String} headers Specifies one or more header cells a cell is related to
6917 * @cfg {Number} height Sets the height of a cell
6918 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6919 * @cfg {Number} rowspan Sets the number of rows a cell should span
6920 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6921 * @cfg {String} valign Vertical aligns the content in a cell
6922 * @cfg {Number} width Specifies the width of a cell
6925 * Create a new TableCell
6926 * @param {Object} config The config object
6929 Roo.bootstrap.TableCell = function(config){
6930 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6933 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6974 cfg.align=this.align
6980 cfg.bgcolor=this.bgcolor
6983 cfg.charoff=this.charoff
6986 cfg.colspan=this.colspan
6989 cfg.headers=this.headers
6992 cfg.height=this.height
6995 cfg.nowrap=this.nowrap
6998 cfg.rowspan=this.rowspan
7001 cfg.scope=this.scope
7004 cfg.valign=this.valign
7007 cfg.width=this.width
7026 * @class Roo.bootstrap.TableRow
7027 * @extends Roo.bootstrap.Component
7028 * Bootstrap TableRow class
7029 * @cfg {String} cls row class
7030 * @cfg {String} align Aligns the content in a table row
7031 * @cfg {String} bgcolor Specifies a background color for a table row
7032 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7033 * @cfg {String} valign Vertical aligns the content in a table row
7036 * Create a new TableRow
7037 * @param {Object} config The config object
7040 Roo.bootstrap.TableRow = function(config){
7041 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7044 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7052 getAutoCreate : function(){
7053 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7063 cfg.align = this.align;
7066 cfg.bgcolor = this.bgcolor;
7069 cfg.charoff = this.charoff;
7072 cfg.valign = this.valign;
7090 * @class Roo.bootstrap.TableBody
7091 * @extends Roo.bootstrap.Component
7092 * Bootstrap TableBody class
7093 * @cfg {String} cls element class
7094 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7095 * @cfg {String} align Aligns the content inside the element
7096 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7097 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7100 * Create a new TableBody
7101 * @param {Object} config The config object
7104 Roo.bootstrap.TableBody = function(config){
7105 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7108 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7116 getAutoCreate : function(){
7117 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7131 cfg.align = this.align;
7134 cfg.charoff = this.charoff;
7137 cfg.valign = this.valign;
7144 // initEvents : function()
7151 // this.store = Roo.factory(this.store, Roo.data);
7152 // this.store.on('load', this.onLoad, this);
7154 // this.store.load();
7158 // onLoad: function ()
7160 // this.fireEvent('load', this);
7170 * Ext JS Library 1.1.1
7171 * Copyright(c) 2006-2007, Ext JS, LLC.
7173 * Originally Released Under LGPL - original licence link has changed is not relivant.
7176 * <script type="text/javascript">
7179 // as we use this in bootstrap.
7180 Roo.namespace('Roo.form');
7182 * @class Roo.form.Action
7183 * Internal Class used to handle form actions
7185 * @param {Roo.form.BasicForm} el The form element or its id
7186 * @param {Object} config Configuration options
7191 // define the action interface
7192 Roo.form.Action = function(form, options){
7194 this.options = options || {};
7197 * Client Validation Failed
7200 Roo.form.Action.CLIENT_INVALID = 'client';
7202 * Server Validation Failed
7205 Roo.form.Action.SERVER_INVALID = 'server';
7207 * Connect to Server Failed
7210 Roo.form.Action.CONNECT_FAILURE = 'connect';
7212 * Reading Data from Server Failed
7215 Roo.form.Action.LOAD_FAILURE = 'load';
7217 Roo.form.Action.prototype = {
7219 failureType : undefined,
7220 response : undefined,
7224 run : function(options){
7229 success : function(response){
7234 handleResponse : function(response){
7238 // default connection failure
7239 failure : function(response){
7241 this.response = response;
7242 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7243 this.form.afterAction(this, false);
7246 processResponse : function(response){
7247 this.response = response;
7248 if(!response.responseText){
7251 this.result = this.handleResponse(response);
7255 // utility functions used internally
7256 getUrl : function(appendParams){
7257 var url = this.options.url || this.form.url || this.form.el.dom.action;
7259 var p = this.getParams();
7261 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7267 getMethod : function(){
7268 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7271 getParams : function(){
7272 var bp = this.form.baseParams;
7273 var p = this.options.params;
7275 if(typeof p == "object"){
7276 p = Roo.urlEncode(Roo.applyIf(p, bp));
7277 }else if(typeof p == 'string' && bp){
7278 p += '&' + Roo.urlEncode(bp);
7281 p = Roo.urlEncode(bp);
7286 createCallback : function(){
7288 success: this.success,
7289 failure: this.failure,
7291 timeout: (this.form.timeout*1000),
7292 upload: this.form.fileUpload ? this.success : undefined
7297 Roo.form.Action.Submit = function(form, options){
7298 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7301 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7304 haveProgress : false,
7305 uploadComplete : false,
7307 // uploadProgress indicator.
7308 uploadProgress : function()
7310 if (!this.form.progressUrl) {
7314 if (!this.haveProgress) {
7315 Roo.MessageBox.progress("Uploading", "Uploading");
7317 if (this.uploadComplete) {
7318 Roo.MessageBox.hide();
7322 this.haveProgress = true;
7324 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7326 var c = new Roo.data.Connection();
7328 url : this.form.progressUrl,
7333 success : function(req){
7334 //console.log(data);
7338 rdata = Roo.decode(req.responseText)
7340 Roo.log("Invalid data from server..");
7344 if (!rdata || !rdata.success) {
7346 Roo.MessageBox.alert(Roo.encode(rdata));
7349 var data = rdata.data;
7351 if (this.uploadComplete) {
7352 Roo.MessageBox.hide();
7357 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7358 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7361 this.uploadProgress.defer(2000,this);
7364 failure: function(data) {
7365 Roo.log('progress url failed ');
7376 // run get Values on the form, so it syncs any secondary forms.
7377 this.form.getValues();
7379 var o = this.options;
7380 var method = this.getMethod();
7381 var isPost = method == 'POST';
7382 if(o.clientValidation === false || this.form.isValid()){
7384 if (this.form.progressUrl) {
7385 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7386 (new Date() * 1) + '' + Math.random());
7391 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7392 form:this.form.el.dom,
7393 url:this.getUrl(!isPost),
7395 params:isPost ? this.getParams() : null,
7396 isUpload: this.form.fileUpload
7399 this.uploadProgress();
7401 }else if (o.clientValidation !== false){ // client validation failed
7402 this.failureType = Roo.form.Action.CLIENT_INVALID;
7403 this.form.afterAction(this, false);
7407 success : function(response)
7409 this.uploadComplete= true;
7410 if (this.haveProgress) {
7411 Roo.MessageBox.hide();
7415 var result = this.processResponse(response);
7416 if(result === true || result.success){
7417 this.form.afterAction(this, true);
7421 this.form.markInvalid(result.errors);
7422 this.failureType = Roo.form.Action.SERVER_INVALID;
7424 this.form.afterAction(this, false);
7426 failure : function(response)
7428 this.uploadComplete= true;
7429 if (this.haveProgress) {
7430 Roo.MessageBox.hide();
7433 this.response = response;
7434 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7435 this.form.afterAction(this, false);
7438 handleResponse : function(response){
7439 if(this.form.errorReader){
7440 var rs = this.form.errorReader.read(response);
7443 for(var i = 0, len = rs.records.length; i < len; i++) {
7444 var r = rs.records[i];
7448 if(errors.length < 1){
7452 success : rs.success,
7458 ret = Roo.decode(response.responseText);
7462 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7472 Roo.form.Action.Load = function(form, options){
7473 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7474 this.reader = this.form.reader;
7477 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7482 Roo.Ajax.request(Roo.apply(
7483 this.createCallback(), {
7484 method:this.getMethod(),
7485 url:this.getUrl(false),
7486 params:this.getParams()
7490 success : function(response){
7492 var result = this.processResponse(response);
7493 if(result === true || !result.success || !result.data){
7494 this.failureType = Roo.form.Action.LOAD_FAILURE;
7495 this.form.afterAction(this, false);
7498 this.form.clearInvalid();
7499 this.form.setValues(result.data);
7500 this.form.afterAction(this, true);
7503 handleResponse : function(response){
7504 if(this.form.reader){
7505 var rs = this.form.reader.read(response);
7506 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7508 success : rs.success,
7512 return Roo.decode(response.responseText);
7516 Roo.form.Action.ACTION_TYPES = {
7517 'load' : Roo.form.Action.Load,
7518 'submit' : Roo.form.Action.Submit
7527 * @class Roo.bootstrap.Form
7528 * @extends Roo.bootstrap.Component
7529 * Bootstrap Form class
7530 * @cfg {String} method GET | POST (default POST)
7531 * @cfg {String} labelAlign top | left (default top)
7532 * @cfg {String} align left | right - for navbars
7533 * @cfg {Boolean} loadMask load mask when submit (default true)
7538 * @param {Object} config The config object
7542 Roo.bootstrap.Form = function(config){
7543 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7545 Roo.bootstrap.Form.popover.apply();
7549 * @event clientvalidation
7550 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7551 * @param {Form} this
7552 * @param {Boolean} valid true if the form has passed client-side validation
7554 clientvalidation: true,
7556 * @event beforeaction
7557 * Fires before any action is performed. Return false to cancel the action.
7558 * @param {Form} this
7559 * @param {Action} action The action to be performed
7563 * @event actionfailed
7564 * Fires when an action fails.
7565 * @param {Form} this
7566 * @param {Action} action The action that failed
7568 actionfailed : true,
7570 * @event actioncomplete
7571 * Fires when an action is completed.
7572 * @param {Form} this
7573 * @param {Action} action The action that completed
7575 actioncomplete : true
7580 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7583 * @cfg {String} method
7584 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7589 * The URL to use for form actions if one isn't supplied in the action options.
7592 * @cfg {Boolean} fileUpload
7593 * Set to true if this form is a file upload.
7597 * @cfg {Object} baseParams
7598 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7602 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7606 * @cfg {Sting} align (left|right) for navbar forms
7611 activeAction : null,
7614 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7615 * element by passing it or its id or mask the form itself by passing in true.
7618 waitMsgTarget : false,
7623 * @cfg {Boolean} errorMask (true|false) default false
7628 * @cfg {Number} maskOffset Default 100
7633 * @cfg {Boolean} maskBody
7637 getAutoCreate : function(){
7641 method : this.method || 'POST',
7642 id : this.id || Roo.id(),
7645 if (this.parent().xtype.match(/^Nav/)) {
7646 cfg.cls = 'navbar-form navbar-' + this.align;
7650 if (this.labelAlign == 'left' ) {
7651 cfg.cls += ' form-horizontal';
7657 initEvents : function()
7659 this.el.on('submit', this.onSubmit, this);
7660 // this was added as random key presses on the form where triggering form submit.
7661 this.el.on('keypress', function(e) {
7662 if (e.getCharCode() != 13) {
7665 // we might need to allow it for textareas.. and some other items.
7666 // check e.getTarget().
7668 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7672 Roo.log("keypress blocked");
7680 onSubmit : function(e){
7685 * Returns true if client-side validation on the form is successful.
7688 isValid : function(){
7689 var items = this.getItems();
7693 items.each(function(f){
7699 if(!target && f.el.isVisible(true)){
7705 if(this.errorMask && !valid){
7706 Roo.bootstrap.Form.popover.mask(this, target);
7713 * Returns true if any fields in this form have changed since their original load.
7716 isDirty : function(){
7718 var items = this.getItems();
7719 items.each(function(f){
7729 * Performs a predefined action (submit or load) or custom actions you define on this form.
7730 * @param {String} actionName The name of the action type
7731 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7732 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7733 * accept other config options):
7735 Property Type Description
7736 ---------------- --------------- ----------------------------------------------------------------------------------
7737 url String The url for the action (defaults to the form's url)
7738 method String The form method to use (defaults to the form's method, or POST if not defined)
7739 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7740 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7741 validate the form on the client (defaults to false)
7743 * @return {BasicForm} this
7745 doAction : function(action, options){
7746 if(typeof action == 'string'){
7747 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7749 if(this.fireEvent('beforeaction', this, action) !== false){
7750 this.beforeAction(action);
7751 action.run.defer(100, action);
7757 beforeAction : function(action){
7758 var o = action.options;
7763 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7765 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7768 // not really supported yet.. ??
7770 //if(this.waitMsgTarget === true){
7771 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7772 //}else if(this.waitMsgTarget){
7773 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7774 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7776 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7782 afterAction : function(action, success){
7783 this.activeAction = null;
7784 var o = action.options;
7789 Roo.get(document.body).unmask();
7795 //if(this.waitMsgTarget === true){
7796 // this.el.unmask();
7797 //}else if(this.waitMsgTarget){
7798 // this.waitMsgTarget.unmask();
7800 // Roo.MessageBox.updateProgress(1);
7801 // Roo.MessageBox.hide();
7808 Roo.callback(o.success, o.scope, [this, action]);
7809 this.fireEvent('actioncomplete', this, action);
7813 // failure condition..
7814 // we have a scenario where updates need confirming.
7815 // eg. if a locking scenario exists..
7816 // we look for { errors : { needs_confirm : true }} in the response.
7818 (typeof(action.result) != 'undefined') &&
7819 (typeof(action.result.errors) != 'undefined') &&
7820 (typeof(action.result.errors.needs_confirm) != 'undefined')
7823 Roo.log("not supported yet");
7826 Roo.MessageBox.confirm(
7827 "Change requires confirmation",
7828 action.result.errorMsg,
7833 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7843 Roo.callback(o.failure, o.scope, [this, action]);
7844 // show an error message if no failed handler is set..
7845 if (!this.hasListener('actionfailed')) {
7846 Roo.log("need to add dialog support");
7848 Roo.MessageBox.alert("Error",
7849 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7850 action.result.errorMsg :
7851 "Saving Failed, please check your entries or try again"
7856 this.fireEvent('actionfailed', this, action);
7861 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7862 * @param {String} id The value to search for
7865 findField : function(id){
7866 var items = this.getItems();
7867 var field = items.get(id);
7869 items.each(function(f){
7870 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7877 return field || null;
7880 * Mark fields in this form invalid in bulk.
7881 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7882 * @return {BasicForm} this
7884 markInvalid : function(errors){
7885 if(errors instanceof Array){
7886 for(var i = 0, len = errors.length; i < len; i++){
7887 var fieldError = errors[i];
7888 var f = this.findField(fieldError.id);
7890 f.markInvalid(fieldError.msg);
7896 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7897 field.markInvalid(errors[id]);
7901 //Roo.each(this.childForms || [], function (f) {
7902 // f.markInvalid(errors);
7909 * Set values for fields in this form in bulk.
7910 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7911 * @return {BasicForm} this
7913 setValues : function(values){
7914 if(values instanceof Array){ // array of objects
7915 for(var i = 0, len = values.length; i < len; i++){
7917 var f = this.findField(v.id);
7919 f.setValue(v.value);
7920 if(this.trackResetOnLoad){
7921 f.originalValue = f.getValue();
7925 }else{ // object hash
7928 if(typeof values[id] != 'function' && (field = this.findField(id))){
7930 if (field.setFromData &&
7932 field.displayField &&
7933 // combos' with local stores can
7934 // be queried via setValue()
7935 // to set their value..
7936 (field.store && !field.store.isLocal)
7940 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7941 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7942 field.setFromData(sd);
7944 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7946 field.setFromData(values);
7949 field.setValue(values[id]);
7953 if(this.trackResetOnLoad){
7954 field.originalValue = field.getValue();
7960 //Roo.each(this.childForms || [], function (f) {
7961 // f.setValues(values);
7968 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7969 * they are returned as an array.
7970 * @param {Boolean} asString
7973 getValues : function(asString){
7974 //if (this.childForms) {
7975 // copy values from the child forms
7976 // Roo.each(this.childForms, function (f) {
7977 // this.setValues(f.getValues());
7983 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7984 if(asString === true){
7987 return Roo.urlDecode(fs);
7991 * Returns the fields in this form as an object with key/value pairs.
7992 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7995 getFieldValues : function(with_hidden)
7997 var items = this.getItems();
7999 items.each(function(f){
8005 var v = f.getValue();
8007 if (f.inputType =='radio') {
8008 if (typeof(ret[f.getName()]) == 'undefined') {
8009 ret[f.getName()] = ''; // empty..
8012 if (!f.el.dom.checked) {
8020 if(f.xtype == 'MoneyField'){
8021 ret[f.currencyName] = f.getCurrency();
8024 // not sure if this supported any more..
8025 if ((typeof(v) == 'object') && f.getRawValue) {
8026 v = f.getRawValue() ; // dates..
8028 // combo boxes where name != hiddenName...
8029 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8030 ret[f.name] = f.getRawValue();
8032 ret[f.getName()] = v;
8039 * Clears all invalid messages in this form.
8040 * @return {BasicForm} this
8042 clearInvalid : function(){
8043 var items = this.getItems();
8045 items.each(function(f){
8056 * @return {BasicForm} this
8059 var items = this.getItems();
8060 items.each(function(f){
8064 Roo.each(this.childForms || [], function (f) {
8072 getItems : function()
8074 var r=new Roo.util.MixedCollection(false, function(o){
8075 return o.id || (o.id = Roo.id());
8077 var iter = function(el) {
8084 Roo.each(el.items,function(e) {
8098 Roo.apply(Roo.bootstrap.Form, {
8125 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8126 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8127 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8128 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8131 this.maskEl.top.enableDisplayMode("block");
8132 this.maskEl.left.enableDisplayMode("block");
8133 this.maskEl.bottom.enableDisplayMode("block");
8134 this.maskEl.right.enableDisplayMode("block");
8136 this.toolTip = new Roo.bootstrap.Tooltip({
8137 cls : 'roo-form-error-popover',
8139 'left' : ['r-l', [-2,0], 'right'],
8140 'right' : ['l-r', [2,0], 'left'],
8141 'bottom' : ['tl-bl', [0,2], 'top'],
8142 'top' : [ 'bl-tl', [0,-2], 'bottom']
8146 this.toolTip.render(Roo.get(document.body));
8148 this.toolTip.el.enableDisplayMode("block");
8150 Roo.get(document.body).on('click', function(){
8154 Roo.get(document.body).on('touchstart', function(){
8158 this.isApplied = true
8161 mask : function(form, target)
8165 this.target = target;
8167 if(!this.form.errorMask || !target.el){
8171 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8173 Roo.log(scrollable);
8175 var ot = this.target.el.calcOffsetsTo(scrollable);
8177 var scrollTo = ot[1] - this.form.maskOffset;
8179 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8181 scrollable.scrollTo('top', scrollTo);
8183 var box = this.target.el.getBox();
8185 var zIndex = Roo.bootstrap.Modal.zIndex++;
8188 this.maskEl.top.setStyle('position', 'absolute');
8189 this.maskEl.top.setStyle('z-index', zIndex);
8190 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8191 this.maskEl.top.setLeft(0);
8192 this.maskEl.top.setTop(0);
8193 this.maskEl.top.show();
8195 this.maskEl.left.setStyle('position', 'absolute');
8196 this.maskEl.left.setStyle('z-index', zIndex);
8197 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8198 this.maskEl.left.setLeft(0);
8199 this.maskEl.left.setTop(box.y - this.padding);
8200 this.maskEl.left.show();
8202 this.maskEl.bottom.setStyle('position', 'absolute');
8203 this.maskEl.bottom.setStyle('z-index', zIndex);
8204 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8205 this.maskEl.bottom.setLeft(0);
8206 this.maskEl.bottom.setTop(box.bottom + this.padding);
8207 this.maskEl.bottom.show();
8209 this.maskEl.right.setStyle('position', 'absolute');
8210 this.maskEl.right.setStyle('z-index', zIndex);
8211 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8212 this.maskEl.right.setLeft(box.right + this.padding);
8213 this.maskEl.right.setTop(box.y - this.padding);
8214 this.maskEl.right.show();
8216 this.toolTip.bindEl = this.target.el;
8218 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8220 var tip = this.target.blankText;
8222 if(this.target.getValue() !== '' ) {
8224 if (this.target.invalidText.length) {
8225 tip = this.target.invalidText;
8226 } else if (this.target.regexText.length){
8227 tip = this.target.regexText;
8231 this.toolTip.show(tip);
8233 this.intervalID = window.setInterval(function() {
8234 Roo.bootstrap.Form.popover.unmask();
8237 window.onwheel = function(){ return false;};
8239 (function(){ this.isMasked = true; }).defer(500, this);
8245 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8249 this.maskEl.top.setStyle('position', 'absolute');
8250 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8251 this.maskEl.top.hide();
8253 this.maskEl.left.setStyle('position', 'absolute');
8254 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8255 this.maskEl.left.hide();
8257 this.maskEl.bottom.setStyle('position', 'absolute');
8258 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8259 this.maskEl.bottom.hide();
8261 this.maskEl.right.setStyle('position', 'absolute');
8262 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8263 this.maskEl.right.hide();
8265 this.toolTip.hide();
8267 this.toolTip.el.hide();
8269 window.onwheel = function(){ return true;};
8271 if(this.intervalID){
8272 window.clearInterval(this.intervalID);
8273 this.intervalID = false;
8276 this.isMasked = false;
8286 * Ext JS Library 1.1.1
8287 * Copyright(c) 2006-2007, Ext JS, LLC.
8289 * Originally Released Under LGPL - original licence link has changed is not relivant.
8292 * <script type="text/javascript">
8295 * @class Roo.form.VTypes
8296 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8299 Roo.form.VTypes = function(){
8300 // closure these in so they are only created once.
8301 var alpha = /^[a-zA-Z_]+$/;
8302 var alphanum = /^[a-zA-Z0-9_]+$/;
8303 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8304 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8306 // All these messages and functions are configurable
8309 * The function used to validate email addresses
8310 * @param {String} value The email address
8312 'email' : function(v){
8313 return email.test(v);
8316 * The error text to display when the email validation function returns false
8319 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8321 * The keystroke filter mask to be applied on email input
8324 'emailMask' : /[a-z0-9_\.\-@]/i,
8327 * The function used to validate URLs
8328 * @param {String} value The URL
8330 'url' : function(v){
8334 * The error text to display when the url validation function returns false
8337 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8340 * The function used to validate alpha values
8341 * @param {String} value The value
8343 'alpha' : function(v){
8344 return alpha.test(v);
8347 * The error text to display when the alpha validation function returns false
8350 'alphaText' : 'This field should only contain letters and _',
8352 * The keystroke filter mask to be applied on alpha input
8355 'alphaMask' : /[a-z_]/i,
8358 * The function used to validate alphanumeric values
8359 * @param {String} value The value
8361 'alphanum' : function(v){
8362 return alphanum.test(v);
8365 * The error text to display when the alphanumeric validation function returns false
8368 'alphanumText' : 'This field should only contain letters, numbers and _',
8370 * The keystroke filter mask to be applied on alphanumeric input
8373 'alphanumMask' : /[a-z0-9_]/i
8383 * @class Roo.bootstrap.Input
8384 * @extends Roo.bootstrap.Component
8385 * Bootstrap Input class
8386 * @cfg {Boolean} disabled is it disabled
8387 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8388 * @cfg {String} name name of the input
8389 * @cfg {string} fieldLabel - the label associated
8390 * @cfg {string} placeholder - placeholder to put in text.
8391 * @cfg {string} before - input group add on before
8392 * @cfg {string} after - input group add on after
8393 * @cfg {string} size - (lg|sm) or leave empty..
8394 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8395 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8396 * @cfg {Number} md colspan out of 12 for computer-sized screens
8397 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8398 * @cfg {string} value default value of the input
8399 * @cfg {Number} labelWidth set the width of label
8400 * @cfg {Number} labellg set the width of label (1-12)
8401 * @cfg {Number} labelmd set the width of label (1-12)
8402 * @cfg {Number} labelsm set the width of label (1-12)
8403 * @cfg {Number} labelxs set the width of label (1-12)
8404 * @cfg {String} labelAlign (top|left)
8405 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8406 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8407 * @cfg {String} indicatorpos (left|right) default left
8409 * @cfg {String} align (left|center|right) Default left
8410 * @cfg {Boolean} forceFeedback (true|false) Default false
8416 * Create a new Input
8417 * @param {Object} config The config object
8420 Roo.bootstrap.Input = function(config){
8422 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8427 * Fires when this field receives input focus.
8428 * @param {Roo.form.Field} this
8433 * Fires when this field loses input focus.
8434 * @param {Roo.form.Field} this
8439 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8440 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8441 * @param {Roo.form.Field} this
8442 * @param {Roo.EventObject} e The event object
8447 * Fires just before the field blurs if the field value has changed.
8448 * @param {Roo.form.Field} this
8449 * @param {Mixed} newValue The new value
8450 * @param {Mixed} oldValue The original value
8455 * Fires after the field has been marked as invalid.
8456 * @param {Roo.form.Field} this
8457 * @param {String} msg The validation message
8462 * Fires after the field has been validated with no errors.
8463 * @param {Roo.form.Field} this
8468 * Fires after the key up
8469 * @param {Roo.form.Field} this
8470 * @param {Roo.EventObject} e The event Object
8476 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8478 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8479 automatic validation (defaults to "keyup").
8481 validationEvent : "keyup",
8483 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8485 validateOnBlur : true,
8487 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8489 validationDelay : 250,
8491 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8493 focusClass : "x-form-focus", // not needed???
8497 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8499 invalidClass : "has-warning",
8502 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8504 validClass : "has-success",
8507 * @cfg {Boolean} hasFeedback (true|false) default true
8512 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8514 invalidFeedbackClass : "glyphicon-warning-sign",
8517 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8519 validFeedbackClass : "glyphicon-ok",
8522 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8524 selectOnFocus : false,
8527 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8531 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8536 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8538 disableKeyFilter : false,
8541 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8545 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8549 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8551 blankText : "Please complete this mandatory field",
8554 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8558 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8560 maxLength : Number.MAX_VALUE,
8562 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8564 minLengthText : "The minimum length for this field is {0}",
8566 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8568 maxLengthText : "The maximum length for this field is {0}",
8572 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8573 * If available, this function will be called only after the basic validators all return true, and will be passed the
8574 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8578 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8579 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8580 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8584 * @cfg {String} regexText -- Depricated - use Invalid Text
8589 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8595 autocomplete: false,
8614 formatedValue : false,
8615 forceFeedback : false,
8617 indicatorpos : 'left',
8624 parentLabelAlign : function()
8627 while (parent.parent()) {
8628 parent = parent.parent();
8629 if (typeof(parent.labelAlign) !='undefined') {
8630 return parent.labelAlign;
8637 getAutoCreate : function()
8639 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8645 if(this.inputType != 'hidden'){
8646 cfg.cls = 'form-group' //input-group
8652 type : this.inputType,
8654 cls : 'form-control',
8655 placeholder : this.placeholder || '',
8656 autocomplete : this.autocomplete || 'new-password'
8660 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8663 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8664 input.maxLength = this.maxLength;
8667 if (this.disabled) {
8668 input.disabled=true;
8671 if (this.readOnly) {
8672 input.readonly=true;
8676 input.name = this.name;
8680 input.cls += ' input-' + this.size;
8684 ['xs','sm','md','lg'].map(function(size){
8685 if (settings[size]) {
8686 cfg.cls += ' col-' + size + '-' + settings[size];
8690 var inputblock = input;
8694 cls: 'glyphicon form-control-feedback'
8697 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8700 cls : 'has-feedback',
8708 if (this.before || this.after) {
8711 cls : 'input-group',
8715 if (this.before && typeof(this.before) == 'string') {
8717 inputblock.cn.push({
8719 cls : 'roo-input-before input-group-addon',
8723 if (this.before && typeof(this.before) == 'object') {
8724 this.before = Roo.factory(this.before);
8726 inputblock.cn.push({
8728 cls : 'roo-input-before input-group-' +
8729 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8733 inputblock.cn.push(input);
8735 if (this.after && typeof(this.after) == 'string') {
8736 inputblock.cn.push({
8738 cls : 'roo-input-after input-group-addon',
8742 if (this.after && typeof(this.after) == 'object') {
8743 this.after = Roo.factory(this.after);
8745 inputblock.cn.push({
8747 cls : 'roo-input-after input-group-' +
8748 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8752 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8753 inputblock.cls += ' has-feedback';
8754 inputblock.cn.push(feedback);
8758 if (align ==='left' && this.fieldLabel.length) {
8760 cfg.cls += ' roo-form-group-label-left';
8765 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8766 tooltip : 'This field is required'
8771 cls : 'control-label',
8772 html : this.fieldLabel
8783 var labelCfg = cfg.cn[1];
8784 var contentCfg = cfg.cn[2];
8786 if(this.indicatorpos == 'right'){
8791 cls : 'control-label',
8795 html : this.fieldLabel
8799 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8800 tooltip : 'This field is required'
8813 labelCfg = cfg.cn[0];
8814 contentCfg = cfg.cn[1];
8818 if(this.labelWidth > 12){
8819 labelCfg.style = "width: " + this.labelWidth + 'px';
8822 if(this.labelWidth < 13 && this.labelmd == 0){
8823 this.labelmd = this.labelWidth;
8826 if(this.labellg > 0){
8827 labelCfg.cls += ' col-lg-' + this.labellg;
8828 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8831 if(this.labelmd > 0){
8832 labelCfg.cls += ' col-md-' + this.labelmd;
8833 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8836 if(this.labelsm > 0){
8837 labelCfg.cls += ' col-sm-' + this.labelsm;
8838 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8841 if(this.labelxs > 0){
8842 labelCfg.cls += ' col-xs-' + this.labelxs;
8843 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8847 } else if ( this.fieldLabel.length) {
8852 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8853 tooltip : 'This field is required'
8857 //cls : 'input-group-addon',
8858 html : this.fieldLabel
8866 if(this.indicatorpos == 'right'){
8871 //cls : 'input-group-addon',
8872 html : this.fieldLabel
8877 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8878 tooltip : 'This field is required'
8898 if (this.parentType === 'Navbar' && this.parent().bar) {
8899 cfg.cls += ' navbar-form';
8902 if (this.parentType === 'NavGroup') {
8903 cfg.cls += ' navbar-form';
8911 * return the real input element.
8913 inputEl: function ()
8915 return this.el.select('input.form-control',true).first();
8918 tooltipEl : function()
8920 return this.inputEl();
8923 indicatorEl : function()
8925 var indicator = this.el.select('i.roo-required-indicator',true).first();
8935 setDisabled : function(v)
8937 var i = this.inputEl().dom;
8939 i.removeAttribute('disabled');
8943 i.setAttribute('disabled','true');
8945 initEvents : function()
8948 this.inputEl().on("keydown" , this.fireKey, this);
8949 this.inputEl().on("focus", this.onFocus, this);
8950 this.inputEl().on("blur", this.onBlur, this);
8952 this.inputEl().relayEvent('keyup', this);
8954 this.indicator = this.indicatorEl();
8957 this.indicator.addClass('invisible');
8961 // reference to original value for reset
8962 this.originalValue = this.getValue();
8963 //Roo.form.TextField.superclass.initEvents.call(this);
8964 if(this.validationEvent == 'keyup'){
8965 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8966 this.inputEl().on('keyup', this.filterValidation, this);
8968 else if(this.validationEvent !== false){
8969 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8972 if(this.selectOnFocus){
8973 this.on("focus", this.preFocus, this);
8976 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8977 this.inputEl().on("keypress", this.filterKeys, this);
8979 this.inputEl().relayEvent('keypress', this);
8982 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8983 this.el.on("click", this.autoSize, this);
8986 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8987 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8990 if (typeof(this.before) == 'object') {
8991 this.before.render(this.el.select('.roo-input-before',true).first());
8993 if (typeof(this.after) == 'object') {
8994 this.after.render(this.el.select('.roo-input-after',true).first());
8999 filterValidation : function(e){
9000 if(!e.isNavKeyPress()){
9001 this.validationTask.delay(this.validationDelay);
9005 * Validates the field value
9006 * @return {Boolean} True if the value is valid, else false
9008 validate : function(){
9009 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9010 if(this.disabled || this.validateValue(this.getRawValue())){
9021 * Validates a value according to the field's validation rules and marks the field as invalid
9022 * if the validation fails
9023 * @param {Mixed} value The value to validate
9024 * @return {Boolean} True if the value is valid, else false
9026 validateValue : function(value){
9027 if(value.length < 1) { // if it's blank
9028 if(this.allowBlank){
9031 return this.inputEl().hasClass('hide') ? true : false;
9034 if(value.length < this.minLength){
9037 if(value.length > this.maxLength){
9041 var vt = Roo.form.VTypes;
9042 if(!vt[this.vtype](value, this)){
9046 if(typeof this.validator == "function"){
9047 var msg = this.validator(value);
9051 if (typeof(msg) == 'string') {
9052 this.invalidText = msg;
9056 if(this.regex && !this.regex.test(value)){
9066 fireKey : function(e){
9067 //Roo.log('field ' + e.getKey());
9068 if(e.isNavKeyPress()){
9069 this.fireEvent("specialkey", this, e);
9072 focus : function (selectText){
9074 this.inputEl().focus();
9075 if(selectText === true){
9076 this.inputEl().dom.select();
9082 onFocus : function(){
9083 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9084 // this.el.addClass(this.focusClass);
9087 this.hasFocus = true;
9088 this.startValue = this.getValue();
9089 this.fireEvent("focus", this);
9093 beforeBlur : Roo.emptyFn,
9097 onBlur : function(){
9099 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9100 //this.el.removeClass(this.focusClass);
9102 this.hasFocus = false;
9103 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9106 var v = this.getValue();
9107 if(String(v) !== String(this.startValue)){
9108 this.fireEvent('change', this, v, this.startValue);
9110 this.fireEvent("blur", this);
9114 * Resets the current field value to the originally loaded value and clears any validation messages
9117 this.setValue(this.originalValue);
9121 * Returns the name of the field
9122 * @return {Mixed} name The name field
9124 getName: function(){
9128 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9129 * @return {Mixed} value The field value
9131 getValue : function(){
9133 var v = this.inputEl().getValue();
9138 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9139 * @return {Mixed} value The field value
9141 getRawValue : function(){
9142 var v = this.inputEl().getValue();
9148 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9149 * @param {Mixed} value The value to set
9151 setRawValue : function(v){
9152 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9155 selectText : function(start, end){
9156 var v = this.getRawValue();
9158 start = start === undefined ? 0 : start;
9159 end = end === undefined ? v.length : end;
9160 var d = this.inputEl().dom;
9161 if(d.setSelectionRange){
9162 d.setSelectionRange(start, end);
9163 }else if(d.createTextRange){
9164 var range = d.createTextRange();
9165 range.moveStart("character", start);
9166 range.moveEnd("character", v.length-end);
9173 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9174 * @param {Mixed} value The value to set
9176 setValue : function(v){
9179 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9185 processValue : function(value){
9186 if(this.stripCharsRe){
9187 var newValue = value.replace(this.stripCharsRe, '');
9188 if(newValue !== value){
9189 this.setRawValue(newValue);
9196 preFocus : function(){
9198 if(this.selectOnFocus){
9199 this.inputEl().dom.select();
9202 filterKeys : function(e){
9204 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9207 var c = e.getCharCode(), cc = String.fromCharCode(c);
9208 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9211 if(!this.maskRe.test(cc)){
9216 * Clear any invalid styles/messages for this field
9218 clearInvalid : function(){
9220 if(!this.el || this.preventMark){ // not rendered
9225 this.el.removeClass(this.invalidClass);
9227 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9229 var feedback = this.el.select('.form-control-feedback', true).first();
9232 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9237 this.fireEvent('valid', this);
9241 * Mark this field as valid
9243 markValid : function()
9245 if(!this.el || this.preventMark){ // not rendered...
9249 this.el.removeClass([this.invalidClass, this.validClass]);
9251 var feedback = this.el.select('.form-control-feedback', true).first();
9254 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9261 if(this.allowBlank && !this.getRawValue().length){
9266 this.indicator.removeClass('visible');
9267 this.indicator.addClass('invisible');
9270 this.el.addClass(this.validClass);
9272 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9274 var feedback = this.el.select('.form-control-feedback', true).first();
9277 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9278 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9283 this.fireEvent('valid', this);
9287 * Mark this field as invalid
9288 * @param {String} msg The validation message
9290 markInvalid : function(msg)
9292 if(!this.el || this.preventMark){ // not rendered
9296 this.el.removeClass([this.invalidClass, this.validClass]);
9298 var feedback = this.el.select('.form-control-feedback', true).first();
9301 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9308 if(this.allowBlank && !this.getRawValue().length){
9313 this.indicator.removeClass('invisible');
9314 this.indicator.addClass('visible');
9317 this.el.addClass(this.invalidClass);
9319 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9321 var feedback = this.el.select('.form-control-feedback', true).first();
9324 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9326 if(this.getValue().length || this.forceFeedback){
9327 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9334 this.fireEvent('invalid', this, msg);
9337 SafariOnKeyDown : function(event)
9339 // this is a workaround for a password hang bug on chrome/ webkit.
9340 if (this.inputEl().dom.type != 'password') {
9344 var isSelectAll = false;
9346 if(this.inputEl().dom.selectionEnd > 0){
9347 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9349 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9350 event.preventDefault();
9355 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9357 event.preventDefault();
9358 // this is very hacky as keydown always get's upper case.
9360 var cc = String.fromCharCode(event.getCharCode());
9361 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9365 adjustWidth : function(tag, w){
9366 tag = tag.toLowerCase();
9367 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9368 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9372 if(tag == 'textarea'){
9375 }else if(Roo.isOpera){
9379 if(tag == 'textarea'){
9387 setFieldLabel : function(v)
9393 this.fieldLabel = v;
9396 var ar = this.el.select('label > span',true);
9397 if (!ar.elements.length) {
9398 Roo.log("could not find label > span on element");
9402 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9406 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9419 * @class Roo.bootstrap.TextArea
9420 * @extends Roo.bootstrap.Input
9421 * Bootstrap TextArea class
9422 * @cfg {Number} cols Specifies the visible width of a text area
9423 * @cfg {Number} rows Specifies the visible number of lines in a text area
9424 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9425 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9426 * @cfg {string} html text
9429 * Create a new TextArea
9430 * @param {Object} config The config object
9433 Roo.bootstrap.TextArea = function(config){
9434 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9438 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9448 getAutoCreate : function(){
9450 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9456 if(this.inputType != 'hidden'){
9457 cfg.cls = 'form-group' //input-group
9465 value : this.value || '',
9466 html: this.html || '',
9467 cls : 'form-control',
9468 placeholder : this.placeholder || ''
9472 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9473 input.maxLength = this.maxLength;
9477 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9481 input.cols = this.cols;
9484 if (this.readOnly) {
9485 input.readonly = true;
9489 input.name = this.name;
9493 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9497 ['xs','sm','md','lg'].map(function(size){
9498 if (settings[size]) {
9499 cfg.cls += ' col-' + size + '-' + settings[size];
9503 var inputblock = input;
9505 if(this.hasFeedback && !this.allowBlank){
9509 cls: 'glyphicon form-control-feedback'
9513 cls : 'has-feedback',
9522 if (this.before || this.after) {
9525 cls : 'input-group',
9529 inputblock.cn.push({
9531 cls : 'input-group-addon',
9536 inputblock.cn.push(input);
9538 if(this.hasFeedback && !this.allowBlank){
9539 inputblock.cls += ' has-feedback';
9540 inputblock.cn.push(feedback);
9544 inputblock.cn.push({
9546 cls : 'input-group-addon',
9553 if (align ==='left' && this.fieldLabel.length) {
9558 cls : 'control-label',
9559 html : this.fieldLabel
9570 if(this.labelWidth > 12){
9571 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9574 if(this.labelWidth < 13 && this.labelmd == 0){
9575 this.labelmd = this.labelWidth;
9578 if(this.labellg > 0){
9579 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9580 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9583 if(this.labelmd > 0){
9584 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9585 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9588 if(this.labelsm > 0){
9589 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9590 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9593 if(this.labelxs > 0){
9594 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9595 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9598 } else if ( this.fieldLabel.length) {
9603 //cls : 'input-group-addon',
9604 html : this.fieldLabel
9622 if (this.disabled) {
9623 input.disabled=true;
9630 * return the real textarea element.
9632 inputEl: function ()
9634 return this.el.select('textarea.form-control',true).first();
9638 * Clear any invalid styles/messages for this field
9640 clearInvalid : function()
9643 if(!this.el || this.preventMark){ // not rendered
9647 var label = this.el.select('label', true).first();
9648 var icon = this.el.select('i.fa-star', true).first();
9654 this.el.removeClass(this.invalidClass);
9656 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9658 var feedback = this.el.select('.form-control-feedback', true).first();
9661 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9666 this.fireEvent('valid', this);
9670 * Mark this field as valid
9672 markValid : function()
9674 if(!this.el || this.preventMark){ // not rendered
9678 this.el.removeClass([this.invalidClass, this.validClass]);
9680 var feedback = this.el.select('.form-control-feedback', true).first();
9683 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9686 if(this.disabled || this.allowBlank){
9690 var label = this.el.select('label', true).first();
9691 var icon = this.el.select('i.fa-star', true).first();
9697 this.el.addClass(this.validClass);
9699 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9701 var feedback = this.el.select('.form-control-feedback', true).first();
9704 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9705 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9710 this.fireEvent('valid', this);
9714 * Mark this field as invalid
9715 * @param {String} msg The validation message
9717 markInvalid : function(msg)
9719 if(!this.el || this.preventMark){ // not rendered
9723 this.el.removeClass([this.invalidClass, this.validClass]);
9725 var feedback = this.el.select('.form-control-feedback', true).first();
9728 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9731 if(this.disabled || this.allowBlank){
9735 var label = this.el.select('label', true).first();
9736 var icon = this.el.select('i.fa-star', true).first();
9738 if(!this.getValue().length && label && !icon){
9739 this.el.createChild({
9741 cls : 'text-danger fa fa-lg fa-star',
9742 tooltip : 'This field is required',
9743 style : 'margin-right:5px;'
9747 this.el.addClass(this.invalidClass);
9749 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9751 var feedback = this.el.select('.form-control-feedback', true).first();
9754 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9756 if(this.getValue().length || this.forceFeedback){
9757 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9764 this.fireEvent('invalid', this, msg);
9772 * trigger field - base class for combo..
9777 * @class Roo.bootstrap.TriggerField
9778 * @extends Roo.bootstrap.Input
9779 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9780 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9781 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9782 * for which you can provide a custom implementation. For example:
9784 var trigger = new Roo.bootstrap.TriggerField();
9785 trigger.onTriggerClick = myTriggerFn;
9786 trigger.applyTo('my-field');
9789 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9790 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9791 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9792 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9793 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9796 * Create a new TriggerField.
9797 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9798 * to the base TextField)
9800 Roo.bootstrap.TriggerField = function(config){
9801 this.mimicing = false;
9802 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9805 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9807 * @cfg {String} triggerClass A CSS class to apply to the trigger
9810 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9815 * @cfg {Boolean} removable (true|false) special filter default false
9819 /** @cfg {Boolean} grow @hide */
9820 /** @cfg {Number} growMin @hide */
9821 /** @cfg {Number} growMax @hide */
9827 autoSize: Roo.emptyFn,
9834 actionMode : 'wrap',
9839 getAutoCreate : function(){
9841 var align = this.labelAlign || this.parentLabelAlign();
9846 cls: 'form-group' //input-group
9853 type : this.inputType,
9854 cls : 'form-control',
9855 autocomplete: 'new-password',
9856 placeholder : this.placeholder || ''
9860 input.name = this.name;
9863 input.cls += ' input-' + this.size;
9866 if (this.disabled) {
9867 input.disabled=true;
9870 var inputblock = input;
9872 if(this.hasFeedback && !this.allowBlank){
9876 cls: 'glyphicon form-control-feedback'
9879 if(this.removable && !this.editable && !this.tickable){
9881 cls : 'has-feedback',
9887 cls : 'roo-combo-removable-btn close'
9894 cls : 'has-feedback',
9903 if(this.removable && !this.editable && !this.tickable){
9905 cls : 'roo-removable',
9911 cls : 'roo-combo-removable-btn close'
9918 if (this.before || this.after) {
9921 cls : 'input-group',
9925 inputblock.cn.push({
9927 cls : 'input-group-addon',
9932 inputblock.cn.push(input);
9934 if(this.hasFeedback && !this.allowBlank){
9935 inputblock.cls += ' has-feedback';
9936 inputblock.cn.push(feedback);
9940 inputblock.cn.push({
9942 cls : 'input-group-addon',
9955 cls: 'form-hidden-field'
9969 cls: 'form-hidden-field'
9973 cls: 'roo-select2-choices',
9977 cls: 'roo-select2-search-field',
9990 cls: 'roo-select2-container input-group',
9995 // cls: 'typeahead typeahead-long dropdown-menu',
9996 // style: 'display:none'
10001 if(!this.multiple && this.showToggleBtn){
10007 if (this.caret != false) {
10010 cls: 'fa fa-' + this.caret
10017 cls : 'input-group-addon btn dropdown-toggle',
10022 cls: 'combobox-clear',
10036 combobox.cls += ' roo-select2-container-multi';
10039 if (align ==='left' && this.fieldLabel.length) {
10041 cfg.cls += ' roo-form-group-label-left';
10046 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10047 tooltip : 'This field is required'
10052 cls : 'control-label',
10053 html : this.fieldLabel
10065 var labelCfg = cfg.cn[1];
10066 var contentCfg = cfg.cn[2];
10068 if(this.indicatorpos == 'right'){
10073 cls : 'control-label',
10077 html : this.fieldLabel
10081 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10082 tooltip : 'This field is required'
10095 labelCfg = cfg.cn[0];
10096 contentCfg = cfg.cn[1];
10099 if(this.labelWidth > 12){
10100 labelCfg.style = "width: " + this.labelWidth + 'px';
10103 if(this.labelWidth < 13 && this.labelmd == 0){
10104 this.labelmd = this.labelWidth;
10107 if(this.labellg > 0){
10108 labelCfg.cls += ' col-lg-' + this.labellg;
10109 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10112 if(this.labelmd > 0){
10113 labelCfg.cls += ' col-md-' + this.labelmd;
10114 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10117 if(this.labelsm > 0){
10118 labelCfg.cls += ' col-sm-' + this.labelsm;
10119 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10122 if(this.labelxs > 0){
10123 labelCfg.cls += ' col-xs-' + this.labelxs;
10124 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10127 } else if ( this.fieldLabel.length) {
10128 // Roo.log(" label");
10132 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10133 tooltip : 'This field is required'
10137 //cls : 'input-group-addon',
10138 html : this.fieldLabel
10146 if(this.indicatorpos == 'right'){
10154 html : this.fieldLabel
10158 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10159 tooltip : 'This field is required'
10172 // Roo.log(" no label && no align");
10179 ['xs','sm','md','lg'].map(function(size){
10180 if (settings[size]) {
10181 cfg.cls += ' col-' + size + '-' + settings[size];
10192 onResize : function(w, h){
10193 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10194 // if(typeof w == 'number'){
10195 // var x = w - this.trigger.getWidth();
10196 // this.inputEl().setWidth(this.adjustWidth('input', x));
10197 // this.trigger.setStyle('left', x+'px');
10202 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10205 getResizeEl : function(){
10206 return this.inputEl();
10210 getPositionEl : function(){
10211 return this.inputEl();
10215 alignErrorIcon : function(){
10216 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10220 initEvents : function(){
10224 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10225 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10226 if(!this.multiple && this.showToggleBtn){
10227 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10228 if(this.hideTrigger){
10229 this.trigger.setDisplayed(false);
10231 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10235 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10238 if(this.removable && !this.editable && !this.tickable){
10239 var close = this.closeTriggerEl();
10242 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10243 close.on('click', this.removeBtnClick, this, close);
10247 //this.trigger.addClassOnOver('x-form-trigger-over');
10248 //this.trigger.addClassOnClick('x-form-trigger-click');
10251 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10255 closeTriggerEl : function()
10257 var close = this.el.select('.roo-combo-removable-btn', true).first();
10258 return close ? close : false;
10261 removeBtnClick : function(e, h, el)
10263 e.preventDefault();
10265 if(this.fireEvent("remove", this) !== false){
10267 this.fireEvent("afterremove", this)
10271 createList : function()
10273 this.list = Roo.get(document.body).createChild({
10275 cls: 'typeahead typeahead-long dropdown-menu',
10276 style: 'display:none'
10279 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10284 initTrigger : function(){
10289 onDestroy : function(){
10291 this.trigger.removeAllListeners();
10292 // this.trigger.remove();
10295 // this.wrap.remove();
10297 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10301 onFocus : function(){
10302 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10304 if(!this.mimicing){
10305 this.wrap.addClass('x-trigger-wrap-focus');
10306 this.mimicing = true;
10307 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10308 if(this.monitorTab){
10309 this.el.on("keydown", this.checkTab, this);
10316 checkTab : function(e){
10317 if(e.getKey() == e.TAB){
10318 this.triggerBlur();
10323 onBlur : function(){
10328 mimicBlur : function(e, t){
10330 if(!this.wrap.contains(t) && this.validateBlur()){
10331 this.triggerBlur();
10337 triggerBlur : function(){
10338 this.mimicing = false;
10339 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10340 if(this.monitorTab){
10341 this.el.un("keydown", this.checkTab, this);
10343 //this.wrap.removeClass('x-trigger-wrap-focus');
10344 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10348 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10349 validateBlur : function(e, t){
10354 onDisable : function(){
10355 this.inputEl().dom.disabled = true;
10356 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10358 // this.wrap.addClass('x-item-disabled');
10363 onEnable : function(){
10364 this.inputEl().dom.disabled = false;
10365 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10367 // this.el.removeClass('x-item-disabled');
10372 onShow : function(){
10373 var ae = this.getActionEl();
10376 ae.dom.style.display = '';
10377 ae.dom.style.visibility = 'visible';
10383 onHide : function(){
10384 var ae = this.getActionEl();
10385 ae.dom.style.display = 'none';
10389 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10390 * by an implementing function.
10392 * @param {EventObject} e
10394 onTriggerClick : Roo.emptyFn
10398 * Ext JS Library 1.1.1
10399 * Copyright(c) 2006-2007, Ext JS, LLC.
10401 * Originally Released Under LGPL - original licence link has changed is not relivant.
10404 * <script type="text/javascript">
10409 * @class Roo.data.SortTypes
10411 * Defines the default sorting (casting?) comparison functions used when sorting data.
10413 Roo.data.SortTypes = {
10415 * Default sort that does nothing
10416 * @param {Mixed} s The value being converted
10417 * @return {Mixed} The comparison value
10419 none : function(s){
10424 * The regular expression used to strip tags
10428 stripTagsRE : /<\/?[^>]+>/gi,
10431 * Strips all HTML tags to sort on text only
10432 * @param {Mixed} s The value being converted
10433 * @return {String} The comparison value
10435 asText : function(s){
10436 return String(s).replace(this.stripTagsRE, "");
10440 * Strips all HTML tags to sort on text only - Case insensitive
10441 * @param {Mixed} s The value being converted
10442 * @return {String} The comparison value
10444 asUCText : function(s){
10445 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10449 * Case insensitive string
10450 * @param {Mixed} s The value being converted
10451 * @return {String} The comparison value
10453 asUCString : function(s) {
10454 return String(s).toUpperCase();
10459 * @param {Mixed} s The value being converted
10460 * @return {Number} The comparison value
10462 asDate : function(s) {
10466 if(s instanceof Date){
10467 return s.getTime();
10469 return Date.parse(String(s));
10474 * @param {Mixed} s The value being converted
10475 * @return {Float} The comparison value
10477 asFloat : function(s) {
10478 var val = parseFloat(String(s).replace(/,/g, ""));
10487 * @param {Mixed} s The value being converted
10488 * @return {Number} The comparison value
10490 asInt : function(s) {
10491 var val = parseInt(String(s).replace(/,/g, ""));
10499 * Ext JS Library 1.1.1
10500 * Copyright(c) 2006-2007, Ext JS, LLC.
10502 * Originally Released Under LGPL - original licence link has changed is not relivant.
10505 * <script type="text/javascript">
10509 * @class Roo.data.Record
10510 * Instances of this class encapsulate both record <em>definition</em> information, and record
10511 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10512 * to access Records cached in an {@link Roo.data.Store} object.<br>
10514 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10515 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10518 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10520 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10521 * {@link #create}. The parameters are the same.
10522 * @param {Array} data An associative Array of data values keyed by the field name.
10523 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10524 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10525 * not specified an integer id is generated.
10527 Roo.data.Record = function(data, id){
10528 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10533 * Generate a constructor for a specific record layout.
10534 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10535 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10536 * Each field definition object may contain the following properties: <ul>
10537 * <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,
10538 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10539 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10540 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10541 * is being used, then this is a string containing the javascript expression to reference the data relative to
10542 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10543 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10544 * this may be omitted.</p></li>
10545 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10546 * <ul><li>auto (Default, implies no conversion)</li>
10551 * <li>date</li></ul></p></li>
10552 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10553 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10554 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10555 * by the Reader into an object that will be stored in the Record. It is passed the
10556 * following parameters:<ul>
10557 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10559 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10561 * <br>usage:<br><pre><code>
10562 var TopicRecord = Roo.data.Record.create(
10563 {name: 'title', mapping: 'topic_title'},
10564 {name: 'author', mapping: 'username'},
10565 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10566 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10567 {name: 'lastPoster', mapping: 'user2'},
10568 {name: 'excerpt', mapping: 'post_text'}
10571 var myNewRecord = new TopicRecord({
10572 title: 'Do my job please',
10575 lastPost: new Date(),
10576 lastPoster: 'Animal',
10577 excerpt: 'No way dude!'
10579 myStore.add(myNewRecord);
10584 Roo.data.Record.create = function(o){
10585 var f = function(){
10586 f.superclass.constructor.apply(this, arguments);
10588 Roo.extend(f, Roo.data.Record);
10589 var p = f.prototype;
10590 p.fields = new Roo.util.MixedCollection(false, function(field){
10593 for(var i = 0, len = o.length; i < len; i++){
10594 p.fields.add(new Roo.data.Field(o[i]));
10596 f.getField = function(name){
10597 return p.fields.get(name);
10602 Roo.data.Record.AUTO_ID = 1000;
10603 Roo.data.Record.EDIT = 'edit';
10604 Roo.data.Record.REJECT = 'reject';
10605 Roo.data.Record.COMMIT = 'commit';
10607 Roo.data.Record.prototype = {
10609 * Readonly flag - true if this record has been modified.
10618 join : function(store){
10619 this.store = store;
10623 * Set the named field to the specified value.
10624 * @param {String} name The name of the field to set.
10625 * @param {Object} value The value to set the field to.
10627 set : function(name, value){
10628 if(this.data[name] == value){
10632 if(!this.modified){
10633 this.modified = {};
10635 if(typeof this.modified[name] == 'undefined'){
10636 this.modified[name] = this.data[name];
10638 this.data[name] = value;
10639 if(!this.editing && this.store){
10640 this.store.afterEdit(this);
10645 * Get the value of the named field.
10646 * @param {String} name The name of the field to get the value of.
10647 * @return {Object} The value of the field.
10649 get : function(name){
10650 return this.data[name];
10654 beginEdit : function(){
10655 this.editing = true;
10656 this.modified = {};
10660 cancelEdit : function(){
10661 this.editing = false;
10662 delete this.modified;
10666 endEdit : function(){
10667 this.editing = false;
10668 if(this.dirty && this.store){
10669 this.store.afterEdit(this);
10674 * Usually called by the {@link Roo.data.Store} which owns the Record.
10675 * Rejects all changes made to the Record since either creation, or the last commit operation.
10676 * Modified fields are reverted to their original values.
10678 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10679 * of reject operations.
10681 reject : function(){
10682 var m = this.modified;
10684 if(typeof m[n] != "function"){
10685 this.data[n] = m[n];
10688 this.dirty = false;
10689 delete this.modified;
10690 this.editing = false;
10692 this.store.afterReject(this);
10697 * Usually called by the {@link Roo.data.Store} which owns the Record.
10698 * Commits all changes made to the Record since either creation, or the last commit operation.
10700 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10701 * of commit operations.
10703 commit : function(){
10704 this.dirty = false;
10705 delete this.modified;
10706 this.editing = false;
10708 this.store.afterCommit(this);
10713 hasError : function(){
10714 return this.error != null;
10718 clearError : function(){
10723 * Creates a copy of this record.
10724 * @param {String} id (optional) A new record id if you don't want to use this record's id
10727 copy : function(newId) {
10728 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10732 * Ext JS Library 1.1.1
10733 * Copyright(c) 2006-2007, Ext JS, LLC.
10735 * Originally Released Under LGPL - original licence link has changed is not relivant.
10738 * <script type="text/javascript">
10744 * @class Roo.data.Store
10745 * @extends Roo.util.Observable
10746 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10747 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10749 * 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
10750 * has no knowledge of the format of the data returned by the Proxy.<br>
10752 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10753 * instances from the data object. These records are cached and made available through accessor functions.
10755 * Creates a new Store.
10756 * @param {Object} config A config object containing the objects needed for the Store to access data,
10757 * and read the data into Records.
10759 Roo.data.Store = function(config){
10760 this.data = new Roo.util.MixedCollection(false);
10761 this.data.getKey = function(o){
10764 this.baseParams = {};
10766 this.paramNames = {
10771 "multisort" : "_multisort"
10774 if(config && config.data){
10775 this.inlineData = config.data;
10776 delete config.data;
10779 Roo.apply(this, config);
10781 if(this.reader){ // reader passed
10782 this.reader = Roo.factory(this.reader, Roo.data);
10783 this.reader.xmodule = this.xmodule || false;
10784 if(!this.recordType){
10785 this.recordType = this.reader.recordType;
10787 if(this.reader.onMetaChange){
10788 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10792 if(this.recordType){
10793 this.fields = this.recordType.prototype.fields;
10795 this.modified = [];
10799 * @event datachanged
10800 * Fires when the data cache has changed, and a widget which is using this Store
10801 * as a Record cache should refresh its view.
10802 * @param {Store} this
10804 datachanged : true,
10806 * @event metachange
10807 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10808 * @param {Store} this
10809 * @param {Object} meta The JSON metadata
10814 * Fires when Records have been added to the Store
10815 * @param {Store} this
10816 * @param {Roo.data.Record[]} records The array of Records added
10817 * @param {Number} index The index at which the record(s) were added
10822 * Fires when a Record has been removed from the Store
10823 * @param {Store} this
10824 * @param {Roo.data.Record} record The Record that was removed
10825 * @param {Number} index The index at which the record was removed
10830 * Fires when a Record has been updated
10831 * @param {Store} this
10832 * @param {Roo.data.Record} record The Record that was updated
10833 * @param {String} operation The update operation being performed. Value may be one of:
10835 Roo.data.Record.EDIT
10836 Roo.data.Record.REJECT
10837 Roo.data.Record.COMMIT
10843 * Fires when the data cache has been cleared.
10844 * @param {Store} this
10848 * @event beforeload
10849 * Fires before a request is made for a new data object. If the beforeload handler returns false
10850 * the load action will be canceled.
10851 * @param {Store} this
10852 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10856 * @event beforeloadadd
10857 * Fires after a new set of Records has been loaded.
10858 * @param {Store} this
10859 * @param {Roo.data.Record[]} records The Records that were loaded
10860 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10862 beforeloadadd : true,
10865 * Fires after a new set of Records has been loaded, before they are added to the store.
10866 * @param {Store} this
10867 * @param {Roo.data.Record[]} records The Records that were loaded
10868 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10869 * @params {Object} return from reader
10873 * @event loadexception
10874 * Fires if an exception occurs in the Proxy during loading.
10875 * Called with the signature of the Proxy's "loadexception" event.
10876 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10879 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10880 * @param {Object} load options
10881 * @param {Object} jsonData from your request (normally this contains the Exception)
10883 loadexception : true
10887 this.proxy = Roo.factory(this.proxy, Roo.data);
10888 this.proxy.xmodule = this.xmodule || false;
10889 this.relayEvents(this.proxy, ["loadexception"]);
10891 this.sortToggle = {};
10892 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10894 Roo.data.Store.superclass.constructor.call(this);
10896 if(this.inlineData){
10897 this.loadData(this.inlineData);
10898 delete this.inlineData;
10902 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10904 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10905 * without a remote query - used by combo/forms at present.
10909 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10912 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10915 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10916 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10919 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10920 * on any HTTP request
10923 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10926 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10930 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10931 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10933 remoteSort : false,
10936 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10937 * loaded or when a record is removed. (defaults to false).
10939 pruneModifiedRecords : false,
10942 lastOptions : null,
10945 * Add Records to the Store and fires the add event.
10946 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10948 add : function(records){
10949 records = [].concat(records);
10950 for(var i = 0, len = records.length; i < len; i++){
10951 records[i].join(this);
10953 var index = this.data.length;
10954 this.data.addAll(records);
10955 this.fireEvent("add", this, records, index);
10959 * Remove a Record from the Store and fires the remove event.
10960 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10962 remove : function(record){
10963 var index = this.data.indexOf(record);
10964 this.data.removeAt(index);
10965 if(this.pruneModifiedRecords){
10966 this.modified.remove(record);
10968 this.fireEvent("remove", this, record, index);
10972 * Remove all Records from the Store and fires the clear event.
10974 removeAll : function(){
10976 if(this.pruneModifiedRecords){
10977 this.modified = [];
10979 this.fireEvent("clear", this);
10983 * Inserts Records to the Store at the given index and fires the add event.
10984 * @param {Number} index The start index at which to insert the passed Records.
10985 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10987 insert : function(index, records){
10988 records = [].concat(records);
10989 for(var i = 0, len = records.length; i < len; i++){
10990 this.data.insert(index, records[i]);
10991 records[i].join(this);
10993 this.fireEvent("add", this, records, index);
10997 * Get the index within the cache of the passed Record.
10998 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10999 * @return {Number} The index of the passed Record. Returns -1 if not found.
11001 indexOf : function(record){
11002 return this.data.indexOf(record);
11006 * Get the index within the cache of the Record with the passed id.
11007 * @param {String} id The id of the Record to find.
11008 * @return {Number} The index of the Record. Returns -1 if not found.
11010 indexOfId : function(id){
11011 return this.data.indexOfKey(id);
11015 * Get the Record with the specified id.
11016 * @param {String} id The id of the Record to find.
11017 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11019 getById : function(id){
11020 return this.data.key(id);
11024 * Get the Record at the specified index.
11025 * @param {Number} index The index of the Record to find.
11026 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11028 getAt : function(index){
11029 return this.data.itemAt(index);
11033 * Returns a range of Records between specified indices.
11034 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11035 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11036 * @return {Roo.data.Record[]} An array of Records
11038 getRange : function(start, end){
11039 return this.data.getRange(start, end);
11043 storeOptions : function(o){
11044 o = Roo.apply({}, o);
11047 this.lastOptions = o;
11051 * Loads the Record cache from the configured Proxy using the configured Reader.
11053 * If using remote paging, then the first load call must specify the <em>start</em>
11054 * and <em>limit</em> properties in the options.params property to establish the initial
11055 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11057 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11058 * and this call will return before the new data has been loaded. Perform any post-processing
11059 * in a callback function, or in a "load" event handler.</strong>
11061 * @param {Object} options An object containing properties which control loading options:<ul>
11062 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11063 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11064 * passed the following arguments:<ul>
11065 * <li>r : Roo.data.Record[]</li>
11066 * <li>options: Options object from the load call</li>
11067 * <li>success: Boolean success indicator</li></ul></li>
11068 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11069 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11072 load : function(options){
11073 options = options || {};
11074 if(this.fireEvent("beforeload", this, options) !== false){
11075 this.storeOptions(options);
11076 var p = Roo.apply(options.params || {}, this.baseParams);
11077 // if meta was not loaded from remote source.. try requesting it.
11078 if (!this.reader.metaFromRemote) {
11079 p._requestMeta = 1;
11081 if(this.sortInfo && this.remoteSort){
11082 var pn = this.paramNames;
11083 p[pn["sort"]] = this.sortInfo.field;
11084 p[pn["dir"]] = this.sortInfo.direction;
11086 if (this.multiSort) {
11087 var pn = this.paramNames;
11088 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11091 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11096 * Reloads the Record cache from the configured Proxy using the configured Reader and
11097 * the options from the last load operation performed.
11098 * @param {Object} options (optional) An object containing properties which may override the options
11099 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11100 * the most recently used options are reused).
11102 reload : function(options){
11103 this.load(Roo.applyIf(options||{}, this.lastOptions));
11107 // Called as a callback by the Reader during a load operation.
11108 loadRecords : function(o, options, success){
11109 if(!o || success === false){
11110 if(success !== false){
11111 this.fireEvent("load", this, [], options, o);
11113 if(options.callback){
11114 options.callback.call(options.scope || this, [], options, false);
11118 // if data returned failure - throw an exception.
11119 if (o.success === false) {
11120 // show a message if no listener is registered.
11121 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11122 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11124 // loadmask wil be hooked into this..
11125 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11128 var r = o.records, t = o.totalRecords || r.length;
11130 this.fireEvent("beforeloadadd", this, r, options, o);
11132 if(!options || options.add !== true){
11133 if(this.pruneModifiedRecords){
11134 this.modified = [];
11136 for(var i = 0, len = r.length; i < len; i++){
11140 this.data = this.snapshot;
11141 delete this.snapshot;
11144 this.data.addAll(r);
11145 this.totalLength = t;
11147 this.fireEvent("datachanged", this);
11149 this.totalLength = Math.max(t, this.data.length+r.length);
11153 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11155 var e = new Roo.data.Record({});
11157 e.set(this.parent.displayField, this.parent.emptyTitle);
11158 e.set(this.parent.valueField, '');
11163 this.fireEvent("load", this, r, options, o);
11164 if(options.callback){
11165 options.callback.call(options.scope || this, r, options, true);
11171 * Loads data from a passed data block. A Reader which understands the format of the data
11172 * must have been configured in the constructor.
11173 * @param {Object} data The data block from which to read the Records. The format of the data expected
11174 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11175 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11177 loadData : function(o, append){
11178 var r = this.reader.readRecords(o);
11179 this.loadRecords(r, {add: append}, true);
11183 * Gets the number of cached records.
11185 * <em>If using paging, this may not be the total size of the dataset. If the data object
11186 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11187 * the data set size</em>
11189 getCount : function(){
11190 return this.data.length || 0;
11194 * Gets the total number of records in the dataset as returned by the server.
11196 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11197 * the dataset size</em>
11199 getTotalCount : function(){
11200 return this.totalLength || 0;
11204 * Returns the sort state of the Store as an object with two properties:
11206 field {String} The name of the field by which the Records are sorted
11207 direction {String} The sort order, "ASC" or "DESC"
11210 getSortState : function(){
11211 return this.sortInfo;
11215 applySort : function(){
11216 if(this.sortInfo && !this.remoteSort){
11217 var s = this.sortInfo, f = s.field;
11218 var st = this.fields.get(f).sortType;
11219 var fn = function(r1, r2){
11220 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11221 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11223 this.data.sort(s.direction, fn);
11224 if(this.snapshot && this.snapshot != this.data){
11225 this.snapshot.sort(s.direction, fn);
11231 * Sets the default sort column and order to be used by the next load operation.
11232 * @param {String} fieldName The name of the field to sort by.
11233 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11235 setDefaultSort : function(field, dir){
11236 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11240 * Sort the Records.
11241 * If remote sorting is used, the sort is performed on the server, and the cache is
11242 * reloaded. If local sorting is used, the cache is sorted internally.
11243 * @param {String} fieldName The name of the field to sort by.
11244 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11246 sort : function(fieldName, dir){
11247 var f = this.fields.get(fieldName);
11249 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11251 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11252 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11257 this.sortToggle[f.name] = dir;
11258 this.sortInfo = {field: f.name, direction: dir};
11259 if(!this.remoteSort){
11261 this.fireEvent("datachanged", this);
11263 this.load(this.lastOptions);
11268 * Calls the specified function for each of the Records in the cache.
11269 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11270 * Returning <em>false</em> aborts and exits the iteration.
11271 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11273 each : function(fn, scope){
11274 this.data.each(fn, scope);
11278 * Gets all records modified since the last commit. Modified records are persisted across load operations
11279 * (e.g., during paging).
11280 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11282 getModifiedRecords : function(){
11283 return this.modified;
11287 createFilterFn : function(property, value, anyMatch){
11288 if(!value.exec){ // not a regex
11289 value = String(value);
11290 if(value.length == 0){
11293 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11295 return function(r){
11296 return value.test(r.data[property]);
11301 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11302 * @param {String} property A field on your records
11303 * @param {Number} start The record index to start at (defaults to 0)
11304 * @param {Number} end The last record index to include (defaults to length - 1)
11305 * @return {Number} The sum
11307 sum : function(property, start, end){
11308 var rs = this.data.items, v = 0;
11309 start = start || 0;
11310 end = (end || end === 0) ? end : rs.length-1;
11312 for(var i = start; i <= end; i++){
11313 v += (rs[i].data[property] || 0);
11319 * Filter the records by a specified property.
11320 * @param {String} field A field on your records
11321 * @param {String/RegExp} value Either a string that the field
11322 * should start with or a RegExp to test against the field
11323 * @param {Boolean} anyMatch True to match any part not just the beginning
11325 filter : function(property, value, anyMatch){
11326 var fn = this.createFilterFn(property, value, anyMatch);
11327 return fn ? this.filterBy(fn) : this.clearFilter();
11331 * Filter by a function. The specified function will be called with each
11332 * record in this data source. If the function returns true the record is included,
11333 * otherwise it is filtered.
11334 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11335 * @param {Object} scope (optional) The scope of the function (defaults to this)
11337 filterBy : function(fn, scope){
11338 this.snapshot = this.snapshot || this.data;
11339 this.data = this.queryBy(fn, scope||this);
11340 this.fireEvent("datachanged", this);
11344 * Query the records by a specified property.
11345 * @param {String} field A field on your records
11346 * @param {String/RegExp} value Either a string that the field
11347 * should start with or a RegExp to test against the field
11348 * @param {Boolean} anyMatch True to match any part not just the beginning
11349 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11351 query : function(property, value, anyMatch){
11352 var fn = this.createFilterFn(property, value, anyMatch);
11353 return fn ? this.queryBy(fn) : this.data.clone();
11357 * Query by a function. The specified function will be called with each
11358 * record in this data source. If the function returns true the record is included
11360 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11361 * @param {Object} scope (optional) The scope of the function (defaults to this)
11362 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11364 queryBy : function(fn, scope){
11365 var data = this.snapshot || this.data;
11366 return data.filterBy(fn, scope||this);
11370 * Collects unique values for a particular dataIndex from this store.
11371 * @param {String} dataIndex The property to collect
11372 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11373 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11374 * @return {Array} An array of the unique values
11376 collect : function(dataIndex, allowNull, bypassFilter){
11377 var d = (bypassFilter === true && this.snapshot) ?
11378 this.snapshot.items : this.data.items;
11379 var v, sv, r = [], l = {};
11380 for(var i = 0, len = d.length; i < len; i++){
11381 v = d[i].data[dataIndex];
11383 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11392 * Revert to a view of the Record cache with no filtering applied.
11393 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11395 clearFilter : function(suppressEvent){
11396 if(this.snapshot && this.snapshot != this.data){
11397 this.data = this.snapshot;
11398 delete this.snapshot;
11399 if(suppressEvent !== true){
11400 this.fireEvent("datachanged", this);
11406 afterEdit : function(record){
11407 if(this.modified.indexOf(record) == -1){
11408 this.modified.push(record);
11410 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11414 afterReject : function(record){
11415 this.modified.remove(record);
11416 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11420 afterCommit : function(record){
11421 this.modified.remove(record);
11422 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11426 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11427 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11429 commitChanges : function(){
11430 var m = this.modified.slice(0);
11431 this.modified = [];
11432 for(var i = 0, len = m.length; i < len; i++){
11438 * Cancel outstanding changes on all changed records.
11440 rejectChanges : function(){
11441 var m = this.modified.slice(0);
11442 this.modified = [];
11443 for(var i = 0, len = m.length; i < len; i++){
11448 onMetaChange : function(meta, rtype, o){
11449 this.recordType = rtype;
11450 this.fields = rtype.prototype.fields;
11451 delete this.snapshot;
11452 this.sortInfo = meta.sortInfo || this.sortInfo;
11453 this.modified = [];
11454 this.fireEvent('metachange', this, this.reader.meta);
11457 moveIndex : function(data, type)
11459 var index = this.indexOf(data);
11461 var newIndex = index + type;
11465 this.insert(newIndex, data);
11470 * Ext JS Library 1.1.1
11471 * Copyright(c) 2006-2007, Ext JS, LLC.
11473 * Originally Released Under LGPL - original licence link has changed is not relivant.
11476 * <script type="text/javascript">
11480 * @class Roo.data.SimpleStore
11481 * @extends Roo.data.Store
11482 * Small helper class to make creating Stores from Array data easier.
11483 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11484 * @cfg {Array} fields An array of field definition objects, or field name strings.
11485 * @cfg {Array} data The multi-dimensional array of data
11487 * @param {Object} config
11489 Roo.data.SimpleStore = function(config){
11490 Roo.data.SimpleStore.superclass.constructor.call(this, {
11492 reader: new Roo.data.ArrayReader({
11495 Roo.data.Record.create(config.fields)
11497 proxy : new Roo.data.MemoryProxy(config.data)
11501 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11503 * Ext JS Library 1.1.1
11504 * Copyright(c) 2006-2007, Ext JS, LLC.
11506 * Originally Released Under LGPL - original licence link has changed is not relivant.
11509 * <script type="text/javascript">
11514 * @extends Roo.data.Store
11515 * @class Roo.data.JsonStore
11516 * Small helper class to make creating Stores for JSON data easier. <br/>
11518 var store = new Roo.data.JsonStore({
11519 url: 'get-images.php',
11521 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11524 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11525 * JsonReader and HttpProxy (unless inline data is provided).</b>
11526 * @cfg {Array} fields An array of field definition objects, or field name strings.
11528 * @param {Object} config
11530 Roo.data.JsonStore = function(c){
11531 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11532 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11533 reader: new Roo.data.JsonReader(c, c.fields)
11536 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11538 * Ext JS Library 1.1.1
11539 * Copyright(c) 2006-2007, Ext JS, LLC.
11541 * Originally Released Under LGPL - original licence link has changed is not relivant.
11544 * <script type="text/javascript">
11548 Roo.data.Field = function(config){
11549 if(typeof config == "string"){
11550 config = {name: config};
11552 Roo.apply(this, config);
11555 this.type = "auto";
11558 var st = Roo.data.SortTypes;
11559 // named sortTypes are supported, here we look them up
11560 if(typeof this.sortType == "string"){
11561 this.sortType = st[this.sortType];
11564 // set default sortType for strings and dates
11565 if(!this.sortType){
11568 this.sortType = st.asUCString;
11571 this.sortType = st.asDate;
11574 this.sortType = st.none;
11579 var stripRe = /[\$,%]/g;
11581 // prebuilt conversion function for this field, instead of
11582 // switching every time we're reading a value
11584 var cv, dateFormat = this.dateFormat;
11589 cv = function(v){ return v; };
11592 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11596 return v !== undefined && v !== null && v !== '' ?
11597 parseInt(String(v).replace(stripRe, ""), 10) : '';
11602 return v !== undefined && v !== null && v !== '' ?
11603 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11608 cv = function(v){ return v === true || v === "true" || v == 1; };
11615 if(v instanceof Date){
11619 if(dateFormat == "timestamp"){
11620 return new Date(v*1000);
11622 return Date.parseDate(v, dateFormat);
11624 var parsed = Date.parse(v);
11625 return parsed ? new Date(parsed) : null;
11634 Roo.data.Field.prototype = {
11642 * Ext JS Library 1.1.1
11643 * Copyright(c) 2006-2007, Ext JS, LLC.
11645 * Originally Released Under LGPL - original licence link has changed is not relivant.
11648 * <script type="text/javascript">
11651 // Base class for reading structured data from a data source. This class is intended to be
11652 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11655 * @class Roo.data.DataReader
11656 * Base class for reading structured data from a data source. This class is intended to be
11657 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11660 Roo.data.DataReader = function(meta, recordType){
11664 this.recordType = recordType instanceof Array ?
11665 Roo.data.Record.create(recordType) : recordType;
11668 Roo.data.DataReader.prototype = {
11670 * Create an empty record
11671 * @param {Object} data (optional) - overlay some values
11672 * @return {Roo.data.Record} record created.
11674 newRow : function(d) {
11676 this.recordType.prototype.fields.each(function(c) {
11678 case 'int' : da[c.name] = 0; break;
11679 case 'date' : da[c.name] = new Date(); break;
11680 case 'float' : da[c.name] = 0.0; break;
11681 case 'boolean' : da[c.name] = false; break;
11682 default : da[c.name] = ""; break;
11686 return new this.recordType(Roo.apply(da, d));
11691 * Ext JS Library 1.1.1
11692 * Copyright(c) 2006-2007, Ext JS, LLC.
11694 * Originally Released Under LGPL - original licence link has changed is not relivant.
11697 * <script type="text/javascript">
11701 * @class Roo.data.DataProxy
11702 * @extends Roo.data.Observable
11703 * This class is an abstract base class for implementations which provide retrieval of
11704 * unformatted data objects.<br>
11706 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11707 * (of the appropriate type which knows how to parse the data object) to provide a block of
11708 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11710 * Custom implementations must implement the load method as described in
11711 * {@link Roo.data.HttpProxy#load}.
11713 Roo.data.DataProxy = function(){
11716 * @event beforeload
11717 * Fires before a network request is made to retrieve a data object.
11718 * @param {Object} This DataProxy object.
11719 * @param {Object} params The params parameter to the load function.
11724 * Fires before the load method's callback is called.
11725 * @param {Object} This DataProxy object.
11726 * @param {Object} o The data object.
11727 * @param {Object} arg The callback argument object passed to the load function.
11731 * @event loadexception
11732 * Fires if an Exception occurs during data retrieval.
11733 * @param {Object} This DataProxy object.
11734 * @param {Object} o The data object.
11735 * @param {Object} arg The callback argument object passed to the load function.
11736 * @param {Object} e The Exception.
11738 loadexception : true
11740 Roo.data.DataProxy.superclass.constructor.call(this);
11743 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11746 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11750 * Ext JS Library 1.1.1
11751 * Copyright(c) 2006-2007, Ext JS, LLC.
11753 * Originally Released Under LGPL - original licence link has changed is not relivant.
11756 * <script type="text/javascript">
11759 * @class Roo.data.MemoryProxy
11760 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11761 * to the Reader when its load method is called.
11763 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11765 Roo.data.MemoryProxy = function(data){
11769 Roo.data.MemoryProxy.superclass.constructor.call(this);
11773 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11776 * Load data from the requested source (in this case an in-memory
11777 * data object passed to the constructor), read the data object into
11778 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11779 * process that block using the passed callback.
11780 * @param {Object} params This parameter is not used by the MemoryProxy class.
11781 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11782 * object into a block of Roo.data.Records.
11783 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11784 * The function must be passed <ul>
11785 * <li>The Record block object</li>
11786 * <li>The "arg" argument from the load function</li>
11787 * <li>A boolean success indicator</li>
11789 * @param {Object} scope The scope in which to call the callback
11790 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11792 load : function(params, reader, callback, scope, arg){
11793 params = params || {};
11796 result = reader.readRecords(this.data);
11798 this.fireEvent("loadexception", this, arg, null, e);
11799 callback.call(scope, null, arg, false);
11802 callback.call(scope, result, arg, true);
11806 update : function(params, records){
11811 * Ext JS Library 1.1.1
11812 * Copyright(c) 2006-2007, Ext JS, LLC.
11814 * Originally Released Under LGPL - original licence link has changed is not relivant.
11817 * <script type="text/javascript">
11820 * @class Roo.data.HttpProxy
11821 * @extends Roo.data.DataProxy
11822 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11823 * configured to reference a certain URL.<br><br>
11825 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11826 * from which the running page was served.<br><br>
11828 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11830 * Be aware that to enable the browser to parse an XML document, the server must set
11831 * the Content-Type header in the HTTP response to "text/xml".
11833 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11834 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11835 * will be used to make the request.
11837 Roo.data.HttpProxy = function(conn){
11838 Roo.data.HttpProxy.superclass.constructor.call(this);
11839 // is conn a conn config or a real conn?
11841 this.useAjax = !conn || !conn.events;
11845 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11846 // thse are take from connection...
11849 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11852 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11853 * extra parameters to each request made by this object. (defaults to undefined)
11856 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11857 * to each request made by this object. (defaults to undefined)
11860 * @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)
11863 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11866 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11872 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11876 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11877 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11878 * a finer-grained basis than the DataProxy events.
11880 getConnection : function(){
11881 return this.useAjax ? Roo.Ajax : this.conn;
11885 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11886 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11887 * process that block using the passed callback.
11888 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11889 * for the request to the remote server.
11890 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11891 * object into a block of Roo.data.Records.
11892 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11893 * The function must be passed <ul>
11894 * <li>The Record block object</li>
11895 * <li>The "arg" argument from the load function</li>
11896 * <li>A boolean success indicator</li>
11898 * @param {Object} scope The scope in which to call the callback
11899 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11901 load : function(params, reader, callback, scope, arg){
11902 if(this.fireEvent("beforeload", this, params) !== false){
11904 params : params || {},
11906 callback : callback,
11911 callback : this.loadResponse,
11915 Roo.applyIf(o, this.conn);
11916 if(this.activeRequest){
11917 Roo.Ajax.abort(this.activeRequest);
11919 this.activeRequest = Roo.Ajax.request(o);
11921 this.conn.request(o);
11924 callback.call(scope||this, null, arg, false);
11929 loadResponse : function(o, success, response){
11930 delete this.activeRequest;
11932 this.fireEvent("loadexception", this, o, response);
11933 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11938 result = o.reader.read(response);
11940 this.fireEvent("loadexception", this, o, response, e);
11941 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11945 this.fireEvent("load", this, o, o.request.arg);
11946 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11950 update : function(dataSet){
11955 updateResponse : function(dataSet){
11960 * Ext JS Library 1.1.1
11961 * Copyright(c) 2006-2007, Ext JS, LLC.
11963 * Originally Released Under LGPL - original licence link has changed is not relivant.
11966 * <script type="text/javascript">
11970 * @class Roo.data.ScriptTagProxy
11971 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11972 * other than the originating domain of the running page.<br><br>
11974 * <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
11975 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11977 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11978 * source code that is used as the source inside a <script> tag.<br><br>
11980 * In order for the browser to process the returned data, the server must wrap the data object
11981 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11982 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11983 * depending on whether the callback name was passed:
11986 boolean scriptTag = false;
11987 String cb = request.getParameter("callback");
11990 response.setContentType("text/javascript");
11992 response.setContentType("application/x-json");
11994 Writer out = response.getWriter();
11996 out.write(cb + "(");
11998 out.print(dataBlock.toJsonString());
12005 * @param {Object} config A configuration object.
12007 Roo.data.ScriptTagProxy = function(config){
12008 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12009 Roo.apply(this, config);
12010 this.head = document.getElementsByTagName("head")[0];
12013 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12015 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12017 * @cfg {String} url The URL from which to request the data object.
12020 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12024 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12025 * the server the name of the callback function set up by the load call to process the returned data object.
12026 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12027 * javascript output which calls this named function passing the data object as its only parameter.
12029 callbackParam : "callback",
12031 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12032 * name to the request.
12037 * Load data from the configured URL, read the data object into
12038 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12039 * process that block using the passed callback.
12040 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12041 * for the request to the remote server.
12042 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12043 * object into a block of Roo.data.Records.
12044 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12045 * The function must be passed <ul>
12046 * <li>The Record block object</li>
12047 * <li>The "arg" argument from the load function</li>
12048 * <li>A boolean success indicator</li>
12050 * @param {Object} scope The scope in which to call the callback
12051 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12053 load : function(params, reader, callback, scope, arg){
12054 if(this.fireEvent("beforeload", this, params) !== false){
12056 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12058 var url = this.url;
12059 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12061 url += "&_dc=" + (new Date().getTime());
12063 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12066 cb : "stcCallback"+transId,
12067 scriptId : "stcScript"+transId,
12071 callback : callback,
12077 window[trans.cb] = function(o){
12078 conn.handleResponse(o, trans);
12081 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12083 if(this.autoAbort !== false){
12087 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12089 var script = document.createElement("script");
12090 script.setAttribute("src", url);
12091 script.setAttribute("type", "text/javascript");
12092 script.setAttribute("id", trans.scriptId);
12093 this.head.appendChild(script);
12095 this.trans = trans;
12097 callback.call(scope||this, null, arg, false);
12102 isLoading : function(){
12103 return this.trans ? true : false;
12107 * Abort the current server request.
12109 abort : function(){
12110 if(this.isLoading()){
12111 this.destroyTrans(this.trans);
12116 destroyTrans : function(trans, isLoaded){
12117 this.head.removeChild(document.getElementById(trans.scriptId));
12118 clearTimeout(trans.timeoutId);
12120 window[trans.cb] = undefined;
12122 delete window[trans.cb];
12125 // if hasn't been loaded, wait for load to remove it to prevent script error
12126 window[trans.cb] = function(){
12127 window[trans.cb] = undefined;
12129 delete window[trans.cb];
12136 handleResponse : function(o, trans){
12137 this.trans = false;
12138 this.destroyTrans(trans, true);
12141 result = trans.reader.readRecords(o);
12143 this.fireEvent("loadexception", this, o, trans.arg, e);
12144 trans.callback.call(trans.scope||window, null, trans.arg, false);
12147 this.fireEvent("load", this, o, trans.arg);
12148 trans.callback.call(trans.scope||window, result, trans.arg, true);
12152 handleFailure : function(trans){
12153 this.trans = false;
12154 this.destroyTrans(trans, false);
12155 this.fireEvent("loadexception", this, null, trans.arg);
12156 trans.callback.call(trans.scope||window, null, trans.arg, false);
12160 * Ext JS Library 1.1.1
12161 * Copyright(c) 2006-2007, Ext JS, LLC.
12163 * Originally Released Under LGPL - original licence link has changed is not relivant.
12166 * <script type="text/javascript">
12170 * @class Roo.data.JsonReader
12171 * @extends Roo.data.DataReader
12172 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12173 * based on mappings in a provided Roo.data.Record constructor.
12175 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12176 * in the reply previously.
12181 var RecordDef = Roo.data.Record.create([
12182 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12183 {name: 'occupation'} // This field will use "occupation" as the mapping.
12185 var myReader = new Roo.data.JsonReader({
12186 totalProperty: "results", // The property which contains the total dataset size (optional)
12187 root: "rows", // The property which contains an Array of row objects
12188 id: "id" // The property within each row object that provides an ID for the record (optional)
12192 * This would consume a JSON file like this:
12194 { 'results': 2, 'rows': [
12195 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12196 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12199 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12200 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12201 * paged from the remote server.
12202 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12203 * @cfg {String} root name of the property which contains the Array of row objects.
12204 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12205 * @cfg {Array} fields Array of field definition objects
12207 * Create a new JsonReader
12208 * @param {Object} meta Metadata configuration options
12209 * @param {Object} recordType Either an Array of field definition objects,
12210 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12212 Roo.data.JsonReader = function(meta, recordType){
12215 // set some defaults:
12216 Roo.applyIf(meta, {
12217 totalProperty: 'total',
12218 successProperty : 'success',
12223 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12225 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12228 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12229 * Used by Store query builder to append _requestMeta to params.
12232 metaFromRemote : false,
12234 * This method is only used by a DataProxy which has retrieved data from a remote server.
12235 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12236 * @return {Object} data A data block which is used by an Roo.data.Store object as
12237 * a cache of Roo.data.Records.
12239 read : function(response){
12240 var json = response.responseText;
12242 var o = /* eval:var:o */ eval("("+json+")");
12244 throw {message: "JsonReader.read: Json object not found"};
12250 this.metaFromRemote = true;
12251 this.meta = o.metaData;
12252 this.recordType = Roo.data.Record.create(o.metaData.fields);
12253 this.onMetaChange(this.meta, this.recordType, o);
12255 return this.readRecords(o);
12258 // private function a store will implement
12259 onMetaChange : function(meta, recordType, o){
12266 simpleAccess: function(obj, subsc) {
12273 getJsonAccessor: function(){
12275 return function(expr) {
12277 return(re.test(expr))
12278 ? new Function("obj", "return obj." + expr)
12283 return Roo.emptyFn;
12288 * Create a data block containing Roo.data.Records from an XML document.
12289 * @param {Object} o An object which contains an Array of row objects in the property specified
12290 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12291 * which contains the total size of the dataset.
12292 * @return {Object} data A data block which is used by an Roo.data.Store object as
12293 * a cache of Roo.data.Records.
12295 readRecords : function(o){
12297 * After any data loads, the raw JSON data is available for further custom processing.
12301 var s = this.meta, Record = this.recordType,
12302 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12304 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12306 if(s.totalProperty) {
12307 this.getTotal = this.getJsonAccessor(s.totalProperty);
12309 if(s.successProperty) {
12310 this.getSuccess = this.getJsonAccessor(s.successProperty);
12312 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12314 var g = this.getJsonAccessor(s.id);
12315 this.getId = function(rec) {
12317 return (r === undefined || r === "") ? null : r;
12320 this.getId = function(){return null;};
12323 for(var jj = 0; jj < fl; jj++){
12325 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12326 this.ef[jj] = this.getJsonAccessor(map);
12330 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12331 if(s.totalProperty){
12332 var vt = parseInt(this.getTotal(o), 10);
12337 if(s.successProperty){
12338 var vs = this.getSuccess(o);
12339 if(vs === false || vs === 'false'){
12344 for(var i = 0; i < c; i++){
12347 var id = this.getId(n);
12348 for(var j = 0; j < fl; j++){
12350 var v = this.ef[j](n);
12352 Roo.log('missing convert for ' + f.name);
12356 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12358 var record = new Record(values, id);
12360 records[i] = record;
12366 totalRecords : totalRecords
12371 * Ext JS Library 1.1.1
12372 * Copyright(c) 2006-2007, Ext JS, LLC.
12374 * Originally Released Under LGPL - original licence link has changed is not relivant.
12377 * <script type="text/javascript">
12381 * @class Roo.data.ArrayReader
12382 * @extends Roo.data.DataReader
12383 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12384 * Each element of that Array represents a row of data fields. The
12385 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12386 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12390 var RecordDef = Roo.data.Record.create([
12391 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12392 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12394 var myReader = new Roo.data.ArrayReader({
12395 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12399 * This would consume an Array like this:
12401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12403 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12405 * Create a new JsonReader
12406 * @param {Object} meta Metadata configuration options.
12407 * @param {Object} recordType Either an Array of field definition objects
12408 * as specified to {@link Roo.data.Record#create},
12409 * or an {@link Roo.data.Record} object
12410 * created using {@link Roo.data.Record#create}.
12412 Roo.data.ArrayReader = function(meta, recordType){
12413 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12418 * Create a data block containing Roo.data.Records from an XML document.
12419 * @param {Object} o An Array of row objects which represents the dataset.
12420 * @return {Object} data A data block which is used by an Roo.data.Store object as
12421 * a cache of Roo.data.Records.
12423 readRecords : function(o){
12424 var sid = this.meta ? this.meta.id : null;
12425 var recordType = this.recordType, fields = recordType.prototype.fields;
12428 for(var i = 0; i < root.length; i++){
12431 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12432 for(var j = 0, jlen = fields.length; j < jlen; j++){
12433 var f = fields.items[j];
12434 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12435 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12437 values[f.name] = v;
12439 var record = new recordType(values, id);
12441 records[records.length] = record;
12445 totalRecords : records.length
12454 * @class Roo.bootstrap.ComboBox
12455 * @extends Roo.bootstrap.TriggerField
12456 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12457 * @cfg {Boolean} append (true|false) default false
12458 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12459 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12460 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12461 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12462 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12463 * @cfg {Boolean} animate default true
12464 * @cfg {Boolean} emptyResultText only for touch device
12465 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12466 * @cfg {String} emptyTitle default ''
12468 * Create a new ComboBox.
12469 * @param {Object} config Configuration options
12471 Roo.bootstrap.ComboBox = function(config){
12472 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12476 * Fires when the dropdown list is expanded
12477 * @param {Roo.bootstrap.ComboBox} combo This combo box
12482 * Fires when the dropdown list is collapsed
12483 * @param {Roo.bootstrap.ComboBox} combo This combo box
12487 * @event beforeselect
12488 * Fires before a list item is selected. Return false to cancel the selection.
12489 * @param {Roo.bootstrap.ComboBox} combo This combo box
12490 * @param {Roo.data.Record} record The data record returned from the underlying store
12491 * @param {Number} index The index of the selected item in the dropdown list
12493 'beforeselect' : true,
12496 * Fires when a list item is selected
12497 * @param {Roo.bootstrap.ComboBox} combo This combo box
12498 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12499 * @param {Number} index The index of the selected item in the dropdown list
12503 * @event beforequery
12504 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12505 * The event object passed has these properties:
12506 * @param {Roo.bootstrap.ComboBox} combo This combo box
12507 * @param {String} query The query
12508 * @param {Boolean} forceAll true to force "all" query
12509 * @param {Boolean} cancel true to cancel the query
12510 * @param {Object} e The query event object
12512 'beforequery': true,
12515 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12516 * @param {Roo.bootstrap.ComboBox} combo This combo box
12521 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12522 * @param {Roo.bootstrap.ComboBox} combo This combo box
12523 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12528 * Fires when the remove value from the combobox array
12529 * @param {Roo.bootstrap.ComboBox} combo This combo box
12533 * @event afterremove
12534 * Fires when the remove value from the combobox array
12535 * @param {Roo.bootstrap.ComboBox} combo This combo box
12537 'afterremove' : true,
12539 * @event specialfilter
12540 * Fires when specialfilter
12541 * @param {Roo.bootstrap.ComboBox} combo This combo box
12543 'specialfilter' : true,
12546 * Fires when tick the element
12547 * @param {Roo.bootstrap.ComboBox} combo This combo box
12551 * @event touchviewdisplay
12552 * Fires when touch view require special display (default is using displayField)
12553 * @param {Roo.bootstrap.ComboBox} combo This combo box
12554 * @param {Object} cfg set html .
12556 'touchviewdisplay' : true
12561 this.tickItems = [];
12563 this.selectedIndex = -1;
12564 if(this.mode == 'local'){
12565 if(config.queryDelay === undefined){
12566 this.queryDelay = 10;
12568 if(config.minChars === undefined){
12574 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12577 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12578 * rendering into an Roo.Editor, defaults to false)
12581 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12582 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12585 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12588 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12589 * the dropdown list (defaults to undefined, with no header element)
12593 * @cfg {String/Roo.Template} tpl The template to use to render the output
12597 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12599 listWidth: undefined,
12601 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12602 * mode = 'remote' or 'text' if mode = 'local')
12604 displayField: undefined,
12607 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12608 * mode = 'remote' or 'value' if mode = 'local').
12609 * Note: use of a valueField requires the user make a selection
12610 * in order for a value to be mapped.
12612 valueField: undefined,
12614 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12619 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12620 * field's data value (defaults to the underlying DOM element's name)
12622 hiddenName: undefined,
12624 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12628 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12630 selectedClass: 'active',
12633 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12637 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12638 * anchor positions (defaults to 'tl-bl')
12640 listAlign: 'tl-bl?',
12642 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12646 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12647 * query specified by the allQuery config option (defaults to 'query')
12649 triggerAction: 'query',
12651 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12652 * (defaults to 4, does not apply if editable = false)
12656 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12657 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12661 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12662 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12666 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12667 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12671 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12672 * when editable = true (defaults to false)
12674 selectOnFocus:false,
12676 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12678 queryParam: 'query',
12680 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12681 * when mode = 'remote' (defaults to 'Loading...')
12683 loadingText: 'Loading...',
12685 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12689 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12693 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12694 * traditional select (defaults to true)
12698 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12702 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12706 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12707 * listWidth has a higher value)
12711 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12712 * allow the user to set arbitrary text into the field (defaults to false)
12714 forceSelection:false,
12716 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12717 * if typeAhead = true (defaults to 250)
12719 typeAheadDelay : 250,
12721 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12722 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12724 valueNotFoundText : undefined,
12726 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12728 blockFocus : false,
12731 * @cfg {Boolean} disableClear Disable showing of clear button.
12733 disableClear : false,
12735 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12737 alwaysQuery : false,
12740 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12745 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12747 invalidClass : "has-warning",
12750 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12752 validClass : "has-success",
12755 * @cfg {Boolean} specialFilter (true|false) special filter default false
12757 specialFilter : false,
12760 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12762 mobileTouchView : true,
12765 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12767 useNativeIOS : false,
12769 ios_options : false,
12781 btnPosition : 'right',
12782 triggerList : true,
12783 showToggleBtn : true,
12785 emptyResultText: 'Empty',
12786 triggerText : 'Select',
12789 // element that contains real text value.. (when hidden is used..)
12791 getAutoCreate : function()
12796 * Render classic select for iso
12799 if(Roo.isIOS && this.useNativeIOS){
12800 cfg = this.getAutoCreateNativeIOS();
12808 if(Roo.isTouch && this.mobileTouchView){
12809 cfg = this.getAutoCreateTouchView();
12816 if(!this.tickable){
12817 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12822 * ComboBox with tickable selections
12825 var align = this.labelAlign || this.parentLabelAlign();
12828 cls : 'form-group roo-combobox-tickable' //input-group
12831 var btn_text_select = '';
12832 var btn_text_done = '';
12833 var btn_text_cancel = '';
12835 if (this.btn_text_show) {
12836 btn_text_select = 'Select';
12837 btn_text_done = 'Done';
12838 btn_text_cancel = 'Cancel';
12843 cls : 'tickable-buttons',
12848 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12849 //html : this.triggerText
12850 html: btn_text_select
12856 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12858 html: btn_text_done
12864 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12866 html: btn_text_cancel
12872 buttons.cn.unshift({
12874 cls: 'roo-select2-search-field-input'
12880 Roo.each(buttons.cn, function(c){
12882 c.cls += ' btn-' + _this.size;
12885 if (_this.disabled) {
12896 cls: 'form-hidden-field'
12900 cls: 'roo-select2-choices',
12904 cls: 'roo-select2-search-field',
12915 cls: 'roo-select2-container input-group roo-select2-container-multi',
12920 // cls: 'typeahead typeahead-long dropdown-menu',
12921 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12926 if(this.hasFeedback && !this.allowBlank){
12930 cls: 'glyphicon form-control-feedback'
12933 combobox.cn.push(feedback);
12937 if (align ==='left' && this.fieldLabel.length) {
12939 cfg.cls += ' roo-form-group-label-left';
12944 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12945 tooltip : 'This field is required'
12950 cls : 'control-label',
12951 html : this.fieldLabel
12963 var labelCfg = cfg.cn[1];
12964 var contentCfg = cfg.cn[2];
12967 if(this.indicatorpos == 'right'){
12973 cls : 'control-label',
12977 html : this.fieldLabel
12981 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12982 tooltip : 'This field is required'
12997 labelCfg = cfg.cn[0];
12998 contentCfg = cfg.cn[1];
13002 if(this.labelWidth > 12){
13003 labelCfg.style = "width: " + this.labelWidth + 'px';
13006 if(this.labelWidth < 13 && this.labelmd == 0){
13007 this.labelmd = this.labelWidth;
13010 if(this.labellg > 0){
13011 labelCfg.cls += ' col-lg-' + this.labellg;
13012 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13015 if(this.labelmd > 0){
13016 labelCfg.cls += ' col-md-' + this.labelmd;
13017 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13020 if(this.labelsm > 0){
13021 labelCfg.cls += ' col-sm-' + this.labelsm;
13022 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13025 if(this.labelxs > 0){
13026 labelCfg.cls += ' col-xs-' + this.labelxs;
13027 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13031 } else if ( this.fieldLabel.length) {
13032 // Roo.log(" label");
13036 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13037 tooltip : 'This field is required'
13041 //cls : 'input-group-addon',
13042 html : this.fieldLabel
13047 if(this.indicatorpos == 'right'){
13051 //cls : 'input-group-addon',
13052 html : this.fieldLabel
13056 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13057 tooltip : 'This field is required'
13066 // Roo.log(" no label && no align");
13073 ['xs','sm','md','lg'].map(function(size){
13074 if (settings[size]) {
13075 cfg.cls += ' col-' + size + '-' + settings[size];
13083 _initEventsCalled : false,
13086 initEvents: function()
13088 if (this._initEventsCalled) { // as we call render... prevent looping...
13091 this._initEventsCalled = true;
13094 throw "can not find store for combo";
13097 this.indicator = this.indicatorEl();
13099 this.store = Roo.factory(this.store, Roo.data);
13100 this.store.parent = this;
13102 // if we are building from html. then this element is so complex, that we can not really
13103 // use the rendered HTML.
13104 // so we have to trash and replace the previous code.
13105 if (Roo.XComponent.build_from_html) {
13106 // remove this element....
13107 var e = this.el.dom, k=0;
13108 while (e ) { e = e.previousSibling; ++k;}
13113 this.rendered = false;
13115 this.render(this.parent().getChildContainer(true), k);
13118 if(Roo.isIOS && this.useNativeIOS){
13119 this.initIOSView();
13127 if(Roo.isTouch && this.mobileTouchView){
13128 this.initTouchView();
13133 this.initTickableEvents();
13137 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13139 if(this.hiddenName){
13141 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13143 this.hiddenField.dom.value =
13144 this.hiddenValue !== undefined ? this.hiddenValue :
13145 this.value !== undefined ? this.value : '';
13147 // prevent input submission
13148 this.el.dom.removeAttribute('name');
13149 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13154 // this.el.dom.setAttribute('autocomplete', 'off');
13157 var cls = 'x-combo-list';
13159 //this.list = new Roo.Layer({
13160 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13166 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13167 _this.list.setWidth(lw);
13170 this.list.on('mouseover', this.onViewOver, this);
13171 this.list.on('mousemove', this.onViewMove, this);
13172 this.list.on('scroll', this.onViewScroll, this);
13175 this.list.swallowEvent('mousewheel');
13176 this.assetHeight = 0;
13179 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13180 this.assetHeight += this.header.getHeight();
13183 this.innerList = this.list.createChild({cls:cls+'-inner'});
13184 this.innerList.on('mouseover', this.onViewOver, this);
13185 this.innerList.on('mousemove', this.onViewMove, this);
13186 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13188 if(this.allowBlank && !this.pageSize && !this.disableClear){
13189 this.footer = this.list.createChild({cls:cls+'-ft'});
13190 this.pageTb = new Roo.Toolbar(this.footer);
13194 this.footer = this.list.createChild({cls:cls+'-ft'});
13195 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13196 {pageSize: this.pageSize});
13200 if (this.pageTb && this.allowBlank && !this.disableClear) {
13202 this.pageTb.add(new Roo.Toolbar.Fill(), {
13203 cls: 'x-btn-icon x-btn-clear',
13205 handler: function()
13208 _this.clearValue();
13209 _this.onSelect(false, -1);
13214 this.assetHeight += this.footer.getHeight();
13219 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13222 this.view = new Roo.View(this.list, this.tpl, {
13223 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13225 //this.view.wrapEl.setDisplayed(false);
13226 this.view.on('click', this.onViewClick, this);
13229 this.store.on('beforeload', this.onBeforeLoad, this);
13230 this.store.on('load', this.onLoad, this);
13231 this.store.on('loadexception', this.onLoadException, this);
13233 if(this.resizable){
13234 this.resizer = new Roo.Resizable(this.list, {
13235 pinned:true, handles:'se'
13237 this.resizer.on('resize', function(r, w, h){
13238 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13239 this.listWidth = w;
13240 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13241 this.restrictHeight();
13243 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13246 if(!this.editable){
13247 this.editable = true;
13248 this.setEditable(false);
13253 if (typeof(this.events.add.listeners) != 'undefined') {
13255 this.addicon = this.wrap.createChild(
13256 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13258 this.addicon.on('click', function(e) {
13259 this.fireEvent('add', this);
13262 if (typeof(this.events.edit.listeners) != 'undefined') {
13264 this.editicon = this.wrap.createChild(
13265 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13266 if (this.addicon) {
13267 this.editicon.setStyle('margin-left', '40px');
13269 this.editicon.on('click', function(e) {
13271 // we fire even if inothing is selected..
13272 this.fireEvent('edit', this, this.lastData );
13278 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13279 "up" : function(e){
13280 this.inKeyMode = true;
13284 "down" : function(e){
13285 if(!this.isExpanded()){
13286 this.onTriggerClick();
13288 this.inKeyMode = true;
13293 "enter" : function(e){
13294 // this.onViewClick();
13298 if(this.fireEvent("specialkey", this, e)){
13299 this.onViewClick(false);
13305 "esc" : function(e){
13309 "tab" : function(e){
13312 if(this.fireEvent("specialkey", this, e)){
13313 this.onViewClick(false);
13321 doRelay : function(foo, bar, hname){
13322 if(hname == 'down' || this.scope.isExpanded()){
13323 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13332 this.queryDelay = Math.max(this.queryDelay || 10,
13333 this.mode == 'local' ? 10 : 250);
13336 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13338 if(this.typeAhead){
13339 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13341 if(this.editable !== false){
13342 this.inputEl().on("keyup", this.onKeyUp, this);
13344 if(this.forceSelection){
13345 this.inputEl().on('blur', this.doForce, this);
13349 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13350 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13354 initTickableEvents: function()
13358 if(this.hiddenName){
13360 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13362 this.hiddenField.dom.value =
13363 this.hiddenValue !== undefined ? this.hiddenValue :
13364 this.value !== undefined ? this.value : '';
13366 // prevent input submission
13367 this.el.dom.removeAttribute('name');
13368 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13373 // this.list = this.el.select('ul.dropdown-menu',true).first();
13375 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13376 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13377 if(this.triggerList){
13378 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13381 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13382 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13384 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13385 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13387 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13388 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13390 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13391 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13392 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13395 this.cancelBtn.hide();
13400 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13401 _this.list.setWidth(lw);
13404 this.list.on('mouseover', this.onViewOver, this);
13405 this.list.on('mousemove', this.onViewMove, this);
13407 this.list.on('scroll', this.onViewScroll, this);
13410 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13413 this.view = new Roo.View(this.list, this.tpl, {
13414 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13417 //this.view.wrapEl.setDisplayed(false);
13418 this.view.on('click', this.onViewClick, this);
13422 this.store.on('beforeload', this.onBeforeLoad, this);
13423 this.store.on('load', this.onLoad, this);
13424 this.store.on('loadexception', this.onLoadException, this);
13427 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13428 "up" : function(e){
13429 this.inKeyMode = true;
13433 "down" : function(e){
13434 this.inKeyMode = true;
13438 "enter" : function(e){
13439 if(this.fireEvent("specialkey", this, e)){
13440 this.onViewClick(false);
13446 "esc" : function(e){
13447 this.onTickableFooterButtonClick(e, false, false);
13450 "tab" : function(e){
13451 this.fireEvent("specialkey", this, e);
13453 this.onTickableFooterButtonClick(e, false, false);
13460 doRelay : function(e, fn, key){
13461 if(this.scope.isExpanded()){
13462 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13471 this.queryDelay = Math.max(this.queryDelay || 10,
13472 this.mode == 'local' ? 10 : 250);
13475 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13477 if(this.typeAhead){
13478 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13481 if(this.editable !== false){
13482 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13485 this.indicator = this.indicatorEl();
13487 if(this.indicator){
13488 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13489 this.indicator.hide();
13494 onDestroy : function(){
13496 this.view.setStore(null);
13497 this.view.el.removeAllListeners();
13498 this.view.el.remove();
13499 this.view.purgeListeners();
13502 this.list.dom.innerHTML = '';
13506 this.store.un('beforeload', this.onBeforeLoad, this);
13507 this.store.un('load', this.onLoad, this);
13508 this.store.un('loadexception', this.onLoadException, this);
13510 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13514 fireKey : function(e){
13515 if(e.isNavKeyPress() && !this.list.isVisible()){
13516 this.fireEvent("specialkey", this, e);
13521 onResize: function(w, h){
13522 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13524 // if(typeof w != 'number'){
13525 // // we do not handle it!?!?
13528 // var tw = this.trigger.getWidth();
13529 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13530 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13532 // this.inputEl().setWidth( this.adjustWidth('input', x));
13534 // //this.trigger.setStyle('left', x+'px');
13536 // if(this.list && this.listWidth === undefined){
13537 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13538 // this.list.setWidth(lw);
13539 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13547 * Allow or prevent the user from directly editing the field text. If false is passed,
13548 * the user will only be able to select from the items defined in the dropdown list. This method
13549 * is the runtime equivalent of setting the 'editable' config option at config time.
13550 * @param {Boolean} value True to allow the user to directly edit the field text
13552 setEditable : function(value){
13553 if(value == this.editable){
13556 this.editable = value;
13558 this.inputEl().dom.setAttribute('readOnly', true);
13559 this.inputEl().on('mousedown', this.onTriggerClick, this);
13560 this.inputEl().addClass('x-combo-noedit');
13562 this.inputEl().dom.setAttribute('readOnly', false);
13563 this.inputEl().un('mousedown', this.onTriggerClick, this);
13564 this.inputEl().removeClass('x-combo-noedit');
13570 onBeforeLoad : function(combo,opts){
13571 if(!this.hasFocus){
13575 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13577 this.restrictHeight();
13578 this.selectedIndex = -1;
13582 onLoad : function(){
13584 this.hasQuery = false;
13586 if(!this.hasFocus){
13590 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13591 this.loading.hide();
13594 if(this.store.getCount() > 0){
13597 this.restrictHeight();
13598 if(this.lastQuery == this.allQuery){
13599 if(this.editable && !this.tickable){
13600 this.inputEl().dom.select();
13604 !this.selectByValue(this.value, true) &&
13607 !this.store.lastOptions ||
13608 typeof(this.store.lastOptions.add) == 'undefined' ||
13609 this.store.lastOptions.add != true
13612 this.select(0, true);
13615 if(this.autoFocus){
13618 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13619 this.taTask.delay(this.typeAheadDelay);
13623 this.onEmptyResults();
13629 onLoadException : function()
13631 this.hasQuery = false;
13633 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13634 this.loading.hide();
13637 if(this.tickable && this.editable){
13642 // only causes errors at present
13643 //Roo.log(this.store.reader.jsonData);
13644 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13646 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13652 onTypeAhead : function(){
13653 if(this.store.getCount() > 0){
13654 var r = this.store.getAt(0);
13655 var newValue = r.data[this.displayField];
13656 var len = newValue.length;
13657 var selStart = this.getRawValue().length;
13659 if(selStart != len){
13660 this.setRawValue(newValue);
13661 this.selectText(selStart, newValue.length);
13667 onSelect : function(record, index){
13669 if(this.fireEvent('beforeselect', this, record, index) !== false){
13671 this.setFromData(index > -1 ? record.data : false);
13674 this.fireEvent('select', this, record, index);
13679 * Returns the currently selected field value or empty string if no value is set.
13680 * @return {String} value The selected value
13682 getValue : function()
13684 if(Roo.isIOS && this.useNativeIOS){
13685 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13689 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13692 if(this.valueField){
13693 return typeof this.value != 'undefined' ? this.value : '';
13695 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13699 getRawValue : function()
13701 if(Roo.isIOS && this.useNativeIOS){
13702 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13705 var v = this.inputEl().getValue();
13711 * Clears any text/value currently set in the field
13713 clearValue : function(){
13715 if(this.hiddenField){
13716 this.hiddenField.dom.value = '';
13719 this.setRawValue('');
13720 this.lastSelectionText = '';
13721 this.lastData = false;
13723 var close = this.closeTriggerEl();
13734 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13735 * will be displayed in the field. If the value does not match the data value of an existing item,
13736 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13737 * Otherwise the field will be blank (although the value will still be set).
13738 * @param {String} value The value to match
13740 setValue : function(v)
13742 if(Roo.isIOS && this.useNativeIOS){
13743 this.setIOSValue(v);
13753 if(this.valueField){
13754 var r = this.findRecord(this.valueField, v);
13756 text = r.data[this.displayField];
13757 }else if(this.valueNotFoundText !== undefined){
13758 text = this.valueNotFoundText;
13761 this.lastSelectionText = text;
13762 if(this.hiddenField){
13763 this.hiddenField.dom.value = v;
13765 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13768 var close = this.closeTriggerEl();
13771 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13777 * @property {Object} the last set data for the element
13782 * Sets the value of the field based on a object which is related to the record format for the store.
13783 * @param {Object} value the value to set as. or false on reset?
13785 setFromData : function(o){
13792 var dv = ''; // display value
13793 var vv = ''; // value value..
13795 if (this.displayField) {
13796 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13798 // this is an error condition!!!
13799 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13802 if(this.valueField){
13803 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13806 var close = this.closeTriggerEl();
13809 if(dv.length || vv * 1 > 0){
13811 this.blockFocus=true;
13817 if(this.hiddenField){
13818 this.hiddenField.dom.value = vv;
13820 this.lastSelectionText = dv;
13821 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13825 // no hidden field.. - we store the value in 'value', but still display
13826 // display field!!!!
13827 this.lastSelectionText = dv;
13828 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13835 reset : function(){
13836 // overridden so that last data is reset..
13843 this.setValue(this.originalValue);
13844 //this.clearInvalid();
13845 this.lastData = false;
13847 this.view.clearSelections();
13853 findRecord : function(prop, value){
13855 if(this.store.getCount() > 0){
13856 this.store.each(function(r){
13857 if(r.data[prop] == value){
13867 getName: function()
13869 // returns hidden if it's set..
13870 if (!this.rendered) {return ''};
13871 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13875 onViewMove : function(e, t){
13876 this.inKeyMode = false;
13880 onViewOver : function(e, t){
13881 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13884 var item = this.view.findItemFromChild(t);
13887 var index = this.view.indexOf(item);
13888 this.select(index, false);
13893 onViewClick : function(view, doFocus, el, e)
13895 var index = this.view.getSelectedIndexes()[0];
13897 var r = this.store.getAt(index);
13901 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13908 Roo.each(this.tickItems, function(v,k){
13910 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13912 _this.tickItems.splice(k, 1);
13914 if(typeof(e) == 'undefined' && view == false){
13915 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13927 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13928 this.tickItems.push(r.data);
13931 if(typeof(e) == 'undefined' && view == false){
13932 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13939 this.onSelect(r, index);
13941 if(doFocus !== false && !this.blockFocus){
13942 this.inputEl().focus();
13947 restrictHeight : function(){
13948 //this.innerList.dom.style.height = '';
13949 //var inner = this.innerList.dom;
13950 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13951 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13952 //this.list.beginUpdate();
13953 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13954 this.list.alignTo(this.inputEl(), this.listAlign);
13955 this.list.alignTo(this.inputEl(), this.listAlign);
13956 //this.list.endUpdate();
13960 onEmptyResults : function(){
13962 if(this.tickable && this.editable){
13963 this.restrictHeight();
13971 * Returns true if the dropdown list is expanded, else false.
13973 isExpanded : function(){
13974 return this.list.isVisible();
13978 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13979 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13980 * @param {String} value The data value of the item to select
13981 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13982 * selected item if it is not currently in view (defaults to true)
13983 * @return {Boolean} True if the value matched an item in the list, else false
13985 selectByValue : function(v, scrollIntoView){
13986 if(v !== undefined && v !== null){
13987 var r = this.findRecord(this.valueField || this.displayField, v);
13989 this.select(this.store.indexOf(r), scrollIntoView);
13997 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13998 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13999 * @param {Number} index The zero-based index of the list item to select
14000 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14001 * selected item if it is not currently in view (defaults to true)
14003 select : function(index, scrollIntoView){
14004 this.selectedIndex = index;
14005 this.view.select(index);
14006 if(scrollIntoView !== false){
14007 var el = this.view.getNode(index);
14009 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14012 this.list.scrollChildIntoView(el, false);
14018 selectNext : function(){
14019 var ct = this.store.getCount();
14021 if(this.selectedIndex == -1){
14023 }else if(this.selectedIndex < ct-1){
14024 this.select(this.selectedIndex+1);
14030 selectPrev : function(){
14031 var ct = this.store.getCount();
14033 if(this.selectedIndex == -1){
14035 }else if(this.selectedIndex != 0){
14036 this.select(this.selectedIndex-1);
14042 onKeyUp : function(e){
14043 if(this.editable !== false && !e.isSpecialKey()){
14044 this.lastKey = e.getKey();
14045 this.dqTask.delay(this.queryDelay);
14050 validateBlur : function(){
14051 return !this.list || !this.list.isVisible();
14055 initQuery : function(){
14057 var v = this.getRawValue();
14059 if(this.tickable && this.editable){
14060 v = this.tickableInputEl().getValue();
14067 doForce : function(){
14068 if(this.inputEl().dom.value.length > 0){
14069 this.inputEl().dom.value =
14070 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14076 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14077 * query allowing the query action to be canceled if needed.
14078 * @param {String} query The SQL query to execute
14079 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14080 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14081 * saved in the current store (defaults to false)
14083 doQuery : function(q, forceAll){
14085 if(q === undefined || q === null){
14090 forceAll: forceAll,
14094 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14099 forceAll = qe.forceAll;
14100 if(forceAll === true || (q.length >= this.minChars)){
14102 this.hasQuery = true;
14104 if(this.lastQuery != q || this.alwaysQuery){
14105 this.lastQuery = q;
14106 if(this.mode == 'local'){
14107 this.selectedIndex = -1;
14109 this.store.clearFilter();
14112 if(this.specialFilter){
14113 this.fireEvent('specialfilter', this);
14118 this.store.filter(this.displayField, q);
14121 this.store.fireEvent("datachanged", this.store);
14128 this.store.baseParams[this.queryParam] = q;
14130 var options = {params : this.getParams(q)};
14133 options.add = true;
14134 options.params.start = this.page * this.pageSize;
14137 this.store.load(options);
14140 * this code will make the page width larger, at the beginning, the list not align correctly,
14141 * we should expand the list on onLoad
14142 * so command out it
14147 this.selectedIndex = -1;
14152 this.loadNext = false;
14156 getParams : function(q){
14158 //p[this.queryParam] = q;
14162 p.limit = this.pageSize;
14168 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14170 collapse : function(){
14171 if(!this.isExpanded()){
14177 this.hasFocus = false;
14181 this.cancelBtn.hide();
14182 this.trigger.show();
14185 this.tickableInputEl().dom.value = '';
14186 this.tickableInputEl().blur();
14191 Roo.get(document).un('mousedown', this.collapseIf, this);
14192 Roo.get(document).un('mousewheel', this.collapseIf, this);
14193 if (!this.editable) {
14194 Roo.get(document).un('keydown', this.listKeyPress, this);
14196 this.fireEvent('collapse', this);
14202 collapseIf : function(e){
14203 var in_combo = e.within(this.el);
14204 var in_list = e.within(this.list);
14205 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14207 if (in_combo || in_list || is_list) {
14208 //e.stopPropagation();
14213 this.onTickableFooterButtonClick(e, false, false);
14221 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14223 expand : function(){
14225 if(this.isExpanded() || !this.hasFocus){
14229 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14230 this.list.setWidth(lw);
14236 this.restrictHeight();
14240 this.tickItems = Roo.apply([], this.item);
14243 this.cancelBtn.show();
14244 this.trigger.hide();
14247 this.tickableInputEl().focus();
14252 Roo.get(document).on('mousedown', this.collapseIf, this);
14253 Roo.get(document).on('mousewheel', this.collapseIf, this);
14254 if (!this.editable) {
14255 Roo.get(document).on('keydown', this.listKeyPress, this);
14258 this.fireEvent('expand', this);
14262 // Implements the default empty TriggerField.onTriggerClick function
14263 onTriggerClick : function(e)
14265 Roo.log('trigger click');
14267 if(this.disabled || !this.triggerList){
14272 this.loadNext = false;
14274 if(this.isExpanded()){
14276 if (!this.blockFocus) {
14277 this.inputEl().focus();
14281 this.hasFocus = true;
14282 if(this.triggerAction == 'all') {
14283 this.doQuery(this.allQuery, true);
14285 this.doQuery(this.getRawValue());
14287 if (!this.blockFocus) {
14288 this.inputEl().focus();
14293 onTickableTriggerClick : function(e)
14300 this.loadNext = false;
14301 this.hasFocus = true;
14303 if(this.triggerAction == 'all') {
14304 this.doQuery(this.allQuery, true);
14306 this.doQuery(this.getRawValue());
14310 onSearchFieldClick : function(e)
14312 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14313 this.onTickableFooterButtonClick(e, false, false);
14317 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14322 this.loadNext = false;
14323 this.hasFocus = true;
14325 if(this.triggerAction == 'all') {
14326 this.doQuery(this.allQuery, true);
14328 this.doQuery(this.getRawValue());
14332 listKeyPress : function(e)
14334 //Roo.log('listkeypress');
14335 // scroll to first matching element based on key pres..
14336 if (e.isSpecialKey()) {
14339 var k = String.fromCharCode(e.getKey()).toUpperCase();
14342 var csel = this.view.getSelectedNodes();
14343 var cselitem = false;
14345 var ix = this.view.indexOf(csel[0]);
14346 cselitem = this.store.getAt(ix);
14347 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14353 this.store.each(function(v) {
14355 // start at existing selection.
14356 if (cselitem.id == v.id) {
14362 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14363 match = this.store.indexOf(v);
14369 if (match === false) {
14370 return true; // no more action?
14373 this.view.select(match);
14374 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14375 sn.scrollIntoView(sn.dom.parentNode, false);
14378 onViewScroll : function(e, t){
14380 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){
14384 this.hasQuery = true;
14386 this.loading = this.list.select('.loading', true).first();
14388 if(this.loading === null){
14389 this.list.createChild({
14391 cls: 'loading roo-select2-more-results roo-select2-active',
14392 html: 'Loading more results...'
14395 this.loading = this.list.select('.loading', true).first();
14397 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14399 this.loading.hide();
14402 this.loading.show();
14407 this.loadNext = true;
14409 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14414 addItem : function(o)
14416 var dv = ''; // display value
14418 if (this.displayField) {
14419 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14421 // this is an error condition!!!
14422 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14429 var choice = this.choices.createChild({
14431 cls: 'roo-select2-search-choice',
14440 cls: 'roo-select2-search-choice-close fa fa-times',
14445 }, this.searchField);
14447 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14449 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14457 this.inputEl().dom.value = '';
14462 onRemoveItem : function(e, _self, o)
14464 e.preventDefault();
14466 this.lastItem = Roo.apply([], this.item);
14468 var index = this.item.indexOf(o.data) * 1;
14471 Roo.log('not this item?!');
14475 this.item.splice(index, 1);
14480 this.fireEvent('remove', this, e);
14486 syncValue : function()
14488 if(!this.item.length){
14495 Roo.each(this.item, function(i){
14496 if(_this.valueField){
14497 value.push(i[_this.valueField]);
14504 this.value = value.join(',');
14506 if(this.hiddenField){
14507 this.hiddenField.dom.value = this.value;
14510 this.store.fireEvent("datachanged", this.store);
14515 clearItem : function()
14517 if(!this.multiple){
14523 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14531 if(this.tickable && !Roo.isTouch){
14532 this.view.refresh();
14536 inputEl: function ()
14538 if(Roo.isIOS && this.useNativeIOS){
14539 return this.el.select('select.roo-ios-select', true).first();
14542 if(Roo.isTouch && this.mobileTouchView){
14543 return this.el.select('input.form-control',true).first();
14547 return this.searchField;
14550 return this.el.select('input.form-control',true).first();
14553 onTickableFooterButtonClick : function(e, btn, el)
14555 e.preventDefault();
14557 this.lastItem = Roo.apply([], this.item);
14559 if(btn && btn.name == 'cancel'){
14560 this.tickItems = Roo.apply([], this.item);
14569 Roo.each(this.tickItems, function(o){
14577 validate : function()
14579 var v = this.getRawValue();
14582 v = this.getValue();
14585 if(this.disabled || this.allowBlank || v.length){
14590 this.markInvalid();
14594 tickableInputEl : function()
14596 if(!this.tickable || !this.editable){
14597 return this.inputEl();
14600 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14604 getAutoCreateTouchView : function()
14609 cls: 'form-group' //input-group
14615 type : this.inputType,
14616 cls : 'form-control x-combo-noedit',
14617 autocomplete: 'new-password',
14618 placeholder : this.placeholder || '',
14623 input.name = this.name;
14627 input.cls += ' input-' + this.size;
14630 if (this.disabled) {
14631 input.disabled = true;
14642 inputblock.cls += ' input-group';
14644 inputblock.cn.unshift({
14646 cls : 'input-group-addon',
14651 if(this.removable && !this.multiple){
14652 inputblock.cls += ' roo-removable';
14654 inputblock.cn.push({
14657 cls : 'roo-combo-removable-btn close'
14661 if(this.hasFeedback && !this.allowBlank){
14663 inputblock.cls += ' has-feedback';
14665 inputblock.cn.push({
14667 cls: 'glyphicon form-control-feedback'
14674 inputblock.cls += (this.before) ? '' : ' input-group';
14676 inputblock.cn.push({
14678 cls : 'input-group-addon',
14689 cls: 'form-hidden-field'
14703 cls: 'form-hidden-field'
14707 cls: 'roo-select2-choices',
14711 cls: 'roo-select2-search-field',
14724 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14730 if(!this.multiple && this.showToggleBtn){
14737 if (this.caret != false) {
14740 cls: 'fa fa-' + this.caret
14747 cls : 'input-group-addon btn dropdown-toggle',
14752 cls: 'combobox-clear',
14766 combobox.cls += ' roo-select2-container-multi';
14769 var align = this.labelAlign || this.parentLabelAlign();
14771 if (align ==='left' && this.fieldLabel.length) {
14776 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14777 tooltip : 'This field is required'
14781 cls : 'control-label',
14782 html : this.fieldLabel
14793 var labelCfg = cfg.cn[1];
14794 var contentCfg = cfg.cn[2];
14797 if(this.indicatorpos == 'right'){
14802 cls : 'control-label',
14806 html : this.fieldLabel
14810 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14811 tooltip : 'This field is required'
14824 labelCfg = cfg.cn[0];
14825 contentCfg = cfg.cn[1];
14830 if(this.labelWidth > 12){
14831 labelCfg.style = "width: " + this.labelWidth + 'px';
14834 if(this.labelWidth < 13 && this.labelmd == 0){
14835 this.labelmd = this.labelWidth;
14838 if(this.labellg > 0){
14839 labelCfg.cls += ' col-lg-' + this.labellg;
14840 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14843 if(this.labelmd > 0){
14844 labelCfg.cls += ' col-md-' + this.labelmd;
14845 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14848 if(this.labelsm > 0){
14849 labelCfg.cls += ' col-sm-' + this.labelsm;
14850 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14853 if(this.labelxs > 0){
14854 labelCfg.cls += ' col-xs-' + this.labelxs;
14855 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14859 } else if ( this.fieldLabel.length) {
14863 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14864 tooltip : 'This field is required'
14868 cls : 'control-label',
14869 html : this.fieldLabel
14880 if(this.indicatorpos == 'right'){
14884 cls : 'control-label',
14885 html : this.fieldLabel,
14889 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14890 tooltip : 'This field is required'
14907 var settings = this;
14909 ['xs','sm','md','lg'].map(function(size){
14910 if (settings[size]) {
14911 cfg.cls += ' col-' + size + '-' + settings[size];
14918 initTouchView : function()
14920 this.renderTouchView();
14922 this.touchViewEl.on('scroll', function(){
14923 this.el.dom.scrollTop = 0;
14926 this.originalValue = this.getValue();
14928 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14930 this.inputEl().on("click", this.showTouchView, this);
14931 if (this.triggerEl) {
14932 this.triggerEl.on("click", this.showTouchView, this);
14936 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14937 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14939 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14941 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14942 this.store.on('load', this.onTouchViewLoad, this);
14943 this.store.on('loadexception', this.onTouchViewLoadException, this);
14945 if(this.hiddenName){
14947 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14949 this.hiddenField.dom.value =
14950 this.hiddenValue !== undefined ? this.hiddenValue :
14951 this.value !== undefined ? this.value : '';
14953 this.el.dom.removeAttribute('name');
14954 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14958 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14959 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14962 if(this.removable && !this.multiple){
14963 var close = this.closeTriggerEl();
14965 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14966 close.on('click', this.removeBtnClick, this, close);
14970 * fix the bug in Safari iOS8
14972 this.inputEl().on("focus", function(e){
14973 document.activeElement.blur();
14981 renderTouchView : function()
14983 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14984 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14986 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14987 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14989 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14990 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14991 this.touchViewBodyEl.setStyle('overflow', 'auto');
14993 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14994 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14996 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14997 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15001 showTouchView : function()
15007 this.touchViewHeaderEl.hide();
15009 if(this.modalTitle.length){
15010 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15011 this.touchViewHeaderEl.show();
15014 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15015 this.touchViewEl.show();
15017 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15019 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15020 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15022 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15024 if(this.modalTitle.length){
15025 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15028 this.touchViewBodyEl.setHeight(bodyHeight);
15032 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15034 this.touchViewEl.addClass('in');
15037 this.doTouchViewQuery();
15041 hideTouchView : function()
15043 this.touchViewEl.removeClass('in');
15047 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15049 this.touchViewEl.setStyle('display', 'none');
15054 setTouchViewValue : function()
15061 Roo.each(this.tickItems, function(o){
15066 this.hideTouchView();
15069 doTouchViewQuery : function()
15078 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15082 if(!this.alwaysQuery || this.mode == 'local'){
15083 this.onTouchViewLoad();
15090 onTouchViewBeforeLoad : function(combo,opts)
15096 onTouchViewLoad : function()
15098 if(this.store.getCount() < 1){
15099 this.onTouchViewEmptyResults();
15103 this.clearTouchView();
15105 var rawValue = this.getRawValue();
15107 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15109 this.tickItems = [];
15111 this.store.data.each(function(d, rowIndex){
15112 var row = this.touchViewListGroup.createChild(template);
15114 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15115 row.addClass(d.data.cls);
15118 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15121 html : d.data[this.displayField]
15124 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15125 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15128 row.removeClass('selected');
15129 if(!this.multiple && this.valueField &&
15130 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15133 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15134 row.addClass('selected');
15137 if(this.multiple && this.valueField &&
15138 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15142 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15143 this.tickItems.push(d.data);
15146 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15150 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15152 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15154 if(this.modalTitle.length){
15155 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15158 var listHeight = this.touchViewListGroup.getHeight();
15162 if(firstChecked && listHeight > bodyHeight){
15163 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15168 onTouchViewLoadException : function()
15170 this.hideTouchView();
15173 onTouchViewEmptyResults : function()
15175 this.clearTouchView();
15177 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15179 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15183 clearTouchView : function()
15185 this.touchViewListGroup.dom.innerHTML = '';
15188 onTouchViewClick : function(e, el, o)
15190 e.preventDefault();
15193 var rowIndex = o.rowIndex;
15195 var r = this.store.getAt(rowIndex);
15197 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15199 if(!this.multiple){
15200 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15201 c.dom.removeAttribute('checked');
15204 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15206 this.setFromData(r.data);
15208 var close = this.closeTriggerEl();
15214 this.hideTouchView();
15216 this.fireEvent('select', this, r, rowIndex);
15221 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15222 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15223 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15227 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15228 this.addItem(r.data);
15229 this.tickItems.push(r.data);
15233 getAutoCreateNativeIOS : function()
15236 cls: 'form-group' //input-group,
15241 cls : 'roo-ios-select'
15245 combobox.name = this.name;
15248 if (this.disabled) {
15249 combobox.disabled = true;
15252 var settings = this;
15254 ['xs','sm','md','lg'].map(function(size){
15255 if (settings[size]) {
15256 cfg.cls += ' col-' + size + '-' + settings[size];
15266 initIOSView : function()
15268 this.store.on('load', this.onIOSViewLoad, this);
15273 onIOSViewLoad : function()
15275 if(this.store.getCount() < 1){
15279 this.clearIOSView();
15281 if(this.allowBlank) {
15283 var default_text = '-- SELECT --';
15285 if(this.placeholder.length){
15286 default_text = this.placeholder;
15289 if(this.emptyTitle.length){
15290 default_text += ' - ' + this.emptyTitle + ' -';
15293 var opt = this.inputEl().createChild({
15296 html : default_text
15300 o[this.valueField] = 0;
15301 o[this.displayField] = default_text;
15303 this.ios_options.push({
15310 this.store.data.each(function(d, rowIndex){
15314 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15315 html = d.data[this.displayField];
15320 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15321 value = d.data[this.valueField];
15330 if(this.value == d.data[this.valueField]){
15331 option['selected'] = true;
15334 var opt = this.inputEl().createChild(option);
15336 this.ios_options.push({
15343 this.inputEl().on('change', function(){
15344 this.fireEvent('select', this);
15349 clearIOSView: function()
15351 this.inputEl().dom.innerHTML = '';
15353 this.ios_options = [];
15356 setIOSValue: function(v)
15360 if(!this.ios_options){
15364 Roo.each(this.ios_options, function(opts){
15366 opts.el.dom.removeAttribute('selected');
15368 if(opts.data[this.valueField] != v){
15372 opts.el.dom.setAttribute('selected', true);
15378 * @cfg {Boolean} grow
15382 * @cfg {Number} growMin
15386 * @cfg {Number} growMax
15395 Roo.apply(Roo.bootstrap.ComboBox, {
15399 cls: 'modal-header',
15421 cls: 'list-group-item',
15425 cls: 'roo-combobox-list-group-item-value'
15429 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15443 listItemCheckbox : {
15445 cls: 'list-group-item',
15449 cls: 'roo-combobox-list-group-item-value'
15453 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15469 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15474 cls: 'modal-footer',
15482 cls: 'col-xs-6 text-left',
15485 cls: 'btn btn-danger roo-touch-view-cancel',
15491 cls: 'col-xs-6 text-right',
15494 cls: 'btn btn-success roo-touch-view-ok',
15505 Roo.apply(Roo.bootstrap.ComboBox, {
15507 touchViewTemplate : {
15509 cls: 'modal fade roo-combobox-touch-view',
15513 cls: 'modal-dialog',
15514 style : 'position:fixed', // we have to fix position....
15518 cls: 'modal-content',
15520 Roo.bootstrap.ComboBox.header,
15521 Roo.bootstrap.ComboBox.body,
15522 Roo.bootstrap.ComboBox.footer
15531 * Ext JS Library 1.1.1
15532 * Copyright(c) 2006-2007, Ext JS, LLC.
15534 * Originally Released Under LGPL - original licence link has changed is not relivant.
15537 * <script type="text/javascript">
15542 * @extends Roo.util.Observable
15543 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15544 * This class also supports single and multi selection modes. <br>
15545 * Create a data model bound view:
15547 var store = new Roo.data.Store(...);
15549 var view = new Roo.View({
15551 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15553 singleSelect: true,
15554 selectedClass: "ydataview-selected",
15558 // listen for node click?
15559 view.on("click", function(vw, index, node, e){
15560 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15564 dataModel.load("foobar.xml");
15566 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15568 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15569 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15571 * Note: old style constructor is still suported (container, template, config)
15574 * Create a new View
15575 * @param {Object} config The config object
15578 Roo.View = function(config, depreciated_tpl, depreciated_config){
15580 this.parent = false;
15582 if (typeof(depreciated_tpl) == 'undefined') {
15583 // new way.. - universal constructor.
15584 Roo.apply(this, config);
15585 this.el = Roo.get(this.el);
15588 this.el = Roo.get(config);
15589 this.tpl = depreciated_tpl;
15590 Roo.apply(this, depreciated_config);
15592 this.wrapEl = this.el.wrap().wrap();
15593 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15596 if(typeof(this.tpl) == "string"){
15597 this.tpl = new Roo.Template(this.tpl);
15599 // support xtype ctors..
15600 this.tpl = new Roo.factory(this.tpl, Roo);
15604 this.tpl.compile();
15609 * @event beforeclick
15610 * Fires before a click is processed. Returns false to cancel the default action.
15611 * @param {Roo.View} this
15612 * @param {Number} index The index of the target node
15613 * @param {HTMLElement} node The target node
15614 * @param {Roo.EventObject} e The raw event object
15616 "beforeclick" : true,
15619 * Fires when a template node is clicked.
15620 * @param {Roo.View} this
15621 * @param {Number} index The index of the target node
15622 * @param {HTMLElement} node The target node
15623 * @param {Roo.EventObject} e The raw event object
15628 * Fires when a template node is double clicked.
15629 * @param {Roo.View} this
15630 * @param {Number} index The index of the target node
15631 * @param {HTMLElement} node The target node
15632 * @param {Roo.EventObject} e The raw event object
15636 * @event contextmenu
15637 * Fires when a template node is right clicked.
15638 * @param {Roo.View} this
15639 * @param {Number} index The index of the target node
15640 * @param {HTMLElement} node The target node
15641 * @param {Roo.EventObject} e The raw event object
15643 "contextmenu" : true,
15645 * @event selectionchange
15646 * Fires when the selected nodes change.
15647 * @param {Roo.View} this
15648 * @param {Array} selections Array of the selected nodes
15650 "selectionchange" : true,
15653 * @event beforeselect
15654 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15655 * @param {Roo.View} this
15656 * @param {HTMLElement} node The node to be selected
15657 * @param {Array} selections Array of currently selected nodes
15659 "beforeselect" : true,
15661 * @event preparedata
15662 * Fires on every row to render, to allow you to change the data.
15663 * @param {Roo.View} this
15664 * @param {Object} data to be rendered (change this)
15666 "preparedata" : true
15674 "click": this.onClick,
15675 "dblclick": this.onDblClick,
15676 "contextmenu": this.onContextMenu,
15680 this.selections = [];
15682 this.cmp = new Roo.CompositeElementLite([]);
15684 this.store = Roo.factory(this.store, Roo.data);
15685 this.setStore(this.store, true);
15688 if ( this.footer && this.footer.xtype) {
15690 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15692 this.footer.dataSource = this.store;
15693 this.footer.container = fctr;
15694 this.footer = Roo.factory(this.footer, Roo);
15695 fctr.insertFirst(this.el);
15697 // this is a bit insane - as the paging toolbar seems to detach the el..
15698 // dom.parentNode.parentNode.parentNode
15699 // they get detached?
15703 Roo.View.superclass.constructor.call(this);
15708 Roo.extend(Roo.View, Roo.util.Observable, {
15711 * @cfg {Roo.data.Store} store Data store to load data from.
15716 * @cfg {String|Roo.Element} el The container element.
15721 * @cfg {String|Roo.Template} tpl The template used by this View
15725 * @cfg {String} dataName the named area of the template to use as the data area
15726 * Works with domtemplates roo-name="name"
15730 * @cfg {String} selectedClass The css class to add to selected nodes
15732 selectedClass : "x-view-selected",
15734 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15739 * @cfg {String} text to display on mask (default Loading)
15743 * @cfg {Boolean} multiSelect Allow multiple selection
15745 multiSelect : false,
15747 * @cfg {Boolean} singleSelect Allow single selection
15749 singleSelect: false,
15752 * @cfg {Boolean} toggleSelect - selecting
15754 toggleSelect : false,
15757 * @cfg {Boolean} tickable - selecting
15762 * Returns the element this view is bound to.
15763 * @return {Roo.Element}
15765 getEl : function(){
15766 return this.wrapEl;
15772 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15774 refresh : function(){
15775 //Roo.log('refresh');
15778 // if we are using something like 'domtemplate', then
15779 // the what gets used is:
15780 // t.applySubtemplate(NAME, data, wrapping data..)
15781 // the outer template then get' applied with
15782 // the store 'extra data'
15783 // and the body get's added to the
15784 // roo-name="data" node?
15785 // <span class='roo-tpl-{name}'></span> ?????
15789 this.clearSelections();
15790 this.el.update("");
15792 var records = this.store.getRange();
15793 if(records.length < 1) {
15795 // is this valid?? = should it render a template??
15797 this.el.update(this.emptyText);
15801 if (this.dataName) {
15802 this.el.update(t.apply(this.store.meta)); //????
15803 el = this.el.child('.roo-tpl-' + this.dataName);
15806 for(var i = 0, len = records.length; i < len; i++){
15807 var data = this.prepareData(records[i].data, i, records[i]);
15808 this.fireEvent("preparedata", this, data, i, records[i]);
15810 var d = Roo.apply({}, data);
15813 Roo.apply(d, {'roo-id' : Roo.id()});
15817 Roo.each(this.parent.item, function(item){
15818 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15821 Roo.apply(d, {'roo-data-checked' : 'checked'});
15825 html[html.length] = Roo.util.Format.trim(
15827 t.applySubtemplate(this.dataName, d, this.store.meta) :
15834 el.update(html.join(""));
15835 this.nodes = el.dom.childNodes;
15836 this.updateIndexes(0);
15841 * Function to override to reformat the data that is sent to
15842 * the template for each node.
15843 * DEPRICATED - use the preparedata event handler.
15844 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15845 * a JSON object for an UpdateManager bound view).
15847 prepareData : function(data, index, record)
15849 this.fireEvent("preparedata", this, data, index, record);
15853 onUpdate : function(ds, record){
15854 // Roo.log('on update');
15855 this.clearSelections();
15856 var index = this.store.indexOf(record);
15857 var n = this.nodes[index];
15858 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15859 n.parentNode.removeChild(n);
15860 this.updateIndexes(index, index);
15866 onAdd : function(ds, records, index)
15868 //Roo.log(['on Add', ds, records, index] );
15869 this.clearSelections();
15870 if(this.nodes.length == 0){
15874 var n = this.nodes[index];
15875 for(var i = 0, len = records.length; i < len; i++){
15876 var d = this.prepareData(records[i].data, i, records[i]);
15878 this.tpl.insertBefore(n, d);
15881 this.tpl.append(this.el, d);
15884 this.updateIndexes(index);
15887 onRemove : function(ds, record, index){
15888 // Roo.log('onRemove');
15889 this.clearSelections();
15890 var el = this.dataName ?
15891 this.el.child('.roo-tpl-' + this.dataName) :
15894 el.dom.removeChild(this.nodes[index]);
15895 this.updateIndexes(index);
15899 * Refresh an individual node.
15900 * @param {Number} index
15902 refreshNode : function(index){
15903 this.onUpdate(this.store, this.store.getAt(index));
15906 updateIndexes : function(startIndex, endIndex){
15907 var ns = this.nodes;
15908 startIndex = startIndex || 0;
15909 endIndex = endIndex || ns.length - 1;
15910 for(var i = startIndex; i <= endIndex; i++){
15911 ns[i].nodeIndex = i;
15916 * Changes the data store this view uses and refresh the view.
15917 * @param {Store} store
15919 setStore : function(store, initial){
15920 if(!initial && this.store){
15921 this.store.un("datachanged", this.refresh);
15922 this.store.un("add", this.onAdd);
15923 this.store.un("remove", this.onRemove);
15924 this.store.un("update", this.onUpdate);
15925 this.store.un("clear", this.refresh);
15926 this.store.un("beforeload", this.onBeforeLoad);
15927 this.store.un("load", this.onLoad);
15928 this.store.un("loadexception", this.onLoad);
15932 store.on("datachanged", this.refresh, this);
15933 store.on("add", this.onAdd, this);
15934 store.on("remove", this.onRemove, this);
15935 store.on("update", this.onUpdate, this);
15936 store.on("clear", this.refresh, this);
15937 store.on("beforeload", this.onBeforeLoad, this);
15938 store.on("load", this.onLoad, this);
15939 store.on("loadexception", this.onLoad, this);
15947 * onbeforeLoad - masks the loading area.
15950 onBeforeLoad : function(store,opts)
15952 //Roo.log('onBeforeLoad');
15954 this.el.update("");
15956 this.el.mask(this.mask ? this.mask : "Loading" );
15958 onLoad : function ()
15965 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15966 * @param {HTMLElement} node
15967 * @return {HTMLElement} The template node
15969 findItemFromChild : function(node){
15970 var el = this.dataName ?
15971 this.el.child('.roo-tpl-' + this.dataName,true) :
15974 if(!node || node.parentNode == el){
15977 var p = node.parentNode;
15978 while(p && p != el){
15979 if(p.parentNode == el){
15988 onClick : function(e){
15989 var item = this.findItemFromChild(e.getTarget());
15991 var index = this.indexOf(item);
15992 if(this.onItemClick(item, index, e) !== false){
15993 this.fireEvent("click", this, index, item, e);
15996 this.clearSelections();
16001 onContextMenu : function(e){
16002 var item = this.findItemFromChild(e.getTarget());
16004 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16009 onDblClick : function(e){
16010 var item = this.findItemFromChild(e.getTarget());
16012 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16016 onItemClick : function(item, index, e)
16018 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16021 if (this.toggleSelect) {
16022 var m = this.isSelected(item) ? 'unselect' : 'select';
16025 _t[m](item, true, false);
16028 if(this.multiSelect || this.singleSelect){
16029 if(this.multiSelect && e.shiftKey && this.lastSelection){
16030 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16032 this.select(item, this.multiSelect && e.ctrlKey);
16033 this.lastSelection = item;
16036 if(!this.tickable){
16037 e.preventDefault();
16045 * Get the number of selected nodes.
16048 getSelectionCount : function(){
16049 return this.selections.length;
16053 * Get the currently selected nodes.
16054 * @return {Array} An array of HTMLElements
16056 getSelectedNodes : function(){
16057 return this.selections;
16061 * Get the indexes of the selected nodes.
16064 getSelectedIndexes : function(){
16065 var indexes = [], s = this.selections;
16066 for(var i = 0, len = s.length; i < len; i++){
16067 indexes.push(s[i].nodeIndex);
16073 * Clear all selections
16074 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16076 clearSelections : function(suppressEvent){
16077 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16078 this.cmp.elements = this.selections;
16079 this.cmp.removeClass(this.selectedClass);
16080 this.selections = [];
16081 if(!suppressEvent){
16082 this.fireEvent("selectionchange", this, this.selections);
16088 * Returns true if the passed node is selected
16089 * @param {HTMLElement/Number} node The node or node index
16090 * @return {Boolean}
16092 isSelected : function(node){
16093 var s = this.selections;
16097 node = this.getNode(node);
16098 return s.indexOf(node) !== -1;
16103 * @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
16104 * @param {Boolean} keepExisting (optional) true to keep existing selections
16105 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16107 select : function(nodeInfo, keepExisting, suppressEvent){
16108 if(nodeInfo instanceof Array){
16110 this.clearSelections(true);
16112 for(var i = 0, len = nodeInfo.length; i < len; i++){
16113 this.select(nodeInfo[i], true, true);
16117 var node = this.getNode(nodeInfo);
16118 if(!node || this.isSelected(node)){
16119 return; // already selected.
16122 this.clearSelections(true);
16125 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16126 Roo.fly(node).addClass(this.selectedClass);
16127 this.selections.push(node);
16128 if(!suppressEvent){
16129 this.fireEvent("selectionchange", this, this.selections);
16137 * @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
16138 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16139 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16141 unselect : function(nodeInfo, keepExisting, suppressEvent)
16143 if(nodeInfo instanceof Array){
16144 Roo.each(this.selections, function(s) {
16145 this.unselect(s, nodeInfo);
16149 var node = this.getNode(nodeInfo);
16150 if(!node || !this.isSelected(node)){
16151 //Roo.log("not selected");
16152 return; // not selected.
16156 Roo.each(this.selections, function(s) {
16158 Roo.fly(node).removeClass(this.selectedClass);
16165 this.selections= ns;
16166 this.fireEvent("selectionchange", this, this.selections);
16170 * Gets a template node.
16171 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16172 * @return {HTMLElement} The node or null if it wasn't found
16174 getNode : function(nodeInfo){
16175 if(typeof nodeInfo == "string"){
16176 return document.getElementById(nodeInfo);
16177 }else if(typeof nodeInfo == "number"){
16178 return this.nodes[nodeInfo];
16184 * Gets a range template nodes.
16185 * @param {Number} startIndex
16186 * @param {Number} endIndex
16187 * @return {Array} An array of nodes
16189 getNodes : function(start, end){
16190 var ns = this.nodes;
16191 start = start || 0;
16192 end = typeof end == "undefined" ? ns.length - 1 : end;
16195 for(var i = start; i <= end; i++){
16199 for(var i = start; i >= end; i--){
16207 * Finds the index of the passed node
16208 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16209 * @return {Number} The index of the node or -1
16211 indexOf : function(node){
16212 node = this.getNode(node);
16213 if(typeof node.nodeIndex == "number"){
16214 return node.nodeIndex;
16216 var ns = this.nodes;
16217 for(var i = 0, len = ns.length; i < len; i++){
16228 * based on jquery fullcalendar
16232 Roo.bootstrap = Roo.bootstrap || {};
16234 * @class Roo.bootstrap.Calendar
16235 * @extends Roo.bootstrap.Component
16236 * Bootstrap Calendar class
16237 * @cfg {Boolean} loadMask (true|false) default false
16238 * @cfg {Object} header generate the user specific header of the calendar, default false
16241 * Create a new Container
16242 * @param {Object} config The config object
16247 Roo.bootstrap.Calendar = function(config){
16248 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16252 * Fires when a date is selected
16253 * @param {DatePicker} this
16254 * @param {Date} date The selected date
16258 * @event monthchange
16259 * Fires when the displayed month changes
16260 * @param {DatePicker} this
16261 * @param {Date} date The selected month
16263 'monthchange': true,
16265 * @event evententer
16266 * Fires when mouse over an event
16267 * @param {Calendar} this
16268 * @param {event} Event
16270 'evententer': true,
16272 * @event eventleave
16273 * Fires when the mouse leaves an
16274 * @param {Calendar} this
16277 'eventleave': true,
16279 * @event eventclick
16280 * Fires when the mouse click an
16281 * @param {Calendar} this
16290 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16293 * @cfg {Number} startDay
16294 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16302 getAutoCreate : function(){
16305 var fc_button = function(name, corner, style, content ) {
16306 return Roo.apply({},{
16308 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16310 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16313 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16324 style : 'width:100%',
16331 cls : 'fc-header-left',
16333 fc_button('prev', 'left', 'arrow', '‹' ),
16334 fc_button('next', 'right', 'arrow', '›' ),
16335 { tag: 'span', cls: 'fc-header-space' },
16336 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16344 cls : 'fc-header-center',
16348 cls: 'fc-header-title',
16351 html : 'month / year'
16359 cls : 'fc-header-right',
16361 /* fc_button('month', 'left', '', 'month' ),
16362 fc_button('week', '', '', 'week' ),
16363 fc_button('day', 'right', '', 'day' )
16375 header = this.header;
16378 var cal_heads = function() {
16380 // fixme - handle this.
16382 for (var i =0; i < Date.dayNames.length; i++) {
16383 var d = Date.dayNames[i];
16386 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16387 html : d.substring(0,3)
16391 ret[0].cls += ' fc-first';
16392 ret[6].cls += ' fc-last';
16395 var cal_cell = function(n) {
16398 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16403 cls: 'fc-day-number',
16407 cls: 'fc-day-content',
16411 style: 'position: relative;' // height: 17px;
16423 var cal_rows = function() {
16426 for (var r = 0; r < 6; r++) {
16433 for (var i =0; i < Date.dayNames.length; i++) {
16434 var d = Date.dayNames[i];
16435 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16438 row.cn[0].cls+=' fc-first';
16439 row.cn[0].cn[0].style = 'min-height:90px';
16440 row.cn[6].cls+=' fc-last';
16444 ret[0].cls += ' fc-first';
16445 ret[4].cls += ' fc-prev-last';
16446 ret[5].cls += ' fc-last';
16453 cls: 'fc-border-separate',
16454 style : 'width:100%',
16462 cls : 'fc-first fc-last',
16480 cls : 'fc-content',
16481 style : "position: relative;",
16484 cls : 'fc-view fc-view-month fc-grid',
16485 style : 'position: relative',
16486 unselectable : 'on',
16489 cls : 'fc-event-container',
16490 style : 'position:absolute;z-index:8;top:0;left:0;'
16508 initEvents : function()
16511 throw "can not find store for calendar";
16517 style: "text-align:center",
16521 style: "background-color:white;width:50%;margin:250 auto",
16525 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16536 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16538 var size = this.el.select('.fc-content', true).first().getSize();
16539 this.maskEl.setSize(size.width, size.height);
16540 this.maskEl.enableDisplayMode("block");
16541 if(!this.loadMask){
16542 this.maskEl.hide();
16545 this.store = Roo.factory(this.store, Roo.data);
16546 this.store.on('load', this.onLoad, this);
16547 this.store.on('beforeload', this.onBeforeLoad, this);
16551 this.cells = this.el.select('.fc-day',true);
16552 //Roo.log(this.cells);
16553 this.textNodes = this.el.query('.fc-day-number');
16554 this.cells.addClassOnOver('fc-state-hover');
16556 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16557 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16558 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16559 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16561 this.on('monthchange', this.onMonthChange, this);
16563 this.update(new Date().clearTime());
16566 resize : function() {
16567 var sz = this.el.getSize();
16569 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16570 this.el.select('.fc-day-content div',true).setHeight(34);
16575 showPrevMonth : function(e){
16576 this.update(this.activeDate.add("mo", -1));
16578 showToday : function(e){
16579 this.update(new Date().clearTime());
16582 showNextMonth : function(e){
16583 this.update(this.activeDate.add("mo", 1));
16587 showPrevYear : function(){
16588 this.update(this.activeDate.add("y", -1));
16592 showNextYear : function(){
16593 this.update(this.activeDate.add("y", 1));
16598 update : function(date)
16600 var vd = this.activeDate;
16601 this.activeDate = date;
16602 // if(vd && this.el){
16603 // var t = date.getTime();
16604 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16605 // Roo.log('using add remove');
16607 // this.fireEvent('monthchange', this, date);
16609 // this.cells.removeClass("fc-state-highlight");
16610 // this.cells.each(function(c){
16611 // if(c.dateValue == t){
16612 // c.addClass("fc-state-highlight");
16613 // setTimeout(function(){
16614 // try{c.dom.firstChild.focus();}catch(e){}
16624 var days = date.getDaysInMonth();
16626 var firstOfMonth = date.getFirstDateOfMonth();
16627 var startingPos = firstOfMonth.getDay()-this.startDay;
16629 if(startingPos < this.startDay){
16633 var pm = date.add(Date.MONTH, -1);
16634 var prevStart = pm.getDaysInMonth()-startingPos;
16636 this.cells = this.el.select('.fc-day',true);
16637 this.textNodes = this.el.query('.fc-day-number');
16638 this.cells.addClassOnOver('fc-state-hover');
16640 var cells = this.cells.elements;
16641 var textEls = this.textNodes;
16643 Roo.each(cells, function(cell){
16644 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16647 days += startingPos;
16649 // convert everything to numbers so it's fast
16650 var day = 86400000;
16651 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16654 //Roo.log(prevStart);
16656 var today = new Date().clearTime().getTime();
16657 var sel = date.clearTime().getTime();
16658 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16659 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16660 var ddMatch = this.disabledDatesRE;
16661 var ddText = this.disabledDatesText;
16662 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16663 var ddaysText = this.disabledDaysText;
16664 var format = this.format;
16666 var setCellClass = function(cal, cell){
16670 //Roo.log('set Cell Class');
16672 var t = d.getTime();
16676 cell.dateValue = t;
16678 cell.className += " fc-today";
16679 cell.className += " fc-state-highlight";
16680 cell.title = cal.todayText;
16683 // disable highlight in other month..
16684 //cell.className += " fc-state-highlight";
16689 cell.className = " fc-state-disabled";
16690 cell.title = cal.minText;
16694 cell.className = " fc-state-disabled";
16695 cell.title = cal.maxText;
16699 if(ddays.indexOf(d.getDay()) != -1){
16700 cell.title = ddaysText;
16701 cell.className = " fc-state-disabled";
16704 if(ddMatch && format){
16705 var fvalue = d.dateFormat(format);
16706 if(ddMatch.test(fvalue)){
16707 cell.title = ddText.replace("%0", fvalue);
16708 cell.className = " fc-state-disabled";
16712 if (!cell.initialClassName) {
16713 cell.initialClassName = cell.dom.className;
16716 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16721 for(; i < startingPos; i++) {
16722 textEls[i].innerHTML = (++prevStart);
16723 d.setDate(d.getDate()+1);
16725 cells[i].className = "fc-past fc-other-month";
16726 setCellClass(this, cells[i]);
16731 for(; i < days; i++){
16732 intDay = i - startingPos + 1;
16733 textEls[i].innerHTML = (intDay);
16734 d.setDate(d.getDate()+1);
16736 cells[i].className = ''; // "x-date-active";
16737 setCellClass(this, cells[i]);
16741 for(; i < 42; i++) {
16742 textEls[i].innerHTML = (++extraDays);
16743 d.setDate(d.getDate()+1);
16745 cells[i].className = "fc-future fc-other-month";
16746 setCellClass(this, cells[i]);
16749 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16751 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16753 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16754 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16756 if(totalRows != 6){
16757 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16758 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16761 this.fireEvent('monthchange', this, date);
16765 if(!this.internalRender){
16766 var main = this.el.dom.firstChild;
16767 var w = main.offsetWidth;
16768 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16769 Roo.fly(main).setWidth(w);
16770 this.internalRender = true;
16771 // opera does not respect the auto grow header center column
16772 // then, after it gets a width opera refuses to recalculate
16773 // without a second pass
16774 if(Roo.isOpera && !this.secondPass){
16775 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16776 this.secondPass = true;
16777 this.update.defer(10, this, [date]);
16784 findCell : function(dt) {
16785 dt = dt.clearTime().getTime();
16787 this.cells.each(function(c){
16788 //Roo.log("check " +c.dateValue + '?=' + dt);
16789 if(c.dateValue == dt){
16799 findCells : function(ev) {
16800 var s = ev.start.clone().clearTime().getTime();
16802 var e= ev.end.clone().clearTime().getTime();
16805 this.cells.each(function(c){
16806 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16808 if(c.dateValue > e){
16811 if(c.dateValue < s){
16820 // findBestRow: function(cells)
16824 // for (var i =0 ; i < cells.length;i++) {
16825 // ret = Math.max(cells[i].rows || 0,ret);
16832 addItem : function(ev)
16834 // look for vertical location slot in
16835 var cells = this.findCells(ev);
16837 // ev.row = this.findBestRow(cells);
16839 // work out the location.
16843 for(var i =0; i < cells.length; i++) {
16845 cells[i].row = cells[0].row;
16848 cells[i].row = cells[i].row + 1;
16858 if (crow.start.getY() == cells[i].getY()) {
16860 crow.end = cells[i];
16877 cells[0].events.push(ev);
16879 this.calevents.push(ev);
16882 clearEvents: function() {
16884 if(!this.calevents){
16888 Roo.each(this.cells.elements, function(c){
16894 Roo.each(this.calevents, function(e) {
16895 Roo.each(e.els, function(el) {
16896 el.un('mouseenter' ,this.onEventEnter, this);
16897 el.un('mouseleave' ,this.onEventLeave, this);
16902 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16908 renderEvents: function()
16912 this.cells.each(function(c) {
16921 if(c.row != c.events.length){
16922 r = 4 - (4 - (c.row - c.events.length));
16925 c.events = ev.slice(0, r);
16926 c.more = ev.slice(r);
16928 if(c.more.length && c.more.length == 1){
16929 c.events.push(c.more.pop());
16932 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16936 this.cells.each(function(c) {
16938 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16941 for (var e = 0; e < c.events.length; e++){
16942 var ev = c.events[e];
16943 var rows = ev.rows;
16945 for(var i = 0; i < rows.length; i++) {
16947 // how many rows should it span..
16950 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16951 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16953 unselectable : "on",
16956 cls: 'fc-event-inner',
16960 // cls: 'fc-event-time',
16961 // html : cells.length > 1 ? '' : ev.time
16965 cls: 'fc-event-title',
16966 html : String.format('{0}', ev.title)
16973 cls: 'ui-resizable-handle ui-resizable-e',
16974 html : '  '
16981 cfg.cls += ' fc-event-start';
16983 if ((i+1) == rows.length) {
16984 cfg.cls += ' fc-event-end';
16987 var ctr = _this.el.select('.fc-event-container',true).first();
16988 var cg = ctr.createChild(cfg);
16990 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16991 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16993 var r = (c.more.length) ? 1 : 0;
16994 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16995 cg.setWidth(ebox.right - sbox.x -2);
16997 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16998 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16999 cg.on('click', _this.onEventClick, _this, ev);
17010 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17011 style : 'position: absolute',
17012 unselectable : "on",
17015 cls: 'fc-event-inner',
17019 cls: 'fc-event-title',
17027 cls: 'ui-resizable-handle ui-resizable-e',
17028 html : '  '
17034 var ctr = _this.el.select('.fc-event-container',true).first();
17035 var cg = ctr.createChild(cfg);
17037 var sbox = c.select('.fc-day-content',true).first().getBox();
17038 var ebox = c.select('.fc-day-content',true).first().getBox();
17040 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17041 cg.setWidth(ebox.right - sbox.x -2);
17043 cg.on('click', _this.onMoreEventClick, _this, c.more);
17053 onEventEnter: function (e, el,event,d) {
17054 this.fireEvent('evententer', this, el, event);
17057 onEventLeave: function (e, el,event,d) {
17058 this.fireEvent('eventleave', this, el, event);
17061 onEventClick: function (e, el,event,d) {
17062 this.fireEvent('eventclick', this, el, event);
17065 onMonthChange: function () {
17069 onMoreEventClick: function(e, el, more)
17073 this.calpopover.placement = 'right';
17074 this.calpopover.setTitle('More');
17076 this.calpopover.setContent('');
17078 var ctr = this.calpopover.el.select('.popover-content', true).first();
17080 Roo.each(more, function(m){
17082 cls : 'fc-event-hori fc-event-draggable',
17085 var cg = ctr.createChild(cfg);
17087 cg.on('click', _this.onEventClick, _this, m);
17090 this.calpopover.show(el);
17095 onLoad: function ()
17097 this.calevents = [];
17100 if(this.store.getCount() > 0){
17101 this.store.data.each(function(d){
17104 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17105 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17106 time : d.data.start_time,
17107 title : d.data.title,
17108 description : d.data.description,
17109 venue : d.data.venue
17114 this.renderEvents();
17116 if(this.calevents.length && this.loadMask){
17117 this.maskEl.hide();
17121 onBeforeLoad: function()
17123 this.clearEvents();
17125 this.maskEl.show();
17139 * @class Roo.bootstrap.Popover
17140 * @extends Roo.bootstrap.Component
17141 * Bootstrap Popover class
17142 * @cfg {String} html contents of the popover (or false to use children..)
17143 * @cfg {String} title of popover (or false to hide)
17144 * @cfg {String} placement how it is placed
17145 * @cfg {String} trigger click || hover (or false to trigger manually)
17146 * @cfg {String} over what (parent or false to trigger manually.)
17147 * @cfg {Number} delay - delay before showing
17150 * Create a new Popover
17151 * @param {Object} config The config object
17154 Roo.bootstrap.Popover = function(config){
17155 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17161 * After the popover show
17163 * @param {Roo.bootstrap.Popover} this
17168 * After the popover hide
17170 * @param {Roo.bootstrap.Popover} this
17176 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17178 title: 'Fill in a title',
17181 placement : 'right',
17182 trigger : 'hover', // hover
17188 can_build_overlaid : false,
17190 getChildContainer : function()
17192 return this.el.select('.popover-content',true).first();
17195 getAutoCreate : function(){
17198 cls : 'popover roo-dynamic',
17199 style: 'display:block',
17205 cls : 'popover-inner',
17209 cls: 'popover-title',
17213 cls : 'popover-content',
17224 setTitle: function(str)
17227 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17229 setContent: function(str)
17232 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17234 // as it get's added to the bottom of the page.
17235 onRender : function(ct, position)
17237 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17239 var cfg = Roo.apply({}, this.getAutoCreate());
17243 cfg.cls += ' ' + this.cls;
17246 cfg.style = this.style;
17248 //Roo.log("adding to ");
17249 this.el = Roo.get(document.body).createChild(cfg, position);
17250 // Roo.log(this.el);
17255 initEvents : function()
17257 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17258 this.el.enableDisplayMode('block');
17260 if (this.over === false) {
17263 if (this.triggers === false) {
17266 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17267 var triggers = this.trigger ? this.trigger.split(' ') : [];
17268 Roo.each(triggers, function(trigger) {
17270 if (trigger == 'click') {
17271 on_el.on('click', this.toggle, this);
17272 } else if (trigger != 'manual') {
17273 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17274 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17276 on_el.on(eventIn ,this.enter, this);
17277 on_el.on(eventOut, this.leave, this);
17288 toggle : function () {
17289 this.hoverState == 'in' ? this.leave() : this.enter();
17292 enter : function () {
17294 clearTimeout(this.timeout);
17296 this.hoverState = 'in';
17298 if (!this.delay || !this.delay.show) {
17303 this.timeout = setTimeout(function () {
17304 if (_t.hoverState == 'in') {
17307 }, this.delay.show)
17310 leave : function() {
17311 clearTimeout(this.timeout);
17313 this.hoverState = 'out';
17315 if (!this.delay || !this.delay.hide) {
17320 this.timeout = setTimeout(function () {
17321 if (_t.hoverState == 'out') {
17324 }, this.delay.hide)
17327 show : function (on_el)
17330 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17334 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17335 if (this.html !== false) {
17336 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17338 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17339 if (!this.title.length) {
17340 this.el.select('.popover-title',true).hide();
17343 var placement = typeof this.placement == 'function' ?
17344 this.placement.call(this, this.el, on_el) :
17347 var autoToken = /\s?auto?\s?/i;
17348 var autoPlace = autoToken.test(placement);
17350 placement = placement.replace(autoToken, '') || 'top';
17354 //this.el.setXY([0,0]);
17356 this.el.dom.style.display='block';
17357 this.el.addClass(placement);
17359 //this.el.appendTo(on_el);
17361 var p = this.getPosition();
17362 var box = this.el.getBox();
17367 var align = Roo.bootstrap.Popover.alignment[placement];
17370 this.el.alignTo(on_el, align[0],align[1]);
17371 //var arrow = this.el.select('.arrow',true).first();
17372 //arrow.set(align[2],
17374 this.el.addClass('in');
17377 if (this.el.hasClass('fade')) {
17381 this.hoverState = 'in';
17383 this.fireEvent('show', this);
17388 this.el.setXY([0,0]);
17389 this.el.removeClass('in');
17391 this.hoverState = null;
17393 this.fireEvent('hide', this);
17398 Roo.bootstrap.Popover.alignment = {
17399 'left' : ['r-l', [-10,0], 'right'],
17400 'right' : ['l-r', [10,0], 'left'],
17401 'bottom' : ['t-b', [0,10], 'top'],
17402 'top' : [ 'b-t', [0,-10], 'bottom']
17413 * @class Roo.bootstrap.Progress
17414 * @extends Roo.bootstrap.Component
17415 * Bootstrap Progress class
17416 * @cfg {Boolean} striped striped of the progress bar
17417 * @cfg {Boolean} active animated of the progress bar
17421 * Create a new Progress
17422 * @param {Object} config The config object
17425 Roo.bootstrap.Progress = function(config){
17426 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17429 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17434 getAutoCreate : function(){
17442 cfg.cls += ' progress-striped';
17446 cfg.cls += ' active';
17465 * @class Roo.bootstrap.ProgressBar
17466 * @extends Roo.bootstrap.Component
17467 * Bootstrap ProgressBar class
17468 * @cfg {Number} aria_valuenow aria-value now
17469 * @cfg {Number} aria_valuemin aria-value min
17470 * @cfg {Number} aria_valuemax aria-value max
17471 * @cfg {String} label label for the progress bar
17472 * @cfg {String} panel (success | info | warning | danger )
17473 * @cfg {String} role role of the progress bar
17474 * @cfg {String} sr_only text
17478 * Create a new ProgressBar
17479 * @param {Object} config The config object
17482 Roo.bootstrap.ProgressBar = function(config){
17483 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17486 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17490 aria_valuemax : 100,
17496 getAutoCreate : function()
17501 cls: 'progress-bar',
17502 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17514 cfg.role = this.role;
17517 if(this.aria_valuenow){
17518 cfg['aria-valuenow'] = this.aria_valuenow;
17521 if(this.aria_valuemin){
17522 cfg['aria-valuemin'] = this.aria_valuemin;
17525 if(this.aria_valuemax){
17526 cfg['aria-valuemax'] = this.aria_valuemax;
17529 if(this.label && !this.sr_only){
17530 cfg.html = this.label;
17534 cfg.cls += ' progress-bar-' + this.panel;
17540 update : function(aria_valuenow)
17542 this.aria_valuenow = aria_valuenow;
17544 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17559 * @class Roo.bootstrap.TabGroup
17560 * @extends Roo.bootstrap.Column
17561 * Bootstrap Column class
17562 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17563 * @cfg {Boolean} carousel true to make the group behave like a carousel
17564 * @cfg {Boolean} bullets show bullets for the panels
17565 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17566 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17567 * @cfg {Boolean} showarrow (true|false) show arrow default true
17570 * Create a new TabGroup
17571 * @param {Object} config The config object
17574 Roo.bootstrap.TabGroup = function(config){
17575 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17577 this.navId = Roo.id();
17580 Roo.bootstrap.TabGroup.register(this);
17584 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17587 transition : false,
17592 slideOnTouch : false,
17595 getAutoCreate : function()
17597 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17599 cfg.cls += ' tab-content';
17601 if (this.carousel) {
17602 cfg.cls += ' carousel slide';
17605 cls : 'carousel-inner',
17609 if(this.bullets && !Roo.isTouch){
17612 cls : 'carousel-bullets',
17616 if(this.bullets_cls){
17617 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17624 cfg.cn[0].cn.push(bullets);
17627 if(this.showarrow){
17628 cfg.cn[0].cn.push({
17630 class : 'carousel-arrow',
17634 class : 'carousel-prev',
17638 class : 'fa fa-chevron-left'
17644 class : 'carousel-next',
17648 class : 'fa fa-chevron-right'
17661 initEvents: function()
17663 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17664 // this.el.on("touchstart", this.onTouchStart, this);
17667 if(this.autoslide){
17670 this.slideFn = window.setInterval(function() {
17671 _this.showPanelNext();
17675 if(this.showarrow){
17676 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17677 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17683 // onTouchStart : function(e, el, o)
17685 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17689 // this.showPanelNext();
17693 getChildContainer : function()
17695 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17699 * register a Navigation item
17700 * @param {Roo.bootstrap.NavItem} the navitem to add
17702 register : function(item)
17704 this.tabs.push( item);
17705 item.navId = this.navId; // not really needed..
17710 getActivePanel : function()
17713 Roo.each(this.tabs, function(t) {
17723 getPanelByName : function(n)
17726 Roo.each(this.tabs, function(t) {
17727 if (t.tabId == n) {
17735 indexOfPanel : function(p)
17738 Roo.each(this.tabs, function(t,i) {
17739 if (t.tabId == p.tabId) {
17748 * show a specific panel
17749 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17750 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17752 showPanel : function (pan)
17754 if(this.transition || typeof(pan) == 'undefined'){
17755 Roo.log("waiting for the transitionend");
17759 if (typeof(pan) == 'number') {
17760 pan = this.tabs[pan];
17763 if (typeof(pan) == 'string') {
17764 pan = this.getPanelByName(pan);
17767 var cur = this.getActivePanel();
17770 Roo.log('pan or acitve pan is undefined');
17774 if (pan.tabId == this.getActivePanel().tabId) {
17778 if (false === cur.fireEvent('beforedeactivate')) {
17782 if(this.bullets > 0 && !Roo.isTouch){
17783 this.setActiveBullet(this.indexOfPanel(pan));
17786 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17788 this.transition = true;
17789 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17790 var lr = dir == 'next' ? 'left' : 'right';
17791 pan.el.addClass(dir); // or prev
17792 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17793 cur.el.addClass(lr); // or right
17794 pan.el.addClass(lr);
17797 cur.el.on('transitionend', function() {
17798 Roo.log("trans end?");
17800 pan.el.removeClass([lr,dir]);
17801 pan.setActive(true);
17803 cur.el.removeClass([lr]);
17804 cur.setActive(false);
17806 _this.transition = false;
17808 }, this, { single: true } );
17813 cur.setActive(false);
17814 pan.setActive(true);
17819 showPanelNext : function()
17821 var i = this.indexOfPanel(this.getActivePanel());
17823 if (i >= this.tabs.length - 1 && !this.autoslide) {
17827 if (i >= this.tabs.length - 1 && this.autoslide) {
17831 this.showPanel(this.tabs[i+1]);
17834 showPanelPrev : function()
17836 var i = this.indexOfPanel(this.getActivePanel());
17838 if (i < 1 && !this.autoslide) {
17842 if (i < 1 && this.autoslide) {
17843 i = this.tabs.length;
17846 this.showPanel(this.tabs[i-1]);
17850 addBullet: function()
17852 if(!this.bullets || Roo.isTouch){
17855 var ctr = this.el.select('.carousel-bullets',true).first();
17856 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17857 var bullet = ctr.createChild({
17858 cls : 'bullet bullet-' + i
17859 },ctr.dom.lastChild);
17864 bullet.on('click', (function(e, el, o, ii, t){
17866 e.preventDefault();
17868 this.showPanel(ii);
17870 if(this.autoslide && this.slideFn){
17871 clearInterval(this.slideFn);
17872 this.slideFn = window.setInterval(function() {
17873 _this.showPanelNext();
17877 }).createDelegate(this, [i, bullet], true));
17882 setActiveBullet : function(i)
17888 Roo.each(this.el.select('.bullet', true).elements, function(el){
17889 el.removeClass('selected');
17892 var bullet = this.el.select('.bullet-' + i, true).first();
17898 bullet.addClass('selected');
17909 Roo.apply(Roo.bootstrap.TabGroup, {
17913 * register a Navigation Group
17914 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17916 register : function(navgrp)
17918 this.groups[navgrp.navId] = navgrp;
17922 * fetch a Navigation Group based on the navigation ID
17923 * if one does not exist , it will get created.
17924 * @param {string} the navgroup to add
17925 * @returns {Roo.bootstrap.NavGroup} the navgroup
17927 get: function(navId) {
17928 if (typeof(this.groups[navId]) == 'undefined') {
17929 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17931 return this.groups[navId] ;
17946 * @class Roo.bootstrap.TabPanel
17947 * @extends Roo.bootstrap.Component
17948 * Bootstrap TabPanel class
17949 * @cfg {Boolean} active panel active
17950 * @cfg {String} html panel content
17951 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17952 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17953 * @cfg {String} href click to link..
17957 * Create a new TabPanel
17958 * @param {Object} config The config object
17961 Roo.bootstrap.TabPanel = function(config){
17962 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17966 * Fires when the active status changes
17967 * @param {Roo.bootstrap.TabPanel} this
17968 * @param {Boolean} state the new state
17973 * @event beforedeactivate
17974 * Fires before a tab is de-activated - can be used to do validation on a form.
17975 * @param {Roo.bootstrap.TabPanel} this
17976 * @return {Boolean} false if there is an error
17979 'beforedeactivate': true
17982 this.tabId = this.tabId || Roo.id();
17986 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17994 getAutoCreate : function(){
17997 // item is needed for carousel - not sure if it has any effect otherwise
17998 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17999 html: this.html || ''
18003 cfg.cls += ' active';
18007 cfg.tabId = this.tabId;
18014 initEvents: function()
18016 var p = this.parent();
18018 this.navId = this.navId || p.navId;
18020 if (typeof(this.navId) != 'undefined') {
18021 // not really needed.. but just in case.. parent should be a NavGroup.
18022 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18026 var i = tg.tabs.length - 1;
18028 if(this.active && tg.bullets > 0 && i < tg.bullets){
18029 tg.setActiveBullet(i);
18033 this.el.on('click', this.onClick, this);
18036 this.el.on("touchstart", this.onTouchStart, this);
18037 this.el.on("touchmove", this.onTouchMove, this);
18038 this.el.on("touchend", this.onTouchEnd, this);
18043 onRender : function(ct, position)
18045 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18048 setActive : function(state)
18050 Roo.log("panel - set active " + this.tabId + "=" + state);
18052 this.active = state;
18054 this.el.removeClass('active');
18056 } else if (!this.el.hasClass('active')) {
18057 this.el.addClass('active');
18060 this.fireEvent('changed', this, state);
18063 onClick : function(e)
18065 e.preventDefault();
18067 if(!this.href.length){
18071 window.location.href = this.href;
18080 onTouchStart : function(e)
18082 this.swiping = false;
18084 this.startX = e.browserEvent.touches[0].clientX;
18085 this.startY = e.browserEvent.touches[0].clientY;
18088 onTouchMove : function(e)
18090 this.swiping = true;
18092 this.endX = e.browserEvent.touches[0].clientX;
18093 this.endY = e.browserEvent.touches[0].clientY;
18096 onTouchEnd : function(e)
18103 var tabGroup = this.parent();
18105 if(this.endX > this.startX){ // swiping right
18106 tabGroup.showPanelPrev();
18110 if(this.startX > this.endX){ // swiping left
18111 tabGroup.showPanelNext();
18130 * @class Roo.bootstrap.DateField
18131 * @extends Roo.bootstrap.Input
18132 * Bootstrap DateField class
18133 * @cfg {Number} weekStart default 0
18134 * @cfg {String} viewMode default empty, (months|years)
18135 * @cfg {String} minViewMode default empty, (months|years)
18136 * @cfg {Number} startDate default -Infinity
18137 * @cfg {Number} endDate default Infinity
18138 * @cfg {Boolean} todayHighlight default false
18139 * @cfg {Boolean} todayBtn default false
18140 * @cfg {Boolean} calendarWeeks default false
18141 * @cfg {Object} daysOfWeekDisabled default empty
18142 * @cfg {Boolean} singleMode default false (true | false)
18144 * @cfg {Boolean} keyboardNavigation default true
18145 * @cfg {String} language default en
18148 * Create a new DateField
18149 * @param {Object} config The config object
18152 Roo.bootstrap.DateField = function(config){
18153 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18157 * Fires when this field show.
18158 * @param {Roo.bootstrap.DateField} this
18159 * @param {Mixed} date The date value
18164 * Fires when this field hide.
18165 * @param {Roo.bootstrap.DateField} this
18166 * @param {Mixed} date The date value
18171 * Fires when select a date.
18172 * @param {Roo.bootstrap.DateField} this
18173 * @param {Mixed} date The date value
18177 * @event beforeselect
18178 * Fires when before select a date.
18179 * @param {Roo.bootstrap.DateField} this
18180 * @param {Mixed} date The date value
18182 beforeselect : true
18186 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18189 * @cfg {String} format
18190 * The default date format string which can be overriden for localization support. The format must be
18191 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18195 * @cfg {String} altFormats
18196 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18197 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18199 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18207 todayHighlight : false,
18213 keyboardNavigation: true,
18215 calendarWeeks: false,
18217 startDate: -Infinity,
18221 daysOfWeekDisabled: [],
18225 singleMode : false,
18227 UTCDate: function()
18229 return new Date(Date.UTC.apply(Date, arguments));
18232 UTCToday: function()
18234 var today = new Date();
18235 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18238 getDate: function() {
18239 var d = this.getUTCDate();
18240 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18243 getUTCDate: function() {
18247 setDate: function(d) {
18248 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18251 setUTCDate: function(d) {
18253 this.setValue(this.formatDate(this.date));
18256 onRender: function(ct, position)
18259 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18261 this.language = this.language || 'en';
18262 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18263 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18265 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18266 this.format = this.format || 'm/d/y';
18267 this.isInline = false;
18268 this.isInput = true;
18269 this.component = this.el.select('.add-on', true).first() || false;
18270 this.component = (this.component && this.component.length === 0) ? false : this.component;
18271 this.hasInput = this.component && this.inputEl().length;
18273 if (typeof(this.minViewMode === 'string')) {
18274 switch (this.minViewMode) {
18276 this.minViewMode = 1;
18279 this.minViewMode = 2;
18282 this.minViewMode = 0;
18287 if (typeof(this.viewMode === 'string')) {
18288 switch (this.viewMode) {
18301 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18303 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18305 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18307 this.picker().on('mousedown', this.onMousedown, this);
18308 this.picker().on('click', this.onClick, this);
18310 this.picker().addClass('datepicker-dropdown');
18312 this.startViewMode = this.viewMode;
18314 if(this.singleMode){
18315 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18316 v.setVisibilityMode(Roo.Element.DISPLAY);
18320 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18321 v.setStyle('width', '189px');
18325 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18326 if(!this.calendarWeeks){
18331 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18332 v.attr('colspan', function(i, val){
18333 return parseInt(val) + 1;
18338 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18340 this.setStartDate(this.startDate);
18341 this.setEndDate(this.endDate);
18343 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18350 if(this.isInline) {
18355 picker : function()
18357 return this.pickerEl;
18358 // return this.el.select('.datepicker', true).first();
18361 fillDow: function()
18363 var dowCnt = this.weekStart;
18372 if(this.calendarWeeks){
18380 while (dowCnt < this.weekStart + 7) {
18384 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18388 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18391 fillMonths: function()
18394 var months = this.picker().select('>.datepicker-months td', true).first();
18396 months.dom.innerHTML = '';
18402 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18405 months.createChild(month);
18412 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;
18414 if (this.date < this.startDate) {
18415 this.viewDate = new Date(this.startDate);
18416 } else if (this.date > this.endDate) {
18417 this.viewDate = new Date(this.endDate);
18419 this.viewDate = new Date(this.date);
18427 var d = new Date(this.viewDate),
18428 year = d.getUTCFullYear(),
18429 month = d.getUTCMonth(),
18430 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18431 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18432 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18433 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18434 currentDate = this.date && this.date.valueOf(),
18435 today = this.UTCToday();
18437 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18439 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18441 // this.picker.select('>tfoot th.today').
18442 // .text(dates[this.language].today)
18443 // .toggle(this.todayBtn !== false);
18445 this.updateNavArrows();
18448 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18450 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18452 prevMonth.setUTCDate(day);
18454 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18456 var nextMonth = new Date(prevMonth);
18458 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18460 nextMonth = nextMonth.valueOf();
18462 var fillMonths = false;
18464 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18466 while(prevMonth.valueOf() < nextMonth) {
18469 if (prevMonth.getUTCDay() === this.weekStart) {
18471 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18479 if(this.calendarWeeks){
18480 // ISO 8601: First week contains first thursday.
18481 // ISO also states week starts on Monday, but we can be more abstract here.
18483 // Start of current week: based on weekstart/current date
18484 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18485 // Thursday of this week
18486 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18487 // First Thursday of year, year from thursday
18488 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18489 // Calendar week: ms between thursdays, div ms per day, div 7 days
18490 calWeek = (th - yth) / 864e5 / 7 + 1;
18492 fillMonths.cn.push({
18500 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18502 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18505 if (this.todayHighlight &&
18506 prevMonth.getUTCFullYear() == today.getFullYear() &&
18507 prevMonth.getUTCMonth() == today.getMonth() &&
18508 prevMonth.getUTCDate() == today.getDate()) {
18509 clsName += ' today';
18512 if (currentDate && prevMonth.valueOf() === currentDate) {
18513 clsName += ' active';
18516 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18517 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18518 clsName += ' disabled';
18521 fillMonths.cn.push({
18523 cls: 'day ' + clsName,
18524 html: prevMonth.getDate()
18527 prevMonth.setDate(prevMonth.getDate()+1);
18530 var currentYear = this.date && this.date.getUTCFullYear();
18531 var currentMonth = this.date && this.date.getUTCMonth();
18533 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18535 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18536 v.removeClass('active');
18538 if(currentYear === year && k === currentMonth){
18539 v.addClass('active');
18542 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18543 v.addClass('disabled');
18549 year = parseInt(year/10, 10) * 10;
18551 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18553 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18556 for (var i = -1; i < 11; i++) {
18557 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18559 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18567 showMode: function(dir)
18570 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18573 Roo.each(this.picker().select('>div',true).elements, function(v){
18574 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18577 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18582 if(this.isInline) {
18586 this.picker().removeClass(['bottom', 'top']);
18588 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18590 * place to the top of element!
18594 this.picker().addClass('top');
18595 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18600 this.picker().addClass('bottom');
18602 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18605 parseDate : function(value)
18607 if(!value || value instanceof Date){
18610 var v = Date.parseDate(value, this.format);
18611 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18612 v = Date.parseDate(value, 'Y-m-d');
18614 if(!v && this.altFormats){
18615 if(!this.altFormatsArray){
18616 this.altFormatsArray = this.altFormats.split("|");
18618 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18619 v = Date.parseDate(value, this.altFormatsArray[i]);
18625 formatDate : function(date, fmt)
18627 return (!date || !(date instanceof Date)) ?
18628 date : date.dateFormat(fmt || this.format);
18631 onFocus : function()
18633 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18637 onBlur : function()
18639 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18641 var d = this.inputEl().getValue();
18650 this.picker().show();
18654 this.fireEvent('show', this, this.date);
18659 if(this.isInline) {
18662 this.picker().hide();
18663 this.viewMode = this.startViewMode;
18666 this.fireEvent('hide', this, this.date);
18670 onMousedown: function(e)
18672 e.stopPropagation();
18673 e.preventDefault();
18678 Roo.bootstrap.DateField.superclass.keyup.call(this);
18682 setValue: function(v)
18684 if(this.fireEvent('beforeselect', this, v) !== false){
18685 var d = new Date(this.parseDate(v) ).clearTime();
18687 if(isNaN(d.getTime())){
18688 this.date = this.viewDate = '';
18689 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18693 v = this.formatDate(d);
18695 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18697 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18701 this.fireEvent('select', this, this.date);
18705 getValue: function()
18707 return this.formatDate(this.date);
18710 fireKey: function(e)
18712 if (!this.picker().isVisible()){
18713 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18719 var dateChanged = false,
18721 newDate, newViewDate;
18726 e.preventDefault();
18730 if (!this.keyboardNavigation) {
18733 dir = e.keyCode == 37 ? -1 : 1;
18736 newDate = this.moveYear(this.date, dir);
18737 newViewDate = this.moveYear(this.viewDate, dir);
18738 } else if (e.shiftKey){
18739 newDate = this.moveMonth(this.date, dir);
18740 newViewDate = this.moveMonth(this.viewDate, dir);
18742 newDate = new Date(this.date);
18743 newDate.setUTCDate(this.date.getUTCDate() + dir);
18744 newViewDate = new Date(this.viewDate);
18745 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18747 if (this.dateWithinRange(newDate)){
18748 this.date = newDate;
18749 this.viewDate = newViewDate;
18750 this.setValue(this.formatDate(this.date));
18752 e.preventDefault();
18753 dateChanged = true;
18758 if (!this.keyboardNavigation) {
18761 dir = e.keyCode == 38 ? -1 : 1;
18763 newDate = this.moveYear(this.date, dir);
18764 newViewDate = this.moveYear(this.viewDate, dir);
18765 } else if (e.shiftKey){
18766 newDate = this.moveMonth(this.date, dir);
18767 newViewDate = this.moveMonth(this.viewDate, dir);
18769 newDate = new Date(this.date);
18770 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18771 newViewDate = new Date(this.viewDate);
18772 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18774 if (this.dateWithinRange(newDate)){
18775 this.date = newDate;
18776 this.viewDate = newViewDate;
18777 this.setValue(this.formatDate(this.date));
18779 e.preventDefault();
18780 dateChanged = true;
18784 this.setValue(this.formatDate(this.date));
18786 e.preventDefault();
18789 this.setValue(this.formatDate(this.date));
18803 onClick: function(e)
18805 e.stopPropagation();
18806 e.preventDefault();
18808 var target = e.getTarget();
18810 if(target.nodeName.toLowerCase() === 'i'){
18811 target = Roo.get(target).dom.parentNode;
18814 var nodeName = target.nodeName;
18815 var className = target.className;
18816 var html = target.innerHTML;
18817 //Roo.log(nodeName);
18819 switch(nodeName.toLowerCase()) {
18821 switch(className) {
18827 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18828 switch(this.viewMode){
18830 this.viewDate = this.moveMonth(this.viewDate, dir);
18834 this.viewDate = this.moveYear(this.viewDate, dir);
18840 var date = new Date();
18841 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18843 this.setValue(this.formatDate(this.date));
18850 if (className.indexOf('disabled') < 0) {
18851 this.viewDate.setUTCDate(1);
18852 if (className.indexOf('month') > -1) {
18853 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18855 var year = parseInt(html, 10) || 0;
18856 this.viewDate.setUTCFullYear(year);
18860 if(this.singleMode){
18861 this.setValue(this.formatDate(this.viewDate));
18872 //Roo.log(className);
18873 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18874 var day = parseInt(html, 10) || 1;
18875 var year = this.viewDate.getUTCFullYear(),
18876 month = this.viewDate.getUTCMonth();
18878 if (className.indexOf('old') > -1) {
18885 } else if (className.indexOf('new') > -1) {
18893 //Roo.log([year,month,day]);
18894 this.date = this.UTCDate(year, month, day,0,0,0,0);
18895 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18897 //Roo.log(this.formatDate(this.date));
18898 this.setValue(this.formatDate(this.date));
18905 setStartDate: function(startDate)
18907 this.startDate = startDate || -Infinity;
18908 if (this.startDate !== -Infinity) {
18909 this.startDate = this.parseDate(this.startDate);
18912 this.updateNavArrows();
18915 setEndDate: function(endDate)
18917 this.endDate = endDate || Infinity;
18918 if (this.endDate !== Infinity) {
18919 this.endDate = this.parseDate(this.endDate);
18922 this.updateNavArrows();
18925 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18927 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18928 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18929 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18931 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18932 return parseInt(d, 10);
18935 this.updateNavArrows();
18938 updateNavArrows: function()
18940 if(this.singleMode){
18944 var d = new Date(this.viewDate),
18945 year = d.getUTCFullYear(),
18946 month = d.getUTCMonth();
18948 Roo.each(this.picker().select('.prev', true).elements, function(v){
18950 switch (this.viewMode) {
18953 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18959 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18966 Roo.each(this.picker().select('.next', true).elements, function(v){
18968 switch (this.viewMode) {
18971 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18977 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18985 moveMonth: function(date, dir)
18990 var new_date = new Date(date.valueOf()),
18991 day = new_date.getUTCDate(),
18992 month = new_date.getUTCMonth(),
18993 mag = Math.abs(dir),
18995 dir = dir > 0 ? 1 : -1;
18998 // If going back one month, make sure month is not current month
18999 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19001 return new_date.getUTCMonth() == month;
19003 // If going forward one month, make sure month is as expected
19004 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19006 return new_date.getUTCMonth() != new_month;
19008 new_month = month + dir;
19009 new_date.setUTCMonth(new_month);
19010 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19011 if (new_month < 0 || new_month > 11) {
19012 new_month = (new_month + 12) % 12;
19015 // For magnitudes >1, move one month at a time...
19016 for (var i=0; i<mag; i++) {
19017 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19018 new_date = this.moveMonth(new_date, dir);
19020 // ...then reset the day, keeping it in the new month
19021 new_month = new_date.getUTCMonth();
19022 new_date.setUTCDate(day);
19024 return new_month != new_date.getUTCMonth();
19027 // Common date-resetting loop -- if date is beyond end of month, make it
19030 new_date.setUTCDate(--day);
19031 new_date.setUTCMonth(new_month);
19036 moveYear: function(date, dir)
19038 return this.moveMonth(date, dir*12);
19041 dateWithinRange: function(date)
19043 return date >= this.startDate && date <= this.endDate;
19049 this.picker().remove();
19052 validateValue : function(value)
19054 if(value.length < 1) {
19055 if(this.allowBlank){
19061 if(value.length < this.minLength){
19064 if(value.length > this.maxLength){
19068 var vt = Roo.form.VTypes;
19069 if(!vt[this.vtype](value, this)){
19073 if(typeof this.validator == "function"){
19074 var msg = this.validator(value);
19080 if(this.regex && !this.regex.test(value)){
19084 if(typeof(this.parseDate(value)) == 'undefined'){
19088 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19092 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19102 Roo.apply(Roo.bootstrap.DateField, {
19113 html: '<i class="fa fa-arrow-left"/>'
19123 html: '<i class="fa fa-arrow-right"/>'
19165 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19166 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19167 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19168 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19169 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19182 navFnc: 'FullYear',
19187 navFnc: 'FullYear',
19192 Roo.apply(Roo.bootstrap.DateField, {
19196 cls: 'datepicker dropdown-menu roo-dynamic',
19200 cls: 'datepicker-days',
19204 cls: 'table-condensed',
19206 Roo.bootstrap.DateField.head,
19210 Roo.bootstrap.DateField.footer
19217 cls: 'datepicker-months',
19221 cls: 'table-condensed',
19223 Roo.bootstrap.DateField.head,
19224 Roo.bootstrap.DateField.content,
19225 Roo.bootstrap.DateField.footer
19232 cls: 'datepicker-years',
19236 cls: 'table-condensed',
19238 Roo.bootstrap.DateField.head,
19239 Roo.bootstrap.DateField.content,
19240 Roo.bootstrap.DateField.footer
19259 * @class Roo.bootstrap.TimeField
19260 * @extends Roo.bootstrap.Input
19261 * Bootstrap DateField class
19265 * Create a new TimeField
19266 * @param {Object} config The config object
19269 Roo.bootstrap.TimeField = function(config){
19270 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19274 * Fires when this field show.
19275 * @param {Roo.bootstrap.DateField} thisthis
19276 * @param {Mixed} date The date value
19281 * Fires when this field hide.
19282 * @param {Roo.bootstrap.DateField} this
19283 * @param {Mixed} date The date value
19288 * Fires when select a date.
19289 * @param {Roo.bootstrap.DateField} this
19290 * @param {Mixed} date The date value
19296 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19299 * @cfg {String} format
19300 * The default time format string which can be overriden for localization support. The format must be
19301 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19305 onRender: function(ct, position)
19308 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19310 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19312 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19314 this.pop = this.picker().select('>.datepicker-time',true).first();
19315 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19317 this.picker().on('mousedown', this.onMousedown, this);
19318 this.picker().on('click', this.onClick, this);
19320 this.picker().addClass('datepicker-dropdown');
19325 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19326 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19327 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19328 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19329 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19330 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19334 fireKey: function(e){
19335 if (!this.picker().isVisible()){
19336 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19342 e.preventDefault();
19350 this.onTogglePeriod();
19353 this.onIncrementMinutes();
19356 this.onDecrementMinutes();
19365 onClick: function(e) {
19366 e.stopPropagation();
19367 e.preventDefault();
19370 picker : function()
19372 return this.el.select('.datepicker', true).first();
19375 fillTime: function()
19377 var time = this.pop.select('tbody', true).first();
19379 time.dom.innerHTML = '';
19394 cls: 'hours-up glyphicon glyphicon-chevron-up'
19414 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19435 cls: 'timepicker-hour',
19450 cls: 'timepicker-minute',
19465 cls: 'btn btn-primary period',
19487 cls: 'hours-down glyphicon glyphicon-chevron-down'
19507 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19525 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19532 var hours = this.time.getHours();
19533 var minutes = this.time.getMinutes();
19546 hours = hours - 12;
19550 hours = '0' + hours;
19554 minutes = '0' + minutes;
19557 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19558 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19559 this.pop.select('button', true).first().dom.innerHTML = period;
19565 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19567 var cls = ['bottom'];
19569 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19576 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19581 this.picker().addClass(cls.join('-'));
19585 Roo.each(cls, function(c){
19587 _this.picker().setTop(_this.inputEl().getHeight());
19591 _this.picker().setTop(0 - _this.picker().getHeight());
19596 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19600 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19607 onFocus : function()
19609 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19613 onBlur : function()
19615 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19621 this.picker().show();
19626 this.fireEvent('show', this, this.date);
19631 this.picker().hide();
19634 this.fireEvent('hide', this, this.date);
19637 setTime : function()
19640 this.setValue(this.time.format(this.format));
19642 this.fireEvent('select', this, this.date);
19647 onMousedown: function(e){
19648 e.stopPropagation();
19649 e.preventDefault();
19652 onIncrementHours: function()
19654 Roo.log('onIncrementHours');
19655 this.time = this.time.add(Date.HOUR, 1);
19660 onDecrementHours: function()
19662 Roo.log('onDecrementHours');
19663 this.time = this.time.add(Date.HOUR, -1);
19667 onIncrementMinutes: function()
19669 Roo.log('onIncrementMinutes');
19670 this.time = this.time.add(Date.MINUTE, 1);
19674 onDecrementMinutes: function()
19676 Roo.log('onDecrementMinutes');
19677 this.time = this.time.add(Date.MINUTE, -1);
19681 onTogglePeriod: function()
19683 Roo.log('onTogglePeriod');
19684 this.time = this.time.add(Date.HOUR, 12);
19691 Roo.apply(Roo.bootstrap.TimeField, {
19721 cls: 'btn btn-info ok',
19733 Roo.apply(Roo.bootstrap.TimeField, {
19737 cls: 'datepicker dropdown-menu',
19741 cls: 'datepicker-time',
19745 cls: 'table-condensed',
19747 Roo.bootstrap.TimeField.content,
19748 Roo.bootstrap.TimeField.footer
19767 * @class Roo.bootstrap.MonthField
19768 * @extends Roo.bootstrap.Input
19769 * Bootstrap MonthField class
19771 * @cfg {String} language default en
19774 * Create a new MonthField
19775 * @param {Object} config The config object
19778 Roo.bootstrap.MonthField = function(config){
19779 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19784 * Fires when this field show.
19785 * @param {Roo.bootstrap.MonthField} this
19786 * @param {Mixed} date The date value
19791 * Fires when this field hide.
19792 * @param {Roo.bootstrap.MonthField} this
19793 * @param {Mixed} date The date value
19798 * Fires when select a date.
19799 * @param {Roo.bootstrap.MonthField} this
19800 * @param {String} oldvalue The old value
19801 * @param {String} newvalue The new value
19807 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19809 onRender: function(ct, position)
19812 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19814 this.language = this.language || 'en';
19815 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19816 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19818 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19819 this.isInline = false;
19820 this.isInput = true;
19821 this.component = this.el.select('.add-on', true).first() || false;
19822 this.component = (this.component && this.component.length === 0) ? false : this.component;
19823 this.hasInput = this.component && this.inputEL().length;
19825 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19827 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19829 this.picker().on('mousedown', this.onMousedown, this);
19830 this.picker().on('click', this.onClick, this);
19832 this.picker().addClass('datepicker-dropdown');
19834 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19835 v.setStyle('width', '189px');
19842 if(this.isInline) {
19848 setValue: function(v, suppressEvent)
19850 var o = this.getValue();
19852 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19856 if(suppressEvent !== true){
19857 this.fireEvent('select', this, o, v);
19862 getValue: function()
19867 onClick: function(e)
19869 e.stopPropagation();
19870 e.preventDefault();
19872 var target = e.getTarget();
19874 if(target.nodeName.toLowerCase() === 'i'){
19875 target = Roo.get(target).dom.parentNode;
19878 var nodeName = target.nodeName;
19879 var className = target.className;
19880 var html = target.innerHTML;
19882 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19886 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19888 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19894 picker : function()
19896 return this.pickerEl;
19899 fillMonths: function()
19902 var months = this.picker().select('>.datepicker-months td', true).first();
19904 months.dom.innerHTML = '';
19910 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19913 months.createChild(month);
19922 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19923 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19926 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19927 e.removeClass('active');
19929 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19930 e.addClass('active');
19937 if(this.isInline) {
19941 this.picker().removeClass(['bottom', 'top']);
19943 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19945 * place to the top of element!
19949 this.picker().addClass('top');
19950 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19955 this.picker().addClass('bottom');
19957 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19960 onFocus : function()
19962 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19966 onBlur : function()
19968 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19970 var d = this.inputEl().getValue();
19979 this.picker().show();
19980 this.picker().select('>.datepicker-months', true).first().show();
19984 this.fireEvent('show', this, this.date);
19989 if(this.isInline) {
19992 this.picker().hide();
19993 this.fireEvent('hide', this, this.date);
19997 onMousedown: function(e)
19999 e.stopPropagation();
20000 e.preventDefault();
20005 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20009 fireKey: function(e)
20011 if (!this.picker().isVisible()){
20012 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20023 e.preventDefault();
20027 dir = e.keyCode == 37 ? -1 : 1;
20029 this.vIndex = this.vIndex + dir;
20031 if(this.vIndex < 0){
20035 if(this.vIndex > 11){
20039 if(isNaN(this.vIndex)){
20043 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20049 dir = e.keyCode == 38 ? -1 : 1;
20051 this.vIndex = this.vIndex + dir * 4;
20053 if(this.vIndex < 0){
20057 if(this.vIndex > 11){
20061 if(isNaN(this.vIndex)){
20065 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20070 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20071 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20075 e.preventDefault();
20078 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20079 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20095 this.picker().remove();
20100 Roo.apply(Roo.bootstrap.MonthField, {
20119 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20120 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20125 Roo.apply(Roo.bootstrap.MonthField, {
20129 cls: 'datepicker dropdown-menu roo-dynamic',
20133 cls: 'datepicker-months',
20137 cls: 'table-condensed',
20139 Roo.bootstrap.DateField.content
20159 * @class Roo.bootstrap.CheckBox
20160 * @extends Roo.bootstrap.Input
20161 * Bootstrap CheckBox class
20163 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20164 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20165 * @cfg {String} boxLabel The text that appears beside the checkbox
20166 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20167 * @cfg {Boolean} checked initnal the element
20168 * @cfg {Boolean} inline inline the element (default false)
20169 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20170 * @cfg {String} tooltip label tooltip
20173 * Create a new CheckBox
20174 * @param {Object} config The config object
20177 Roo.bootstrap.CheckBox = function(config){
20178 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20183 * Fires when the element is checked or unchecked.
20184 * @param {Roo.bootstrap.CheckBox} this This input
20185 * @param {Boolean} checked The new checked value
20190 * Fires when the element is click.
20191 * @param {Roo.bootstrap.CheckBox} this This input
20198 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20200 inputType: 'checkbox',
20209 getAutoCreate : function()
20211 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20217 cfg.cls = 'form-group ' + this.inputType; //input-group
20220 cfg.cls += ' ' + this.inputType + '-inline';
20226 type : this.inputType,
20227 value : this.inputValue,
20228 cls : 'roo-' + this.inputType, //'form-box',
20229 placeholder : this.placeholder || ''
20233 if(this.inputType != 'radio'){
20237 cls : 'roo-hidden-value',
20238 value : this.checked ? this.inputValue : this.valueOff
20243 if (this.weight) { // Validity check?
20244 cfg.cls += " " + this.inputType + "-" + this.weight;
20247 if (this.disabled) {
20248 input.disabled=true;
20252 input.checked = this.checked;
20257 input.name = this.name;
20259 if(this.inputType != 'radio'){
20260 hidden.name = this.name;
20261 input.name = '_hidden_' + this.name;
20266 input.cls += ' input-' + this.size;
20271 ['xs','sm','md','lg'].map(function(size){
20272 if (settings[size]) {
20273 cfg.cls += ' col-' + size + '-' + settings[size];
20277 var inputblock = input;
20279 if (this.before || this.after) {
20282 cls : 'input-group',
20287 inputblock.cn.push({
20289 cls : 'input-group-addon',
20294 inputblock.cn.push(input);
20296 if(this.inputType != 'radio'){
20297 inputblock.cn.push(hidden);
20301 inputblock.cn.push({
20303 cls : 'input-group-addon',
20310 if (align ==='left' && this.fieldLabel.length) {
20311 // Roo.log("left and has label");
20316 cls : 'control-label',
20317 html : this.fieldLabel
20327 if(this.labelWidth > 12){
20328 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20331 if(this.labelWidth < 13 && this.labelmd == 0){
20332 this.labelmd = this.labelWidth;
20335 if(this.labellg > 0){
20336 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20337 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20340 if(this.labelmd > 0){
20341 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20342 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20345 if(this.labelsm > 0){
20346 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20347 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20350 if(this.labelxs > 0){
20351 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20352 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20355 } else if ( this.fieldLabel.length) {
20356 // Roo.log(" label");
20360 tag: this.boxLabel ? 'span' : 'label',
20362 cls: 'control-label box-input-label',
20363 //cls : 'input-group-addon',
20364 html : this.fieldLabel
20373 // Roo.log(" no label && no align");
20374 cfg.cn = [ inputblock ] ;
20380 var boxLabelCfg = {
20382 //'for': id, // box label is handled by onclick - so no for...
20384 html: this.boxLabel
20388 boxLabelCfg.tooltip = this.tooltip;
20391 cfg.cn.push(boxLabelCfg);
20394 if(this.inputType != 'radio'){
20395 cfg.cn.push(hidden);
20403 * return the real input element.
20405 inputEl: function ()
20407 return this.el.select('input.roo-' + this.inputType,true).first();
20409 hiddenEl: function ()
20411 return this.el.select('input.roo-hidden-value',true).first();
20414 labelEl: function()
20416 return this.el.select('label.control-label',true).first();
20418 /* depricated... */
20422 return this.labelEl();
20425 boxLabelEl: function()
20427 return this.el.select('label.box-label',true).first();
20430 initEvents : function()
20432 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20434 this.inputEl().on('click', this.onClick, this);
20436 if (this.boxLabel) {
20437 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20440 this.startValue = this.getValue();
20443 Roo.bootstrap.CheckBox.register(this);
20447 onClick : function(e)
20449 if(this.fireEvent('click', this, e) !== false){
20450 this.setChecked(!this.checked);
20455 setChecked : function(state,suppressEvent)
20457 this.startValue = this.getValue();
20459 if(this.inputType == 'radio'){
20461 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20462 e.dom.checked = false;
20465 this.inputEl().dom.checked = true;
20467 this.inputEl().dom.value = this.inputValue;
20469 if(suppressEvent !== true){
20470 this.fireEvent('check', this, true);
20478 this.checked = state;
20480 this.inputEl().dom.checked = state;
20483 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20485 if(suppressEvent !== true){
20486 this.fireEvent('check', this, state);
20492 getValue : function()
20494 if(this.inputType == 'radio'){
20495 return this.getGroupValue();
20498 return this.hiddenEl().dom.value;
20502 getGroupValue : function()
20504 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20508 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20511 setValue : function(v,suppressEvent)
20513 if(this.inputType == 'radio'){
20514 this.setGroupValue(v, suppressEvent);
20518 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20523 setGroupValue : function(v, suppressEvent)
20525 this.startValue = this.getValue();
20527 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20528 e.dom.checked = false;
20530 if(e.dom.value == v){
20531 e.dom.checked = true;
20535 if(suppressEvent !== true){
20536 this.fireEvent('check', this, true);
20544 validate : function()
20548 (this.inputType == 'radio' && this.validateRadio()) ||
20549 (this.inputType == 'checkbox' && this.validateCheckbox())
20555 this.markInvalid();
20559 validateRadio : function()
20561 if(this.allowBlank){
20567 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20568 if(!e.dom.checked){
20580 validateCheckbox : function()
20583 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20584 //return (this.getValue() == this.inputValue) ? true : false;
20587 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20595 for(var i in group){
20596 if(group[i].el.isVisible(true)){
20604 for(var i in group){
20609 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20616 * Mark this field as valid
20618 markValid : function()
20622 this.fireEvent('valid', this);
20624 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20627 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20634 if(this.inputType == 'radio'){
20635 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20636 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20637 e.findParent('.form-group', false, true).addClass(_this.validClass);
20644 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20645 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20649 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20655 for(var i in group){
20656 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20657 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20662 * Mark this field as invalid
20663 * @param {String} msg The validation message
20665 markInvalid : function(msg)
20667 if(this.allowBlank){
20673 this.fireEvent('invalid', this, msg);
20675 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20678 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20682 label.markInvalid();
20685 if(this.inputType == 'radio'){
20686 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20687 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20688 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20695 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20696 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20700 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20706 for(var i in group){
20707 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20708 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20713 clearInvalid : function()
20715 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20717 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20719 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20721 if (label && label.iconEl) {
20722 label.iconEl.removeClass(label.validClass);
20723 label.iconEl.removeClass(label.invalidClass);
20727 disable : function()
20729 if(this.inputType != 'radio'){
20730 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20737 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20738 _this.getActionEl().addClass(this.disabledClass);
20739 e.dom.disabled = true;
20743 this.disabled = true;
20744 this.fireEvent("disable", this);
20748 enable : function()
20750 if(this.inputType != 'radio'){
20751 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20758 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20759 _this.getActionEl().removeClass(this.disabledClass);
20760 e.dom.disabled = false;
20764 this.disabled = false;
20765 this.fireEvent("enable", this);
20769 setBoxLabel : function(v)
20774 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20780 Roo.apply(Roo.bootstrap.CheckBox, {
20785 * register a CheckBox Group
20786 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20788 register : function(checkbox)
20790 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20791 this.groups[checkbox.groupId] = {};
20794 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20798 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20802 * fetch a CheckBox Group based on the group ID
20803 * @param {string} the group ID
20804 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20806 get: function(groupId) {
20807 if (typeof(this.groups[groupId]) == 'undefined') {
20811 return this.groups[groupId] ;
20824 * @class Roo.bootstrap.Radio
20825 * @extends Roo.bootstrap.Component
20826 * Bootstrap Radio class
20827 * @cfg {String} boxLabel - the label associated
20828 * @cfg {String} value - the value of radio
20831 * Create a new Radio
20832 * @param {Object} config The config object
20834 Roo.bootstrap.Radio = function(config){
20835 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20839 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20845 getAutoCreate : function()
20849 cls : 'form-group radio',
20854 html : this.boxLabel
20862 initEvents : function()
20864 this.parent().register(this);
20866 this.el.on('click', this.onClick, this);
20870 onClick : function()
20872 this.setChecked(true);
20875 setChecked : function(state, suppressEvent)
20877 this.parent().setValue(this.value, suppressEvent);
20881 setBoxLabel : function(v)
20886 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20901 * @class Roo.bootstrap.SecurePass
20902 * @extends Roo.bootstrap.Input
20903 * Bootstrap SecurePass class
20907 * Create a new SecurePass
20908 * @param {Object} config The config object
20911 Roo.bootstrap.SecurePass = function (config) {
20912 // these go here, so the translation tool can replace them..
20914 PwdEmpty: "Please type a password, and then retype it to confirm.",
20915 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20916 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20917 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20918 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20919 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20920 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20921 TooWeak: "Your password is Too Weak."
20923 this.meterLabel = "Password strength:";
20924 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20925 this.meterClass = [
20926 "roo-password-meter-tooweak",
20927 "roo-password-meter-weak",
20928 "roo-password-meter-medium",
20929 "roo-password-meter-strong",
20930 "roo-password-meter-grey"
20935 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20938 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20940 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20942 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20943 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20944 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20945 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20946 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20947 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20948 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20958 * @cfg {String/Object} Label for the strength meter (defaults to
20959 * 'Password strength:')
20964 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20965 * ['Weak', 'Medium', 'Strong'])
20968 pwdStrengths: false,
20981 initEvents: function ()
20983 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20985 if (this.el.is('input[type=password]') && Roo.isSafari) {
20986 this.el.on('keydown', this.SafariOnKeyDown, this);
20989 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20992 onRender: function (ct, position)
20994 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20995 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20996 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20998 this.trigger.createChild({
21003 cls: 'roo-password-meter-grey col-xs-12',
21006 //width: this.meterWidth + 'px'
21010 cls: 'roo-password-meter-text'
21016 if (this.hideTrigger) {
21017 this.trigger.setDisplayed(false);
21019 this.setSize(this.width || '', this.height || '');
21022 onDestroy: function ()
21024 if (this.trigger) {
21025 this.trigger.removeAllListeners();
21026 this.trigger.remove();
21029 this.wrap.remove();
21031 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21034 checkStrength: function ()
21036 var pwd = this.inputEl().getValue();
21037 if (pwd == this._lastPwd) {
21042 if (this.ClientSideStrongPassword(pwd)) {
21044 } else if (this.ClientSideMediumPassword(pwd)) {
21046 } else if (this.ClientSideWeakPassword(pwd)) {
21052 Roo.log('strength1: ' + strength);
21054 //var pm = this.trigger.child('div/div/div').dom;
21055 var pm = this.trigger.child('div/div');
21056 pm.removeClass(this.meterClass);
21057 pm.addClass(this.meterClass[strength]);
21060 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21062 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21064 this._lastPwd = pwd;
21068 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21070 this._lastPwd = '';
21072 var pm = this.trigger.child('div/div');
21073 pm.removeClass(this.meterClass);
21074 pm.addClass('roo-password-meter-grey');
21077 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21080 this.inputEl().dom.type='password';
21083 validateValue: function (value)
21086 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21089 if (value.length == 0) {
21090 if (this.allowBlank) {
21091 this.clearInvalid();
21095 this.markInvalid(this.errors.PwdEmpty);
21096 this.errorMsg = this.errors.PwdEmpty;
21104 if ('[\x21-\x7e]*'.match(value)) {
21105 this.markInvalid(this.errors.PwdBadChar);
21106 this.errorMsg = this.errors.PwdBadChar;
21109 if (value.length < 6) {
21110 this.markInvalid(this.errors.PwdShort);
21111 this.errorMsg = this.errors.PwdShort;
21114 if (value.length > 16) {
21115 this.markInvalid(this.errors.PwdLong);
21116 this.errorMsg = this.errors.PwdLong;
21120 if (this.ClientSideStrongPassword(value)) {
21122 } else if (this.ClientSideMediumPassword(value)) {
21124 } else if (this.ClientSideWeakPassword(value)) {
21131 if (strength < 2) {
21132 //this.markInvalid(this.errors.TooWeak);
21133 this.errorMsg = this.errors.TooWeak;
21138 console.log('strength2: ' + strength);
21140 //var pm = this.trigger.child('div/div/div').dom;
21142 var pm = this.trigger.child('div/div');
21143 pm.removeClass(this.meterClass);
21144 pm.addClass(this.meterClass[strength]);
21146 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21148 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21150 this.errorMsg = '';
21154 CharacterSetChecks: function (type)
21157 this.fResult = false;
21160 isctype: function (character, type)
21163 case this.kCapitalLetter:
21164 if (character >= 'A' && character <= 'Z') {
21169 case this.kSmallLetter:
21170 if (character >= 'a' && character <= 'z') {
21176 if (character >= '0' && character <= '9') {
21181 case this.kPunctuation:
21182 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21193 IsLongEnough: function (pwd, size)
21195 return !(pwd == null || isNaN(size) || pwd.length < size);
21198 SpansEnoughCharacterSets: function (word, nb)
21200 if (!this.IsLongEnough(word, nb))
21205 var characterSetChecks = new Array(
21206 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21207 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21210 for (var index = 0; index < word.length; ++index) {
21211 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21212 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21213 characterSetChecks[nCharSet].fResult = true;
21220 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21221 if (characterSetChecks[nCharSet].fResult) {
21226 if (nCharSets < nb) {
21232 ClientSideStrongPassword: function (pwd)
21234 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21237 ClientSideMediumPassword: function (pwd)
21239 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21242 ClientSideWeakPassword: function (pwd)
21244 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21247 })//<script type="text/javascript">
21250 * Based Ext JS Library 1.1.1
21251 * Copyright(c) 2006-2007, Ext JS, LLC.
21257 * @class Roo.HtmlEditorCore
21258 * @extends Roo.Component
21259 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21261 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21264 Roo.HtmlEditorCore = function(config){
21267 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21272 * @event initialize
21273 * Fires when the editor is fully initialized (including the iframe)
21274 * @param {Roo.HtmlEditorCore} this
21279 * Fires when the editor is first receives the focus. Any insertion must wait
21280 * until after this event.
21281 * @param {Roo.HtmlEditorCore} this
21285 * @event beforesync
21286 * Fires before the textarea is updated with content from the editor iframe. Return false
21287 * to cancel the sync.
21288 * @param {Roo.HtmlEditorCore} this
21289 * @param {String} html
21293 * @event beforepush
21294 * Fires before the iframe editor is updated with content from the textarea. Return false
21295 * to cancel the push.
21296 * @param {Roo.HtmlEditorCore} this
21297 * @param {String} html
21302 * Fires when the textarea is updated with content from the editor iframe.
21303 * @param {Roo.HtmlEditorCore} this
21304 * @param {String} html
21309 * Fires when the iframe editor is updated with content from the textarea.
21310 * @param {Roo.HtmlEditorCore} this
21311 * @param {String} html
21316 * @event editorevent
21317 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21318 * @param {Roo.HtmlEditorCore} this
21324 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21326 // defaults : white / black...
21327 this.applyBlacklists();
21334 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21338 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21344 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21349 * @cfg {Number} height (in pixels)
21353 * @cfg {Number} width (in pixels)
21358 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21361 stylesheets: false,
21366 // private properties
21367 validationEvent : false,
21369 initialized : false,
21371 sourceEditMode : false,
21372 onFocus : Roo.emptyFn,
21374 hideMode:'offsets',
21378 // blacklist + whitelisted elements..
21385 * Protected method that will not generally be called directly. It
21386 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21387 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21389 getDocMarkup : function(){
21393 // inherit styels from page...??
21394 if (this.stylesheets === false) {
21396 Roo.get(document.head).select('style').each(function(node) {
21397 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21400 Roo.get(document.head).select('link').each(function(node) {
21401 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21404 } else if (!this.stylesheets.length) {
21406 st = '<style type="text/css">' +
21407 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21410 st = '<style type="text/css">' +
21415 st += '<style type="text/css">' +
21416 'IMG { cursor: pointer } ' +
21419 var cls = 'roo-htmleditor-body';
21421 if(this.bodyCls.length){
21422 cls += ' ' + this.bodyCls;
21425 return '<html><head>' + st +
21426 //<style type="text/css">' +
21427 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21429 ' </head><body class="' + cls + '"></body></html>';
21433 onRender : function(ct, position)
21436 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21437 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21440 this.el.dom.style.border = '0 none';
21441 this.el.dom.setAttribute('tabIndex', -1);
21442 this.el.addClass('x-hidden hide');
21446 if(Roo.isIE){ // fix IE 1px bogus margin
21447 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21451 this.frameId = Roo.id();
21455 var iframe = this.owner.wrap.createChild({
21457 cls: 'form-control', // bootstrap..
21459 name: this.frameId,
21460 frameBorder : 'no',
21461 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21466 this.iframe = iframe.dom;
21468 this.assignDocWin();
21470 this.doc.designMode = 'on';
21473 this.doc.write(this.getDocMarkup());
21477 var task = { // must defer to wait for browser to be ready
21479 //console.log("run task?" + this.doc.readyState);
21480 this.assignDocWin();
21481 if(this.doc.body || this.doc.readyState == 'complete'){
21483 this.doc.designMode="on";
21487 Roo.TaskMgr.stop(task);
21488 this.initEditor.defer(10, this);
21495 Roo.TaskMgr.start(task);
21500 onResize : function(w, h)
21502 Roo.log('resize: ' +w + ',' + h );
21503 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21507 if(typeof w == 'number'){
21509 this.iframe.style.width = w + 'px';
21511 if(typeof h == 'number'){
21513 this.iframe.style.height = h + 'px';
21515 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21522 * Toggles the editor between standard and source edit mode.
21523 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21525 toggleSourceEdit : function(sourceEditMode){
21527 this.sourceEditMode = sourceEditMode === true;
21529 if(this.sourceEditMode){
21531 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21534 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21535 //this.iframe.className = '';
21538 //this.setSize(this.owner.wrap.getSize());
21539 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21546 * Protected method that will not generally be called directly. If you need/want
21547 * custom HTML cleanup, this is the method you should override.
21548 * @param {String} html The HTML to be cleaned
21549 * return {String} The cleaned HTML
21551 cleanHtml : function(html){
21552 html = String(html);
21553 if(html.length > 5){
21554 if(Roo.isSafari){ // strip safari nonsense
21555 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21558 if(html == ' '){
21565 * HTML Editor -> Textarea
21566 * Protected method that will not generally be called directly. Syncs the contents
21567 * of the editor iframe with the textarea.
21569 syncValue : function(){
21570 if(this.initialized){
21571 var bd = (this.doc.body || this.doc.documentElement);
21572 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21573 var html = bd.innerHTML;
21575 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21576 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21578 html = '<div style="'+m[0]+'">' + html + '</div>';
21581 html = this.cleanHtml(html);
21582 // fix up the special chars.. normaly like back quotes in word...
21583 // however we do not want to do this with chinese..
21584 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21585 var cc = b.charCodeAt();
21587 (cc >= 0x4E00 && cc < 0xA000 ) ||
21588 (cc >= 0x3400 && cc < 0x4E00 ) ||
21589 (cc >= 0xf900 && cc < 0xfb00 )
21595 if(this.owner.fireEvent('beforesync', this, html) !== false){
21596 this.el.dom.value = html;
21597 this.owner.fireEvent('sync', this, html);
21603 * Protected method that will not generally be called directly. Pushes the value of the textarea
21604 * into the iframe editor.
21606 pushValue : function(){
21607 if(this.initialized){
21608 var v = this.el.dom.value.trim();
21610 // if(v.length < 1){
21614 if(this.owner.fireEvent('beforepush', this, v) !== false){
21615 var d = (this.doc.body || this.doc.documentElement);
21617 this.cleanUpPaste();
21618 this.el.dom.value = d.innerHTML;
21619 this.owner.fireEvent('push', this, v);
21625 deferFocus : function(){
21626 this.focus.defer(10, this);
21630 focus : function(){
21631 if(this.win && !this.sourceEditMode){
21638 assignDocWin: function()
21640 var iframe = this.iframe;
21643 this.doc = iframe.contentWindow.document;
21644 this.win = iframe.contentWindow;
21646 // if (!Roo.get(this.frameId)) {
21649 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21650 // this.win = Roo.get(this.frameId).dom.contentWindow;
21652 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21656 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21657 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21662 initEditor : function(){
21663 //console.log("INIT EDITOR");
21664 this.assignDocWin();
21668 this.doc.designMode="on";
21670 this.doc.write(this.getDocMarkup());
21673 var dbody = (this.doc.body || this.doc.documentElement);
21674 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21675 // this copies styles from the containing element into thsi one..
21676 // not sure why we need all of this..
21677 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21679 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21680 //ss['background-attachment'] = 'fixed'; // w3c
21681 dbody.bgProperties = 'fixed'; // ie
21682 //Roo.DomHelper.applyStyles(dbody, ss);
21683 Roo.EventManager.on(this.doc, {
21684 //'mousedown': this.onEditorEvent,
21685 'mouseup': this.onEditorEvent,
21686 'dblclick': this.onEditorEvent,
21687 'click': this.onEditorEvent,
21688 'keyup': this.onEditorEvent,
21693 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21695 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21696 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21698 this.initialized = true;
21700 this.owner.fireEvent('initialize', this);
21705 onDestroy : function(){
21711 //for (var i =0; i < this.toolbars.length;i++) {
21712 // // fixme - ask toolbars for heights?
21713 // this.toolbars[i].onDestroy();
21716 //this.wrap.dom.innerHTML = '';
21717 //this.wrap.remove();
21722 onFirstFocus : function(){
21724 this.assignDocWin();
21727 this.activated = true;
21730 if(Roo.isGecko){ // prevent silly gecko errors
21732 var s = this.win.getSelection();
21733 if(!s.focusNode || s.focusNode.nodeType != 3){
21734 var r = s.getRangeAt(0);
21735 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21740 this.execCmd('useCSS', true);
21741 this.execCmd('styleWithCSS', false);
21744 this.owner.fireEvent('activate', this);
21748 adjustFont: function(btn){
21749 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21750 //if(Roo.isSafari){ // safari
21753 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21754 if(Roo.isSafari){ // safari
21755 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21756 v = (v < 10) ? 10 : v;
21757 v = (v > 48) ? 48 : v;
21758 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21763 v = Math.max(1, v+adjust);
21765 this.execCmd('FontSize', v );
21768 onEditorEvent : function(e)
21770 this.owner.fireEvent('editorevent', this, e);
21771 // this.updateToolbar();
21772 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21775 insertTag : function(tg)
21777 // could be a bit smarter... -> wrap the current selected tRoo..
21778 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21780 range = this.createRange(this.getSelection());
21781 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21782 wrappingNode.appendChild(range.extractContents());
21783 range.insertNode(wrappingNode);
21790 this.execCmd("formatblock", tg);
21794 insertText : function(txt)
21798 var range = this.createRange();
21799 range.deleteContents();
21800 //alert(Sender.getAttribute('label'));
21802 range.insertNode(this.doc.createTextNode(txt));
21808 * Executes a Midas editor command on the editor document and performs necessary focus and
21809 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21810 * @param {String} cmd The Midas command
21811 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21813 relayCmd : function(cmd, value){
21815 this.execCmd(cmd, value);
21816 this.owner.fireEvent('editorevent', this);
21817 //this.updateToolbar();
21818 this.owner.deferFocus();
21822 * Executes a Midas editor command directly on the editor document.
21823 * For visual commands, you should use {@link #relayCmd} instead.
21824 * <b>This should only be called after the editor is initialized.</b>
21825 * @param {String} cmd The Midas command
21826 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21828 execCmd : function(cmd, value){
21829 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21836 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21838 * @param {String} text | dom node..
21840 insertAtCursor : function(text)
21843 if(!this.activated){
21849 var r = this.doc.selection.createRange();
21860 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21864 // from jquery ui (MIT licenced)
21866 var win = this.win;
21868 if (win.getSelection && win.getSelection().getRangeAt) {
21869 range = win.getSelection().getRangeAt(0);
21870 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21871 range.insertNode(node);
21872 } else if (win.document.selection && win.document.selection.createRange) {
21873 // no firefox support
21874 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21875 win.document.selection.createRange().pasteHTML(txt);
21877 // no firefox support
21878 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21879 this.execCmd('InsertHTML', txt);
21888 mozKeyPress : function(e){
21890 var c = e.getCharCode(), cmd;
21893 c = String.fromCharCode(c).toLowerCase();
21907 this.cleanUpPaste.defer(100, this);
21915 e.preventDefault();
21923 fixKeys : function(){ // load time branching for fastest keydown performance
21925 return function(e){
21926 var k = e.getKey(), r;
21929 r = this.doc.selection.createRange();
21932 r.pasteHTML('    ');
21939 r = this.doc.selection.createRange();
21941 var target = r.parentElement();
21942 if(!target || target.tagName.toLowerCase() != 'li'){
21944 r.pasteHTML('<br />');
21950 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21951 this.cleanUpPaste.defer(100, this);
21957 }else if(Roo.isOpera){
21958 return function(e){
21959 var k = e.getKey();
21963 this.execCmd('InsertHTML','    ');
21966 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21967 this.cleanUpPaste.defer(100, this);
21972 }else if(Roo.isSafari){
21973 return function(e){
21974 var k = e.getKey();
21978 this.execCmd('InsertText','\t');
21982 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21983 this.cleanUpPaste.defer(100, this);
21991 getAllAncestors: function()
21993 var p = this.getSelectedNode();
21996 a.push(p); // push blank onto stack..
21997 p = this.getParentElement();
22001 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22005 a.push(this.doc.body);
22009 lastSelNode : false,
22012 getSelection : function()
22014 this.assignDocWin();
22015 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22018 getSelectedNode: function()
22020 // this may only work on Gecko!!!
22022 // should we cache this!!!!
22027 var range = this.createRange(this.getSelection()).cloneRange();
22030 var parent = range.parentElement();
22032 var testRange = range.duplicate();
22033 testRange.moveToElementText(parent);
22034 if (testRange.inRange(range)) {
22037 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22040 parent = parent.parentElement;
22045 // is ancestor a text element.
22046 var ac = range.commonAncestorContainer;
22047 if (ac.nodeType == 3) {
22048 ac = ac.parentNode;
22051 var ar = ac.childNodes;
22054 var other_nodes = [];
22055 var has_other_nodes = false;
22056 for (var i=0;i<ar.length;i++) {
22057 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22060 // fullly contained node.
22062 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22067 // probably selected..
22068 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22069 other_nodes.push(ar[i]);
22073 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22078 has_other_nodes = true;
22080 if (!nodes.length && other_nodes.length) {
22081 nodes= other_nodes;
22083 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22089 createRange: function(sel)
22091 // this has strange effects when using with
22092 // top toolbar - not sure if it's a great idea.
22093 //this.editor.contentWindow.focus();
22094 if (typeof sel != "undefined") {
22096 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22098 return this.doc.createRange();
22101 return this.doc.createRange();
22104 getParentElement: function()
22107 this.assignDocWin();
22108 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22110 var range = this.createRange(sel);
22113 var p = range.commonAncestorContainer;
22114 while (p.nodeType == 3) { // text node
22125 * Range intersection.. the hard stuff...
22129 * [ -- selected range --- ]
22133 * if end is before start or hits it. fail.
22134 * if start is after end or hits it fail.
22136 * if either hits (but other is outside. - then it's not
22142 // @see http://www.thismuchiknow.co.uk/?p=64.
22143 rangeIntersectsNode : function(range, node)
22145 var nodeRange = node.ownerDocument.createRange();
22147 nodeRange.selectNode(node);
22149 nodeRange.selectNodeContents(node);
22152 var rangeStartRange = range.cloneRange();
22153 rangeStartRange.collapse(true);
22155 var rangeEndRange = range.cloneRange();
22156 rangeEndRange.collapse(false);
22158 var nodeStartRange = nodeRange.cloneRange();
22159 nodeStartRange.collapse(true);
22161 var nodeEndRange = nodeRange.cloneRange();
22162 nodeEndRange.collapse(false);
22164 return rangeStartRange.compareBoundaryPoints(
22165 Range.START_TO_START, nodeEndRange) == -1 &&
22166 rangeEndRange.compareBoundaryPoints(
22167 Range.START_TO_START, nodeStartRange) == 1;
22171 rangeCompareNode : function(range, node)
22173 var nodeRange = node.ownerDocument.createRange();
22175 nodeRange.selectNode(node);
22177 nodeRange.selectNodeContents(node);
22181 range.collapse(true);
22183 nodeRange.collapse(true);
22185 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22186 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22188 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22190 var nodeIsBefore = ss == 1;
22191 var nodeIsAfter = ee == -1;
22193 if (nodeIsBefore && nodeIsAfter) {
22196 if (!nodeIsBefore && nodeIsAfter) {
22197 return 1; //right trailed.
22200 if (nodeIsBefore && !nodeIsAfter) {
22201 return 2; // left trailed.
22207 // private? - in a new class?
22208 cleanUpPaste : function()
22210 // cleans up the whole document..
22211 Roo.log('cleanuppaste');
22213 this.cleanUpChildren(this.doc.body);
22214 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22215 if (clean != this.doc.body.innerHTML) {
22216 this.doc.body.innerHTML = clean;
22221 cleanWordChars : function(input) {// change the chars to hex code
22222 var he = Roo.HtmlEditorCore;
22224 var output = input;
22225 Roo.each(he.swapCodes, function(sw) {
22226 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22228 output = output.replace(swapper, sw[1]);
22235 cleanUpChildren : function (n)
22237 if (!n.childNodes.length) {
22240 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22241 this.cleanUpChild(n.childNodes[i]);
22248 cleanUpChild : function (node)
22251 //console.log(node);
22252 if (node.nodeName == "#text") {
22253 // clean up silly Windows -- stuff?
22256 if (node.nodeName == "#comment") {
22257 node.parentNode.removeChild(node);
22258 // clean up silly Windows -- stuff?
22261 var lcname = node.tagName.toLowerCase();
22262 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22263 // whitelist of tags..
22265 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22267 node.parentNode.removeChild(node);
22272 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22274 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22275 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22277 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22278 // remove_keep_children = true;
22281 if (remove_keep_children) {
22282 this.cleanUpChildren(node);
22283 // inserts everything just before this node...
22284 while (node.childNodes.length) {
22285 var cn = node.childNodes[0];
22286 node.removeChild(cn);
22287 node.parentNode.insertBefore(cn, node);
22289 node.parentNode.removeChild(node);
22293 if (!node.attributes || !node.attributes.length) {
22294 this.cleanUpChildren(node);
22298 function cleanAttr(n,v)
22301 if (v.match(/^\./) || v.match(/^\//)) {
22304 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22307 if (v.match(/^#/)) {
22310 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22311 node.removeAttribute(n);
22315 var cwhite = this.cwhite;
22316 var cblack = this.cblack;
22318 function cleanStyle(n,v)
22320 if (v.match(/expression/)) { //XSS?? should we even bother..
22321 node.removeAttribute(n);
22325 var parts = v.split(/;/);
22328 Roo.each(parts, function(p) {
22329 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22333 var l = p.split(':').shift().replace(/\s+/g,'');
22334 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22336 if ( cwhite.length && cblack.indexOf(l) > -1) {
22337 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22338 //node.removeAttribute(n);
22342 // only allow 'c whitelisted system attributes'
22343 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22344 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22345 //node.removeAttribute(n);
22355 if (clean.length) {
22356 node.setAttribute(n, clean.join(';'));
22358 node.removeAttribute(n);
22364 for (var i = node.attributes.length-1; i > -1 ; i--) {
22365 var a = node.attributes[i];
22368 if (a.name.toLowerCase().substr(0,2)=='on') {
22369 node.removeAttribute(a.name);
22372 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22373 node.removeAttribute(a.name);
22376 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22377 cleanAttr(a.name,a.value); // fixme..
22380 if (a.name == 'style') {
22381 cleanStyle(a.name,a.value);
22384 /// clean up MS crap..
22385 // tecnically this should be a list of valid class'es..
22388 if (a.name == 'class') {
22389 if (a.value.match(/^Mso/)) {
22390 node.className = '';
22393 if (a.value.match(/^body$/)) {
22394 node.className = '';
22405 this.cleanUpChildren(node);
22411 * Clean up MS wordisms...
22413 cleanWord : function(node)
22418 this.cleanWord(this.doc.body);
22421 if (node.nodeName == "#text") {
22422 // clean up silly Windows -- stuff?
22425 if (node.nodeName == "#comment") {
22426 node.parentNode.removeChild(node);
22427 // clean up silly Windows -- stuff?
22431 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22432 node.parentNode.removeChild(node);
22436 // remove - but keep children..
22437 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22438 while (node.childNodes.length) {
22439 var cn = node.childNodes[0];
22440 node.removeChild(cn);
22441 node.parentNode.insertBefore(cn, node);
22443 node.parentNode.removeChild(node);
22444 this.iterateChildren(node, this.cleanWord);
22448 if (node.className.length) {
22450 var cn = node.className.split(/\W+/);
22452 Roo.each(cn, function(cls) {
22453 if (cls.match(/Mso[a-zA-Z]+/)) {
22458 node.className = cna.length ? cna.join(' ') : '';
22460 node.removeAttribute("class");
22464 if (node.hasAttribute("lang")) {
22465 node.removeAttribute("lang");
22468 if (node.hasAttribute("style")) {
22470 var styles = node.getAttribute("style").split(";");
22472 Roo.each(styles, function(s) {
22473 if (!s.match(/:/)) {
22476 var kv = s.split(":");
22477 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22480 // what ever is left... we allow.
22483 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22484 if (!nstyle.length) {
22485 node.removeAttribute('style');
22488 this.iterateChildren(node, this.cleanWord);
22494 * iterateChildren of a Node, calling fn each time, using this as the scole..
22495 * @param {DomNode} node node to iterate children of.
22496 * @param {Function} fn method of this class to call on each item.
22498 iterateChildren : function(node, fn)
22500 if (!node.childNodes.length) {
22503 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22504 fn.call(this, node.childNodes[i])
22510 * cleanTableWidths.
22512 * Quite often pasting from word etc.. results in tables with column and widths.
22513 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22516 cleanTableWidths : function(node)
22521 this.cleanTableWidths(this.doc.body);
22526 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22529 Roo.log(node.tagName);
22530 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22531 this.iterateChildren(node, this.cleanTableWidths);
22534 if (node.hasAttribute('width')) {
22535 node.removeAttribute('width');
22539 if (node.hasAttribute("style")) {
22542 var styles = node.getAttribute("style").split(";");
22544 Roo.each(styles, function(s) {
22545 if (!s.match(/:/)) {
22548 var kv = s.split(":");
22549 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22552 // what ever is left... we allow.
22555 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22556 if (!nstyle.length) {
22557 node.removeAttribute('style');
22561 this.iterateChildren(node, this.cleanTableWidths);
22569 domToHTML : function(currentElement, depth, nopadtext) {
22571 depth = depth || 0;
22572 nopadtext = nopadtext || false;
22574 if (!currentElement) {
22575 return this.domToHTML(this.doc.body);
22578 //Roo.log(currentElement);
22580 var allText = false;
22581 var nodeName = currentElement.nodeName;
22582 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22584 if (nodeName == '#text') {
22586 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22591 if (nodeName != 'BODY') {
22594 // Prints the node tagName, such as <A>, <IMG>, etc
22597 for(i = 0; i < currentElement.attributes.length;i++) {
22599 var aname = currentElement.attributes.item(i).name;
22600 if (!currentElement.attributes.item(i).value.length) {
22603 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22606 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22615 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22618 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22623 // Traverse the tree
22625 var currentElementChild = currentElement.childNodes.item(i);
22626 var allText = true;
22627 var innerHTML = '';
22629 while (currentElementChild) {
22630 // Formatting code (indent the tree so it looks nice on the screen)
22631 var nopad = nopadtext;
22632 if (lastnode == 'SPAN') {
22636 if (currentElementChild.nodeName == '#text') {
22637 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22638 toadd = nopadtext ? toadd : toadd.trim();
22639 if (!nopad && toadd.length > 80) {
22640 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22642 innerHTML += toadd;
22645 currentElementChild = currentElement.childNodes.item(i);
22651 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22653 // Recursively traverse the tree structure of the child node
22654 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22655 lastnode = currentElementChild.nodeName;
22657 currentElementChild=currentElement.childNodes.item(i);
22663 // The remaining code is mostly for formatting the tree
22664 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22669 ret+= "</"+tagName+">";
22675 applyBlacklists : function()
22677 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22678 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22682 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22683 if (b.indexOf(tag) > -1) {
22686 this.white.push(tag);
22690 Roo.each(w, function(tag) {
22691 if (b.indexOf(tag) > -1) {
22694 if (this.white.indexOf(tag) > -1) {
22697 this.white.push(tag);
22702 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22703 if (w.indexOf(tag) > -1) {
22706 this.black.push(tag);
22710 Roo.each(b, function(tag) {
22711 if (w.indexOf(tag) > -1) {
22714 if (this.black.indexOf(tag) > -1) {
22717 this.black.push(tag);
22722 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22723 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22727 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22728 if (b.indexOf(tag) > -1) {
22731 this.cwhite.push(tag);
22735 Roo.each(w, function(tag) {
22736 if (b.indexOf(tag) > -1) {
22739 if (this.cwhite.indexOf(tag) > -1) {
22742 this.cwhite.push(tag);
22747 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22748 if (w.indexOf(tag) > -1) {
22751 this.cblack.push(tag);
22755 Roo.each(b, function(tag) {
22756 if (w.indexOf(tag) > -1) {
22759 if (this.cblack.indexOf(tag) > -1) {
22762 this.cblack.push(tag);
22767 setStylesheets : function(stylesheets)
22769 if(typeof(stylesheets) == 'string'){
22770 Roo.get(this.iframe.contentDocument.head).createChild({
22772 rel : 'stylesheet',
22781 Roo.each(stylesheets, function(s) {
22786 Roo.get(_this.iframe.contentDocument.head).createChild({
22788 rel : 'stylesheet',
22797 removeStylesheets : function()
22801 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22806 setStyle : function(style)
22808 Roo.get(this.iframe.contentDocument.head).createChild({
22817 // hide stuff that is not compatible
22831 * @event specialkey
22835 * @cfg {String} fieldClass @hide
22838 * @cfg {String} focusClass @hide
22841 * @cfg {String} autoCreate @hide
22844 * @cfg {String} inputType @hide
22847 * @cfg {String} invalidClass @hide
22850 * @cfg {String} invalidText @hide
22853 * @cfg {String} msgFx @hide
22856 * @cfg {String} validateOnBlur @hide
22860 Roo.HtmlEditorCore.white = [
22861 'area', 'br', 'img', 'input', 'hr', 'wbr',
22863 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22864 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22865 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22866 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22867 'table', 'ul', 'xmp',
22869 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22872 'dir', 'menu', 'ol', 'ul', 'dl',
22878 Roo.HtmlEditorCore.black = [
22879 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22881 'base', 'basefont', 'bgsound', 'blink', 'body',
22882 'frame', 'frameset', 'head', 'html', 'ilayer',
22883 'iframe', 'layer', 'link', 'meta', 'object',
22884 'script', 'style' ,'title', 'xml' // clean later..
22886 Roo.HtmlEditorCore.clean = [
22887 'script', 'style', 'title', 'xml'
22889 Roo.HtmlEditorCore.remove = [
22894 Roo.HtmlEditorCore.ablack = [
22898 Roo.HtmlEditorCore.aclean = [
22899 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22903 Roo.HtmlEditorCore.pwhite= [
22904 'http', 'https', 'mailto'
22907 // white listed style attributes.
22908 Roo.HtmlEditorCore.cwhite= [
22909 // 'text-align', /// default is to allow most things..
22915 // black listed style attributes.
22916 Roo.HtmlEditorCore.cblack= [
22917 // 'font-size' -- this can be set by the project
22921 Roo.HtmlEditorCore.swapCodes =[
22940 * @class Roo.bootstrap.HtmlEditor
22941 * @extends Roo.bootstrap.TextArea
22942 * Bootstrap HtmlEditor class
22945 * Create a new HtmlEditor
22946 * @param {Object} config The config object
22949 Roo.bootstrap.HtmlEditor = function(config){
22950 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22951 if (!this.toolbars) {
22952 this.toolbars = [];
22955 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22958 * @event initialize
22959 * Fires when the editor is fully initialized (including the iframe)
22960 * @param {HtmlEditor} this
22965 * Fires when the editor is first receives the focus. Any insertion must wait
22966 * until after this event.
22967 * @param {HtmlEditor} this
22971 * @event beforesync
22972 * Fires before the textarea is updated with content from the editor iframe. Return false
22973 * to cancel the sync.
22974 * @param {HtmlEditor} this
22975 * @param {String} html
22979 * @event beforepush
22980 * Fires before the iframe editor is updated with content from the textarea. Return false
22981 * to cancel the push.
22982 * @param {HtmlEditor} this
22983 * @param {String} html
22988 * Fires when the textarea is updated with content from the editor iframe.
22989 * @param {HtmlEditor} this
22990 * @param {String} html
22995 * Fires when the iframe editor is updated with content from the textarea.
22996 * @param {HtmlEditor} this
22997 * @param {String} html
23001 * @event editmodechange
23002 * Fires when the editor switches edit modes
23003 * @param {HtmlEditor} this
23004 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23006 editmodechange: true,
23008 * @event editorevent
23009 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23010 * @param {HtmlEditor} this
23014 * @event firstfocus
23015 * Fires when on first focus - needed by toolbars..
23016 * @param {HtmlEditor} this
23021 * Auto save the htmlEditor value as a file into Events
23022 * @param {HtmlEditor} this
23026 * @event savedpreview
23027 * preview the saved version of htmlEditor
23028 * @param {HtmlEditor} this
23035 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23039 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23044 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23049 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23054 * @cfg {Number} height (in pixels)
23058 * @cfg {Number} width (in pixels)
23063 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23066 stylesheets: false,
23071 // private properties
23072 validationEvent : false,
23074 initialized : false,
23077 onFocus : Roo.emptyFn,
23079 hideMode:'offsets',
23081 tbContainer : false,
23085 toolbarContainer :function() {
23086 return this.wrap.select('.x-html-editor-tb',true).first();
23090 * Protected method that will not generally be called directly. It
23091 * is called when the editor creates its toolbar. Override this method if you need to
23092 * add custom toolbar buttons.
23093 * @param {HtmlEditor} editor
23095 createToolbar : function(){
23096 Roo.log('renewing');
23097 Roo.log("create toolbars");
23099 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23100 this.toolbars[0].render(this.toolbarContainer());
23104 // if (!editor.toolbars || !editor.toolbars.length) {
23105 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23108 // for (var i =0 ; i < editor.toolbars.length;i++) {
23109 // editor.toolbars[i] = Roo.factory(
23110 // typeof(editor.toolbars[i]) == 'string' ?
23111 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23112 // Roo.bootstrap.HtmlEditor);
23113 // editor.toolbars[i].init(editor);
23119 onRender : function(ct, position)
23121 // Roo.log("Call onRender: " + this.xtype);
23123 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23125 this.wrap = this.inputEl().wrap({
23126 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23129 this.editorcore.onRender(ct, position);
23131 if (this.resizable) {
23132 this.resizeEl = new Roo.Resizable(this.wrap, {
23136 minHeight : this.height,
23137 height: this.height,
23138 handles : this.resizable,
23141 resize : function(r, w, h) {
23142 _t.onResize(w,h); // -something
23148 this.createToolbar(this);
23151 if(!this.width && this.resizable){
23152 this.setSize(this.wrap.getSize());
23154 if (this.resizeEl) {
23155 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23156 // should trigger onReize..
23162 onResize : function(w, h)
23164 Roo.log('resize: ' +w + ',' + h );
23165 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23169 if(this.inputEl() ){
23170 if(typeof w == 'number'){
23171 var aw = w - this.wrap.getFrameWidth('lr');
23172 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23175 if(typeof h == 'number'){
23176 var tbh = -11; // fixme it needs to tool bar size!
23177 for (var i =0; i < this.toolbars.length;i++) {
23178 // fixme - ask toolbars for heights?
23179 tbh += this.toolbars[i].el.getHeight();
23180 //if (this.toolbars[i].footer) {
23181 // tbh += this.toolbars[i].footer.el.getHeight();
23189 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23190 ah -= 5; // knock a few pixes off for look..
23191 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23195 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23196 this.editorcore.onResize(ew,eh);
23201 * Toggles the editor between standard and source edit mode.
23202 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23204 toggleSourceEdit : function(sourceEditMode)
23206 this.editorcore.toggleSourceEdit(sourceEditMode);
23208 if(this.editorcore.sourceEditMode){
23209 Roo.log('editor - showing textarea');
23212 // Roo.log(this.syncValue());
23214 this.inputEl().removeClass(['hide', 'x-hidden']);
23215 this.inputEl().dom.removeAttribute('tabIndex');
23216 this.inputEl().focus();
23218 Roo.log('editor - hiding textarea');
23220 // Roo.log(this.pushValue());
23223 this.inputEl().addClass(['hide', 'x-hidden']);
23224 this.inputEl().dom.setAttribute('tabIndex', -1);
23225 //this.deferFocus();
23228 if(this.resizable){
23229 this.setSize(this.wrap.getSize());
23232 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23235 // private (for BoxComponent)
23236 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23238 // private (for BoxComponent)
23239 getResizeEl : function(){
23243 // private (for BoxComponent)
23244 getPositionEl : function(){
23249 initEvents : function(){
23250 this.originalValue = this.getValue();
23254 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23257 // markInvalid : Roo.emptyFn,
23259 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23262 // clearInvalid : Roo.emptyFn,
23264 setValue : function(v){
23265 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23266 this.editorcore.pushValue();
23271 deferFocus : function(){
23272 this.focus.defer(10, this);
23276 focus : function(){
23277 this.editorcore.focus();
23283 onDestroy : function(){
23289 for (var i =0; i < this.toolbars.length;i++) {
23290 // fixme - ask toolbars for heights?
23291 this.toolbars[i].onDestroy();
23294 this.wrap.dom.innerHTML = '';
23295 this.wrap.remove();
23300 onFirstFocus : function(){
23301 //Roo.log("onFirstFocus");
23302 this.editorcore.onFirstFocus();
23303 for (var i =0; i < this.toolbars.length;i++) {
23304 this.toolbars[i].onFirstFocus();
23310 syncValue : function()
23312 this.editorcore.syncValue();
23315 pushValue : function()
23317 this.editorcore.pushValue();
23321 // hide stuff that is not compatible
23335 * @event specialkey
23339 * @cfg {String} fieldClass @hide
23342 * @cfg {String} focusClass @hide
23345 * @cfg {String} autoCreate @hide
23348 * @cfg {String} inputType @hide
23351 * @cfg {String} invalidClass @hide
23354 * @cfg {String} invalidText @hide
23357 * @cfg {String} msgFx @hide
23360 * @cfg {String} validateOnBlur @hide
23369 Roo.namespace('Roo.bootstrap.htmleditor');
23371 * @class Roo.bootstrap.HtmlEditorToolbar1
23376 new Roo.bootstrap.HtmlEditor({
23379 new Roo.bootstrap.HtmlEditorToolbar1({
23380 disable : { fonts: 1 , format: 1, ..., ... , ...],
23386 * @cfg {Object} disable List of elements to disable..
23387 * @cfg {Array} btns List of additional buttons.
23391 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23394 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23397 Roo.apply(this, config);
23399 // default disabled, based on 'good practice'..
23400 this.disable = this.disable || {};
23401 Roo.applyIf(this.disable, {
23404 specialElements : true
23406 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23408 this.editor = config.editor;
23409 this.editorcore = config.editor.editorcore;
23411 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23413 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23414 // dont call parent... till later.
23416 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23421 editorcore : false,
23426 "h1","h2","h3","h4","h5","h6",
23428 "abbr", "acronym", "address", "cite", "samp", "var",
23432 onRender : function(ct, position)
23434 // Roo.log("Call onRender: " + this.xtype);
23436 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23438 this.el.dom.style.marginBottom = '0';
23440 var editorcore = this.editorcore;
23441 var editor= this.editor;
23444 var btn = function(id,cmd , toggle, handler, html){
23446 var event = toggle ? 'toggle' : 'click';
23451 xns: Roo.bootstrap,
23454 enableToggle:toggle !== false,
23456 pressed : toggle ? false : null,
23459 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23460 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23466 // var cb_box = function...
23471 xns: Roo.bootstrap,
23472 glyphicon : 'font',
23476 xns: Roo.bootstrap,
23480 Roo.each(this.formats, function(f) {
23481 style.menu.items.push({
23483 xns: Roo.bootstrap,
23484 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23489 editorcore.insertTag(this.tagname);
23496 children.push(style);
23498 btn('bold',false,true);
23499 btn('italic',false,true);
23500 btn('align-left', 'justifyleft',true);
23501 btn('align-center', 'justifycenter',true);
23502 btn('align-right' , 'justifyright',true);
23503 btn('link', false, false, function(btn) {
23504 //Roo.log("create link?");
23505 var url = prompt(this.createLinkText, this.defaultLinkValue);
23506 if(url && url != 'http:/'+'/'){
23507 this.editorcore.relayCmd('createlink', url);
23510 btn('list','insertunorderedlist',true);
23511 btn('pencil', false,true, function(btn){
23513 this.toggleSourceEdit(btn.pressed);
23516 if (this.editor.btns.length > 0) {
23517 for (var i = 0; i<this.editor.btns.length; i++) {
23518 children.push(this.editor.btns[i]);
23526 xns: Roo.bootstrap,
23531 xns: Roo.bootstrap,
23536 cog.menu.items.push({
23538 xns: Roo.bootstrap,
23539 html : Clean styles,
23544 editorcore.insertTag(this.tagname);
23553 this.xtype = 'NavSimplebar';
23555 for(var i=0;i< children.length;i++) {
23557 this.buttons.add(this.addxtypeChild(children[i]));
23561 editor.on('editorevent', this.updateToolbar, this);
23563 onBtnClick : function(id)
23565 this.editorcore.relayCmd(id);
23566 this.editorcore.focus();
23570 * Protected method that will not generally be called directly. It triggers
23571 * a toolbar update by reading the markup state of the current selection in the editor.
23573 updateToolbar: function(){
23575 if(!this.editorcore.activated){
23576 this.editor.onFirstFocus(); // is this neeed?
23580 var btns = this.buttons;
23581 var doc = this.editorcore.doc;
23582 btns.get('bold').setActive(doc.queryCommandState('bold'));
23583 btns.get('italic').setActive(doc.queryCommandState('italic'));
23584 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23586 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23587 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23588 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23590 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23591 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23594 var ans = this.editorcore.getAllAncestors();
23595 if (this.formatCombo) {
23598 var store = this.formatCombo.store;
23599 this.formatCombo.setValue("");
23600 for (var i =0; i < ans.length;i++) {
23601 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23603 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23611 // hides menus... - so this cant be on a menu...
23612 Roo.bootstrap.MenuMgr.hideAll();
23614 Roo.bootstrap.MenuMgr.hideAll();
23615 //this.editorsyncValue();
23617 onFirstFocus: function() {
23618 this.buttons.each(function(item){
23622 toggleSourceEdit : function(sourceEditMode){
23625 if(sourceEditMode){
23626 Roo.log("disabling buttons");
23627 this.buttons.each( function(item){
23628 if(item.cmd != 'pencil'){
23634 Roo.log("enabling buttons");
23635 if(this.editorcore.initialized){
23636 this.buttons.each( function(item){
23642 Roo.log("calling toggole on editor");
23643 // tell the editor that it's been pressed..
23644 this.editor.toggleSourceEdit(sourceEditMode);
23654 * @class Roo.bootstrap.Table.AbstractSelectionModel
23655 * @extends Roo.util.Observable
23656 * Abstract base class for grid SelectionModels. It provides the interface that should be
23657 * implemented by descendant classes. This class should not be directly instantiated.
23660 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23661 this.locked = false;
23662 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23666 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23667 /** @ignore Called by the grid automatically. Do not call directly. */
23668 init : function(grid){
23674 * Locks the selections.
23677 this.locked = true;
23681 * Unlocks the selections.
23683 unlock : function(){
23684 this.locked = false;
23688 * Returns true if the selections are locked.
23689 * @return {Boolean}
23691 isLocked : function(){
23692 return this.locked;
23696 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23697 * @class Roo.bootstrap.Table.RowSelectionModel
23698 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23699 * It supports multiple selections and keyboard selection/navigation.
23701 * @param {Object} config
23704 Roo.bootstrap.Table.RowSelectionModel = function(config){
23705 Roo.apply(this, config);
23706 this.selections = new Roo.util.MixedCollection(false, function(o){
23711 this.lastActive = false;
23715 * @event selectionchange
23716 * Fires when the selection changes
23717 * @param {SelectionModel} this
23719 "selectionchange" : true,
23721 * @event afterselectionchange
23722 * Fires after the selection changes (eg. by key press or clicking)
23723 * @param {SelectionModel} this
23725 "afterselectionchange" : true,
23727 * @event beforerowselect
23728 * Fires when a row is selected being selected, return false to cancel.
23729 * @param {SelectionModel} this
23730 * @param {Number} rowIndex The selected index
23731 * @param {Boolean} keepExisting False if other selections will be cleared
23733 "beforerowselect" : true,
23736 * Fires when a row is selected.
23737 * @param {SelectionModel} this
23738 * @param {Number} rowIndex The selected index
23739 * @param {Roo.data.Record} r The record
23741 "rowselect" : true,
23743 * @event rowdeselect
23744 * Fires when a row is deselected.
23745 * @param {SelectionModel} this
23746 * @param {Number} rowIndex The selected index
23748 "rowdeselect" : true
23750 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23751 this.locked = false;
23754 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23756 * @cfg {Boolean} singleSelect
23757 * True to allow selection of only one row at a time (defaults to false)
23759 singleSelect : false,
23762 initEvents : function()
23765 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23766 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23767 //}else{ // allow click to work like normal
23768 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23770 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23771 this.grid.on("rowclick", this.handleMouseDown, this);
23773 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23774 "up" : function(e){
23776 this.selectPrevious(e.shiftKey);
23777 }else if(this.last !== false && this.lastActive !== false){
23778 var last = this.last;
23779 this.selectRange(this.last, this.lastActive-1);
23780 this.grid.getView().focusRow(this.lastActive);
23781 if(last !== false){
23785 this.selectFirstRow();
23787 this.fireEvent("afterselectionchange", this);
23789 "down" : function(e){
23791 this.selectNext(e.shiftKey);
23792 }else if(this.last !== false && this.lastActive !== false){
23793 var last = this.last;
23794 this.selectRange(this.last, this.lastActive+1);
23795 this.grid.getView().focusRow(this.lastActive);
23796 if(last !== false){
23800 this.selectFirstRow();
23802 this.fireEvent("afterselectionchange", this);
23806 this.grid.store.on('load', function(){
23807 this.selections.clear();
23810 var view = this.grid.view;
23811 view.on("refresh", this.onRefresh, this);
23812 view.on("rowupdated", this.onRowUpdated, this);
23813 view.on("rowremoved", this.onRemove, this);
23818 onRefresh : function()
23820 var ds = this.grid.store, i, v = this.grid.view;
23821 var s = this.selections;
23822 s.each(function(r){
23823 if((i = ds.indexOfId(r.id)) != -1){
23832 onRemove : function(v, index, r){
23833 this.selections.remove(r);
23837 onRowUpdated : function(v, index, r){
23838 if(this.isSelected(r)){
23839 v.onRowSelect(index);
23845 * @param {Array} records The records to select
23846 * @param {Boolean} keepExisting (optional) True to keep existing selections
23848 selectRecords : function(records, keepExisting)
23851 this.clearSelections();
23853 var ds = this.grid.store;
23854 for(var i = 0, len = records.length; i < len; i++){
23855 this.selectRow(ds.indexOf(records[i]), true);
23860 * Gets the number of selected rows.
23863 getCount : function(){
23864 return this.selections.length;
23868 * Selects the first row in the grid.
23870 selectFirstRow : function(){
23875 * Select the last row.
23876 * @param {Boolean} keepExisting (optional) True to keep existing selections
23878 selectLastRow : function(keepExisting){
23879 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23880 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23884 * Selects the row immediately following the last selected row.
23885 * @param {Boolean} keepExisting (optional) True to keep existing selections
23887 selectNext : function(keepExisting)
23889 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23890 this.selectRow(this.last+1, keepExisting);
23891 this.grid.getView().focusRow(this.last);
23896 * Selects the row that precedes the last selected row.
23897 * @param {Boolean} keepExisting (optional) True to keep existing selections
23899 selectPrevious : function(keepExisting){
23901 this.selectRow(this.last-1, keepExisting);
23902 this.grid.getView().focusRow(this.last);
23907 * Returns the selected records
23908 * @return {Array} Array of selected records
23910 getSelections : function(){
23911 return [].concat(this.selections.items);
23915 * Returns the first selected record.
23918 getSelected : function(){
23919 return this.selections.itemAt(0);
23924 * Clears all selections.
23926 clearSelections : function(fast)
23932 var ds = this.grid.store;
23933 var s = this.selections;
23934 s.each(function(r){
23935 this.deselectRow(ds.indexOfId(r.id));
23939 this.selections.clear();
23946 * Selects all rows.
23948 selectAll : function(){
23952 this.selections.clear();
23953 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23954 this.selectRow(i, true);
23959 * Returns True if there is a selection.
23960 * @return {Boolean}
23962 hasSelection : function(){
23963 return this.selections.length > 0;
23967 * Returns True if the specified row is selected.
23968 * @param {Number/Record} record The record or index of the record to check
23969 * @return {Boolean}
23971 isSelected : function(index){
23972 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23973 return (r && this.selections.key(r.id) ? true : false);
23977 * Returns True if the specified record id is selected.
23978 * @param {String} id The id of record to check
23979 * @return {Boolean}
23981 isIdSelected : function(id){
23982 return (this.selections.key(id) ? true : false);
23987 handleMouseDBClick : function(e, t){
23991 handleMouseDown : function(e, t)
23993 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23994 if(this.isLocked() || rowIndex < 0 ){
23997 if(e.shiftKey && this.last !== false){
23998 var last = this.last;
23999 this.selectRange(last, rowIndex, e.ctrlKey);
24000 this.last = last; // reset the last
24004 var isSelected = this.isSelected(rowIndex);
24005 //Roo.log("select row:" + rowIndex);
24007 this.deselectRow(rowIndex);
24009 this.selectRow(rowIndex, true);
24013 if(e.button !== 0 && isSelected){
24014 alert('rowIndex 2: ' + rowIndex);
24015 view.focusRow(rowIndex);
24016 }else if(e.ctrlKey && isSelected){
24017 this.deselectRow(rowIndex);
24018 }else if(!isSelected){
24019 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24020 view.focusRow(rowIndex);
24024 this.fireEvent("afterselectionchange", this);
24027 handleDragableRowClick : function(grid, rowIndex, e)
24029 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24030 this.selectRow(rowIndex, false);
24031 grid.view.focusRow(rowIndex);
24032 this.fireEvent("afterselectionchange", this);
24037 * Selects multiple rows.
24038 * @param {Array} rows Array of the indexes of the row to select
24039 * @param {Boolean} keepExisting (optional) True to keep existing selections
24041 selectRows : function(rows, keepExisting){
24043 this.clearSelections();
24045 for(var i = 0, len = rows.length; i < len; i++){
24046 this.selectRow(rows[i], true);
24051 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24052 * @param {Number} startRow The index of the first row in the range
24053 * @param {Number} endRow The index of the last row in the range
24054 * @param {Boolean} keepExisting (optional) True to retain existing selections
24056 selectRange : function(startRow, endRow, keepExisting){
24061 this.clearSelections();
24063 if(startRow <= endRow){
24064 for(var i = startRow; i <= endRow; i++){
24065 this.selectRow(i, true);
24068 for(var i = startRow; i >= endRow; i--){
24069 this.selectRow(i, true);
24075 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24076 * @param {Number} startRow The index of the first row in the range
24077 * @param {Number} endRow The index of the last row in the range
24079 deselectRange : function(startRow, endRow, preventViewNotify){
24083 for(var i = startRow; i <= endRow; i++){
24084 this.deselectRow(i, preventViewNotify);
24090 * @param {Number} row The index of the row to select
24091 * @param {Boolean} keepExisting (optional) True to keep existing selections
24093 selectRow : function(index, keepExisting, preventViewNotify)
24095 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24098 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24099 if(!keepExisting || this.singleSelect){
24100 this.clearSelections();
24103 var r = this.grid.store.getAt(index);
24104 //console.log('selectRow - record id :' + r.id);
24106 this.selections.add(r);
24107 this.last = this.lastActive = index;
24108 if(!preventViewNotify){
24109 var proxy = new Roo.Element(
24110 this.grid.getRowDom(index)
24112 proxy.addClass('bg-info info');
24114 this.fireEvent("rowselect", this, index, r);
24115 this.fireEvent("selectionchange", this);
24121 * @param {Number} row The index of the row to deselect
24123 deselectRow : function(index, preventViewNotify)
24128 if(this.last == index){
24131 if(this.lastActive == index){
24132 this.lastActive = false;
24135 var r = this.grid.store.getAt(index);
24140 this.selections.remove(r);
24141 //.console.log('deselectRow - record id :' + r.id);
24142 if(!preventViewNotify){
24144 var proxy = new Roo.Element(
24145 this.grid.getRowDom(index)
24147 proxy.removeClass('bg-info info');
24149 this.fireEvent("rowdeselect", this, index);
24150 this.fireEvent("selectionchange", this);
24154 restoreLast : function(){
24156 this.last = this._last;
24161 acceptsNav : function(row, col, cm){
24162 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24166 onEditorKey : function(field, e){
24167 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24172 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24174 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24176 }else if(k == e.ENTER && !e.ctrlKey){
24180 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24182 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24184 }else if(k == e.ESC){
24188 g.startEditing(newCell[0], newCell[1]);
24194 * Ext JS Library 1.1.1
24195 * Copyright(c) 2006-2007, Ext JS, LLC.
24197 * Originally Released Under LGPL - original licence link has changed is not relivant.
24200 * <script type="text/javascript">
24204 * @class Roo.bootstrap.PagingToolbar
24205 * @extends Roo.bootstrap.NavSimplebar
24206 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24208 * Create a new PagingToolbar
24209 * @param {Object} config The config object
24210 * @param {Roo.data.Store} store
24212 Roo.bootstrap.PagingToolbar = function(config)
24214 // old args format still supported... - xtype is prefered..
24215 // created from xtype...
24217 this.ds = config.dataSource;
24219 if (config.store && !this.ds) {
24220 this.store= Roo.factory(config.store, Roo.data);
24221 this.ds = this.store;
24222 this.ds.xmodule = this.xmodule || false;
24225 this.toolbarItems = [];
24226 if (config.items) {
24227 this.toolbarItems = config.items;
24230 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24235 this.bind(this.ds);
24238 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24242 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24244 * @cfg {Roo.data.Store} dataSource
24245 * The underlying data store providing the paged data
24248 * @cfg {String/HTMLElement/Element} container
24249 * container The id or element that will contain the toolbar
24252 * @cfg {Boolean} displayInfo
24253 * True to display the displayMsg (defaults to false)
24256 * @cfg {Number} pageSize
24257 * The number of records to display per page (defaults to 20)
24261 * @cfg {String} displayMsg
24262 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24264 displayMsg : 'Displaying {0} - {1} of {2}',
24266 * @cfg {String} emptyMsg
24267 * The message to display when no records are found (defaults to "No data to display")
24269 emptyMsg : 'No data to display',
24271 * Customizable piece of the default paging text (defaults to "Page")
24274 beforePageText : "Page",
24276 * Customizable piece of the default paging text (defaults to "of %0")
24279 afterPageText : "of {0}",
24281 * Customizable piece of the default paging text (defaults to "First Page")
24284 firstText : "First Page",
24286 * Customizable piece of the default paging text (defaults to "Previous Page")
24289 prevText : "Previous Page",
24291 * Customizable piece of the default paging text (defaults to "Next Page")
24294 nextText : "Next Page",
24296 * Customizable piece of the default paging text (defaults to "Last Page")
24299 lastText : "Last Page",
24301 * Customizable piece of the default paging text (defaults to "Refresh")
24304 refreshText : "Refresh",
24308 onRender : function(ct, position)
24310 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24311 this.navgroup.parentId = this.id;
24312 this.navgroup.onRender(this.el, null);
24313 // add the buttons to the navgroup
24315 if(this.displayInfo){
24316 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24317 this.displayEl = this.el.select('.x-paging-info', true).first();
24318 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24319 // this.displayEl = navel.el.select('span',true).first();
24325 Roo.each(_this.buttons, function(e){ // this might need to use render????
24326 Roo.factory(e).onRender(_this.el, null);
24330 Roo.each(_this.toolbarItems, function(e) {
24331 _this.navgroup.addItem(e);
24335 this.first = this.navgroup.addItem({
24336 tooltip: this.firstText,
24338 icon : 'fa fa-backward',
24340 preventDefault: true,
24341 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24344 this.prev = this.navgroup.addItem({
24345 tooltip: this.prevText,
24347 icon : 'fa fa-step-backward',
24349 preventDefault: true,
24350 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24352 //this.addSeparator();
24355 var field = this.navgroup.addItem( {
24357 cls : 'x-paging-position',
24359 html : this.beforePageText +
24360 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24361 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24364 this.field = field.el.select('input', true).first();
24365 this.field.on("keydown", this.onPagingKeydown, this);
24366 this.field.on("focus", function(){this.dom.select();});
24369 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24370 //this.field.setHeight(18);
24371 //this.addSeparator();
24372 this.next = this.navgroup.addItem({
24373 tooltip: this.nextText,
24375 html : ' <i class="fa fa-step-forward">',
24377 preventDefault: true,
24378 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24380 this.last = this.navgroup.addItem({
24381 tooltip: this.lastText,
24382 icon : 'fa fa-forward',
24385 preventDefault: true,
24386 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24388 //this.addSeparator();
24389 this.loading = this.navgroup.addItem({
24390 tooltip: this.refreshText,
24391 icon: 'fa fa-refresh',
24392 preventDefault: true,
24393 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24399 updateInfo : function(){
24400 if(this.displayEl){
24401 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24402 var msg = count == 0 ?
24406 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24408 this.displayEl.update(msg);
24413 onLoad : function(ds, r, o)
24415 this.cursor = o.params ? o.params.start : 0;
24416 var d = this.getPageData(),
24421 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24422 this.field.dom.value = ap;
24423 this.first.setDisabled(ap == 1);
24424 this.prev.setDisabled(ap == 1);
24425 this.next.setDisabled(ap == ps);
24426 this.last.setDisabled(ap == ps);
24427 this.loading.enable();
24432 getPageData : function(){
24433 var total = this.ds.getTotalCount();
24436 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24437 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24442 onLoadError : function(){
24443 this.loading.enable();
24447 onPagingKeydown : function(e){
24448 var k = e.getKey();
24449 var d = this.getPageData();
24451 var v = this.field.dom.value, pageNum;
24452 if(!v || isNaN(pageNum = parseInt(v, 10))){
24453 this.field.dom.value = d.activePage;
24456 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24457 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24460 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))
24462 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24463 this.field.dom.value = pageNum;
24464 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24467 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24469 var v = this.field.dom.value, pageNum;
24470 var increment = (e.shiftKey) ? 10 : 1;
24471 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24474 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24475 this.field.dom.value = d.activePage;
24478 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24480 this.field.dom.value = parseInt(v, 10) + increment;
24481 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24482 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24489 beforeLoad : function(){
24491 this.loading.disable();
24496 onClick : function(which){
24505 ds.load({params:{start: 0, limit: this.pageSize}});
24508 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24511 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24514 var total = ds.getTotalCount();
24515 var extra = total % this.pageSize;
24516 var lastStart = extra ? (total - extra) : total-this.pageSize;
24517 ds.load({params:{start: lastStart, limit: this.pageSize}});
24520 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24526 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24527 * @param {Roo.data.Store} store The data store to unbind
24529 unbind : function(ds){
24530 ds.un("beforeload", this.beforeLoad, this);
24531 ds.un("load", this.onLoad, this);
24532 ds.un("loadexception", this.onLoadError, this);
24533 ds.un("remove", this.updateInfo, this);
24534 ds.un("add", this.updateInfo, this);
24535 this.ds = undefined;
24539 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24540 * @param {Roo.data.Store} store The data store to bind
24542 bind : function(ds){
24543 ds.on("beforeload", this.beforeLoad, this);
24544 ds.on("load", this.onLoad, this);
24545 ds.on("loadexception", this.onLoadError, this);
24546 ds.on("remove", this.updateInfo, this);
24547 ds.on("add", this.updateInfo, this);
24558 * @class Roo.bootstrap.MessageBar
24559 * @extends Roo.bootstrap.Component
24560 * Bootstrap MessageBar class
24561 * @cfg {String} html contents of the MessageBar
24562 * @cfg {String} weight (info | success | warning | danger) default info
24563 * @cfg {String} beforeClass insert the bar before the given class
24564 * @cfg {Boolean} closable (true | false) default false
24565 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24568 * Create a new Element
24569 * @param {Object} config The config object
24572 Roo.bootstrap.MessageBar = function(config){
24573 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24576 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24582 beforeClass: 'bootstrap-sticky-wrap',
24584 getAutoCreate : function(){
24588 cls: 'alert alert-dismissable alert-' + this.weight,
24593 html: this.html || ''
24599 cfg.cls += ' alert-messages-fixed';
24613 onRender : function(ct, position)
24615 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24618 var cfg = Roo.apply({}, this.getAutoCreate());
24622 cfg.cls += ' ' + this.cls;
24625 cfg.style = this.style;
24627 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24629 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24632 this.el.select('>button.close').on('click', this.hide, this);
24638 if (!this.rendered) {
24644 this.fireEvent('show', this);
24650 if (!this.rendered) {
24656 this.fireEvent('hide', this);
24659 update : function()
24661 // var e = this.el.dom.firstChild;
24663 // if(this.closable){
24664 // e = e.nextSibling;
24667 // e.data = this.html || '';
24669 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24685 * @class Roo.bootstrap.Graph
24686 * @extends Roo.bootstrap.Component
24687 * Bootstrap Graph class
24691 @cfg {String} graphtype bar | vbar | pie
24692 @cfg {number} g_x coodinator | centre x (pie)
24693 @cfg {number} g_y coodinator | centre y (pie)
24694 @cfg {number} g_r radius (pie)
24695 @cfg {number} g_height height of the chart (respected by all elements in the set)
24696 @cfg {number} g_width width of the chart (respected by all elements in the set)
24697 @cfg {Object} title The title of the chart
24700 -opts (object) options for the chart
24702 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24703 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24705 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.
24706 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24708 o stretch (boolean)
24710 -opts (object) options for the pie
24713 o startAngle (number)
24714 o endAngle (number)
24718 * Create a new Input
24719 * @param {Object} config The config object
24722 Roo.bootstrap.Graph = function(config){
24723 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24729 * The img click event for the img.
24730 * @param {Roo.EventObject} e
24736 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24747 //g_colors: this.colors,
24754 getAutoCreate : function(){
24765 onRender : function(ct,position){
24768 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24770 if (typeof(Raphael) == 'undefined') {
24771 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24775 this.raphael = Raphael(this.el.dom);
24777 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24778 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24779 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24780 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24782 r.text(160, 10, "Single Series Chart").attr(txtattr);
24783 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24784 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24785 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24787 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24788 r.barchart(330, 10, 300, 220, data1);
24789 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24790 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24793 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24794 // r.barchart(30, 30, 560, 250, xdata, {
24795 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24796 // axis : "0 0 1 1",
24797 // axisxlabels : xdata
24798 // //yvalues : cols,
24801 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24803 // this.load(null,xdata,{
24804 // axis : "0 0 1 1",
24805 // axisxlabels : xdata
24810 load : function(graphtype,xdata,opts)
24812 this.raphael.clear();
24814 graphtype = this.graphtype;
24819 var r = this.raphael,
24820 fin = function () {
24821 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24823 fout = function () {
24824 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24826 pfin = function() {
24827 this.sector.stop();
24828 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24831 this.label[0].stop();
24832 this.label[0].attr({ r: 7.5 });
24833 this.label[1].attr({ "font-weight": 800 });
24836 pfout = function() {
24837 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24840 this.label[0].animate({ r: 5 }, 500, "bounce");
24841 this.label[1].attr({ "font-weight": 400 });
24847 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24850 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24853 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24854 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24856 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24863 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24868 setTitle: function(o)
24873 initEvents: function() {
24876 this.el.on('click', this.onClick, this);
24880 onClick : function(e)
24882 Roo.log('img onclick');
24883 this.fireEvent('click', this, e);
24895 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24898 * @class Roo.bootstrap.dash.NumberBox
24899 * @extends Roo.bootstrap.Component
24900 * Bootstrap NumberBox class
24901 * @cfg {String} headline Box headline
24902 * @cfg {String} content Box content
24903 * @cfg {String} icon Box icon
24904 * @cfg {String} footer Footer text
24905 * @cfg {String} fhref Footer href
24908 * Create a new NumberBox
24909 * @param {Object} config The config object
24913 Roo.bootstrap.dash.NumberBox = function(config){
24914 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24918 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24927 getAutoCreate : function(){
24931 cls : 'small-box ',
24939 cls : 'roo-headline',
24940 html : this.headline
24944 cls : 'roo-content',
24945 html : this.content
24959 cls : 'ion ' + this.icon
24968 cls : 'small-box-footer',
24969 href : this.fhref || '#',
24973 cfg.cn.push(footer);
24980 onRender : function(ct,position){
24981 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24988 setHeadline: function (value)
24990 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24993 setFooter: function (value, href)
24995 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24998 this.el.select('a.small-box-footer',true).first().attr('href', href);
25003 setContent: function (value)
25005 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25008 initEvents: function()
25022 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25025 * @class Roo.bootstrap.dash.TabBox
25026 * @extends Roo.bootstrap.Component
25027 * Bootstrap TabBox class
25028 * @cfg {String} title Title of the TabBox
25029 * @cfg {String} icon Icon of the TabBox
25030 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25031 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25034 * Create a new TabBox
25035 * @param {Object} config The config object
25039 Roo.bootstrap.dash.TabBox = function(config){
25040 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25045 * When a pane is added
25046 * @param {Roo.bootstrap.dash.TabPane} pane
25050 * @event activatepane
25051 * When a pane is activated
25052 * @param {Roo.bootstrap.dash.TabPane} pane
25054 "activatepane" : true
25062 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25067 tabScrollable : false,
25069 getChildContainer : function()
25071 return this.el.select('.tab-content', true).first();
25074 getAutoCreate : function(){
25078 cls: 'pull-left header',
25086 cls: 'fa ' + this.icon
25092 cls: 'nav nav-tabs pull-right',
25098 if(this.tabScrollable){
25105 cls: 'nav nav-tabs pull-right',
25116 cls: 'nav-tabs-custom',
25121 cls: 'tab-content no-padding',
25129 initEvents : function()
25131 //Roo.log('add add pane handler');
25132 this.on('addpane', this.onAddPane, this);
25135 * Updates the box title
25136 * @param {String} html to set the title to.
25138 setTitle : function(value)
25140 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25142 onAddPane : function(pane)
25144 this.panes.push(pane);
25145 //Roo.log('addpane');
25147 // tabs are rendere left to right..
25148 if(!this.showtabs){
25152 var ctr = this.el.select('.nav-tabs', true).first();
25155 var existing = ctr.select('.nav-tab',true);
25156 var qty = existing.getCount();;
25159 var tab = ctr.createChild({
25161 cls : 'nav-tab' + (qty ? '' : ' active'),
25169 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25172 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25174 pane.el.addClass('active');
25179 onTabClick : function(ev,un,ob,pane)
25181 //Roo.log('tab - prev default');
25182 ev.preventDefault();
25185 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25186 pane.tab.addClass('active');
25187 //Roo.log(pane.title);
25188 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25189 // technically we should have a deactivate event.. but maybe add later.
25190 // and it should not de-activate the selected tab...
25191 this.fireEvent('activatepane', pane);
25192 pane.el.addClass('active');
25193 pane.fireEvent('activate');
25198 getActivePane : function()
25201 Roo.each(this.panes, function(p) {
25202 if(p.el.hasClass('active')){
25223 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25225 * @class Roo.bootstrap.TabPane
25226 * @extends Roo.bootstrap.Component
25227 * Bootstrap TabPane class
25228 * @cfg {Boolean} active (false | true) Default false
25229 * @cfg {String} title title of panel
25233 * Create a new TabPane
25234 * @param {Object} config The config object
25237 Roo.bootstrap.dash.TabPane = function(config){
25238 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25244 * When a pane is activated
25245 * @param {Roo.bootstrap.dash.TabPane} pane
25252 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25257 // the tabBox that this is attached to.
25260 getAutoCreate : function()
25268 cfg.cls += ' active';
25273 initEvents : function()
25275 //Roo.log('trigger add pane handler');
25276 this.parent().fireEvent('addpane', this)
25280 * Updates the tab title
25281 * @param {String} html to set the title to.
25283 setTitle: function(str)
25289 this.tab.select('a', true).first().dom.innerHTML = str;
25306 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25309 * @class Roo.bootstrap.menu.Menu
25310 * @extends Roo.bootstrap.Component
25311 * Bootstrap Menu class - container for Menu
25312 * @cfg {String} html Text of the menu
25313 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25314 * @cfg {String} icon Font awesome icon
25315 * @cfg {String} pos Menu align to (top | bottom) default bottom
25319 * Create a new Menu
25320 * @param {Object} config The config object
25324 Roo.bootstrap.menu.Menu = function(config){
25325 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25329 * @event beforeshow
25330 * Fires before this menu is displayed
25331 * @param {Roo.bootstrap.menu.Menu} this
25335 * @event beforehide
25336 * Fires before this menu is hidden
25337 * @param {Roo.bootstrap.menu.Menu} this
25342 * Fires after this menu is displayed
25343 * @param {Roo.bootstrap.menu.Menu} this
25348 * Fires after this menu is hidden
25349 * @param {Roo.bootstrap.menu.Menu} this
25354 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25355 * @param {Roo.bootstrap.menu.Menu} this
25356 * @param {Roo.EventObject} e
25363 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25367 weight : 'default',
25372 getChildContainer : function() {
25373 if(this.isSubMenu){
25377 return this.el.select('ul.dropdown-menu', true).first();
25380 getAutoCreate : function()
25385 cls : 'roo-menu-text',
25393 cls : 'fa ' + this.icon
25404 cls : 'dropdown-button btn btn-' + this.weight,
25409 cls : 'dropdown-toggle btn btn-' + this.weight,
25419 cls : 'dropdown-menu'
25425 if(this.pos == 'top'){
25426 cfg.cls += ' dropup';
25429 if(this.isSubMenu){
25432 cls : 'dropdown-menu'
25439 onRender : function(ct, position)
25441 this.isSubMenu = ct.hasClass('dropdown-submenu');
25443 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25446 initEvents : function()
25448 if(this.isSubMenu){
25452 this.hidden = true;
25454 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25455 this.triggerEl.on('click', this.onTriggerPress, this);
25457 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25458 this.buttonEl.on('click', this.onClick, this);
25464 if(this.isSubMenu){
25468 return this.el.select('ul.dropdown-menu', true).first();
25471 onClick : function(e)
25473 this.fireEvent("click", this, e);
25476 onTriggerPress : function(e)
25478 if (this.isVisible()) {
25485 isVisible : function(){
25486 return !this.hidden;
25491 this.fireEvent("beforeshow", this);
25493 this.hidden = false;
25494 this.el.addClass('open');
25496 Roo.get(document).on("mouseup", this.onMouseUp, this);
25498 this.fireEvent("show", this);
25505 this.fireEvent("beforehide", this);
25507 this.hidden = true;
25508 this.el.removeClass('open');
25510 Roo.get(document).un("mouseup", this.onMouseUp);
25512 this.fireEvent("hide", this);
25515 onMouseUp : function()
25529 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25532 * @class Roo.bootstrap.menu.Item
25533 * @extends Roo.bootstrap.Component
25534 * Bootstrap MenuItem class
25535 * @cfg {Boolean} submenu (true | false) default false
25536 * @cfg {String} html text of the item
25537 * @cfg {String} href the link
25538 * @cfg {Boolean} disable (true | false) default false
25539 * @cfg {Boolean} preventDefault (true | false) default true
25540 * @cfg {String} icon Font awesome icon
25541 * @cfg {String} pos Submenu align to (left | right) default right
25545 * Create a new Item
25546 * @param {Object} config The config object
25550 Roo.bootstrap.menu.Item = function(config){
25551 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25555 * Fires when the mouse is hovering over this menu
25556 * @param {Roo.bootstrap.menu.Item} this
25557 * @param {Roo.EventObject} e
25562 * Fires when the mouse exits this menu
25563 * @param {Roo.bootstrap.menu.Item} this
25564 * @param {Roo.EventObject} e
25570 * The raw click event for the entire grid.
25571 * @param {Roo.EventObject} e
25577 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25582 preventDefault: true,
25587 getAutoCreate : function()
25592 cls : 'roo-menu-item-text',
25600 cls : 'fa ' + this.icon
25609 href : this.href || '#',
25616 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25620 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25622 if(this.pos == 'left'){
25623 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25630 initEvents : function()
25632 this.el.on('mouseover', this.onMouseOver, this);
25633 this.el.on('mouseout', this.onMouseOut, this);
25635 this.el.select('a', true).first().on('click', this.onClick, this);
25639 onClick : function(e)
25641 if(this.preventDefault){
25642 e.preventDefault();
25645 this.fireEvent("click", this, e);
25648 onMouseOver : function(e)
25650 if(this.submenu && this.pos == 'left'){
25651 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25654 this.fireEvent("mouseover", this, e);
25657 onMouseOut : function(e)
25659 this.fireEvent("mouseout", this, e);
25671 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25674 * @class Roo.bootstrap.menu.Separator
25675 * @extends Roo.bootstrap.Component
25676 * Bootstrap Separator class
25679 * Create a new Separator
25680 * @param {Object} config The config object
25684 Roo.bootstrap.menu.Separator = function(config){
25685 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25688 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25690 getAutoCreate : function(){
25711 * @class Roo.bootstrap.Tooltip
25712 * Bootstrap Tooltip class
25713 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25714 * to determine which dom element triggers the tooltip.
25716 * It needs to add support for additional attributes like tooltip-position
25719 * Create a new Toolti
25720 * @param {Object} config The config object
25723 Roo.bootstrap.Tooltip = function(config){
25724 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25726 this.alignment = Roo.bootstrap.Tooltip.alignment;
25728 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25729 this.alignment = config.alignment;
25734 Roo.apply(Roo.bootstrap.Tooltip, {
25736 * @function init initialize tooltip monitoring.
25740 currentTip : false,
25741 currentRegion : false,
25747 Roo.get(document).on('mouseover', this.enter ,this);
25748 Roo.get(document).on('mouseout', this.leave, this);
25751 this.currentTip = new Roo.bootstrap.Tooltip();
25754 enter : function(ev)
25756 var dom = ev.getTarget();
25758 //Roo.log(['enter',dom]);
25759 var el = Roo.fly(dom);
25760 if (this.currentEl) {
25762 //Roo.log(this.currentEl);
25763 //Roo.log(this.currentEl.contains(dom));
25764 if (this.currentEl == el) {
25767 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25773 if (this.currentTip.el) {
25774 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25778 if(!el || el.dom == document){
25784 // you can not look for children, as if el is the body.. then everythign is the child..
25785 if (!el.attr('tooltip')) { //
25786 if (!el.select("[tooltip]").elements.length) {
25789 // is the mouse over this child...?
25790 bindEl = el.select("[tooltip]").first();
25791 var xy = ev.getXY();
25792 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25793 //Roo.log("not in region.");
25796 //Roo.log("child element over..");
25799 this.currentEl = bindEl;
25800 this.currentTip.bind(bindEl);
25801 this.currentRegion = Roo.lib.Region.getRegion(dom);
25802 this.currentTip.enter();
25805 leave : function(ev)
25807 var dom = ev.getTarget();
25808 //Roo.log(['leave',dom]);
25809 if (!this.currentEl) {
25814 if (dom != this.currentEl.dom) {
25817 var xy = ev.getXY();
25818 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25821 // only activate leave if mouse cursor is outside... bounding box..
25826 if (this.currentTip) {
25827 this.currentTip.leave();
25829 //Roo.log('clear currentEl');
25830 this.currentEl = false;
25835 'left' : ['r-l', [-2,0], 'right'],
25836 'right' : ['l-r', [2,0], 'left'],
25837 'bottom' : ['t-b', [0,2], 'top'],
25838 'top' : [ 'b-t', [0,-2], 'bottom']
25844 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25849 delay : null, // can be { show : 300 , hide: 500}
25853 hoverState : null, //???
25855 placement : 'bottom',
25859 getAutoCreate : function(){
25866 cls : 'tooltip-arrow'
25869 cls : 'tooltip-inner'
25876 bind : function(el)
25882 enter : function () {
25884 if (this.timeout != null) {
25885 clearTimeout(this.timeout);
25888 this.hoverState = 'in';
25889 //Roo.log("enter - show");
25890 if (!this.delay || !this.delay.show) {
25895 this.timeout = setTimeout(function () {
25896 if (_t.hoverState == 'in') {
25899 }, this.delay.show);
25903 clearTimeout(this.timeout);
25905 this.hoverState = 'out';
25906 if (!this.delay || !this.delay.hide) {
25912 this.timeout = setTimeout(function () {
25913 //Roo.log("leave - timeout");
25915 if (_t.hoverState == 'out') {
25917 Roo.bootstrap.Tooltip.currentEl = false;
25922 show : function (msg)
25925 this.render(document.body);
25928 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25930 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25932 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25934 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25936 var placement = typeof this.placement == 'function' ?
25937 this.placement.call(this, this.el, on_el) :
25940 var autoToken = /\s?auto?\s?/i;
25941 var autoPlace = autoToken.test(placement);
25943 placement = placement.replace(autoToken, '') || 'top';
25947 //this.el.setXY([0,0]);
25949 //this.el.dom.style.display='block';
25951 //this.el.appendTo(on_el);
25953 var p = this.getPosition();
25954 var box = this.el.getBox();
25960 var align = this.alignment[placement];
25962 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25964 if(placement == 'top' || placement == 'bottom'){
25966 placement = 'right';
25969 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25970 placement = 'left';
25973 var scroll = Roo.select('body', true).first().getScroll();
25975 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25981 this.el.alignTo(this.bindEl, align[0],align[1]);
25982 //var arrow = this.el.select('.arrow',true).first();
25983 //arrow.set(align[2],
25985 this.el.addClass(placement);
25987 this.el.addClass('in fade');
25989 this.hoverState = null;
25991 if (this.el.hasClass('fade')) {
26002 //this.el.setXY([0,0]);
26003 this.el.removeClass('in');
26019 * @class Roo.bootstrap.LocationPicker
26020 * @extends Roo.bootstrap.Component
26021 * Bootstrap LocationPicker class
26022 * @cfg {Number} latitude Position when init default 0
26023 * @cfg {Number} longitude Position when init default 0
26024 * @cfg {Number} zoom default 15
26025 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26026 * @cfg {Boolean} mapTypeControl default false
26027 * @cfg {Boolean} disableDoubleClickZoom default false
26028 * @cfg {Boolean} scrollwheel default true
26029 * @cfg {Boolean} streetViewControl default false
26030 * @cfg {Number} radius default 0
26031 * @cfg {String} locationName
26032 * @cfg {Boolean} draggable default true
26033 * @cfg {Boolean} enableAutocomplete default false
26034 * @cfg {Boolean} enableReverseGeocode default true
26035 * @cfg {String} markerTitle
26038 * Create a new LocationPicker
26039 * @param {Object} config The config object
26043 Roo.bootstrap.LocationPicker = function(config){
26045 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26050 * Fires when the picker initialized.
26051 * @param {Roo.bootstrap.LocationPicker} this
26052 * @param {Google Location} location
26056 * @event positionchanged
26057 * Fires when the picker position changed.
26058 * @param {Roo.bootstrap.LocationPicker} this
26059 * @param {Google Location} location
26061 positionchanged : true,
26064 * Fires when the map resize.
26065 * @param {Roo.bootstrap.LocationPicker} this
26070 * Fires when the map show.
26071 * @param {Roo.bootstrap.LocationPicker} this
26076 * Fires when the map hide.
26077 * @param {Roo.bootstrap.LocationPicker} this
26082 * Fires when click the map.
26083 * @param {Roo.bootstrap.LocationPicker} this
26084 * @param {Map event} e
26088 * @event mapRightClick
26089 * Fires when right click the map.
26090 * @param {Roo.bootstrap.LocationPicker} this
26091 * @param {Map event} e
26093 mapRightClick : true,
26095 * @event markerClick
26096 * Fires when click the marker.
26097 * @param {Roo.bootstrap.LocationPicker} this
26098 * @param {Map event} e
26100 markerClick : true,
26102 * @event markerRightClick
26103 * Fires when right click the marker.
26104 * @param {Roo.bootstrap.LocationPicker} this
26105 * @param {Map event} e
26107 markerRightClick : true,
26109 * @event OverlayViewDraw
26110 * Fires when OverlayView Draw
26111 * @param {Roo.bootstrap.LocationPicker} this
26113 OverlayViewDraw : true,
26115 * @event OverlayViewOnAdd
26116 * Fires when OverlayView Draw
26117 * @param {Roo.bootstrap.LocationPicker} this
26119 OverlayViewOnAdd : true,
26121 * @event OverlayViewOnRemove
26122 * Fires when OverlayView Draw
26123 * @param {Roo.bootstrap.LocationPicker} this
26125 OverlayViewOnRemove : true,
26127 * @event OverlayViewShow
26128 * Fires when OverlayView Draw
26129 * @param {Roo.bootstrap.LocationPicker} this
26130 * @param {Pixel} cpx
26132 OverlayViewShow : true,
26134 * @event OverlayViewHide
26135 * Fires when OverlayView Draw
26136 * @param {Roo.bootstrap.LocationPicker} this
26138 OverlayViewHide : true,
26140 * @event loadexception
26141 * Fires when load google lib failed.
26142 * @param {Roo.bootstrap.LocationPicker} this
26144 loadexception : true
26149 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26151 gMapContext: false,
26157 mapTypeControl: false,
26158 disableDoubleClickZoom: false,
26160 streetViewControl: false,
26164 enableAutocomplete: false,
26165 enableReverseGeocode: true,
26168 getAutoCreate: function()
26173 cls: 'roo-location-picker'
26179 initEvents: function(ct, position)
26181 if(!this.el.getWidth() || this.isApplied()){
26185 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26190 initial: function()
26192 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26193 this.fireEvent('loadexception', this);
26197 if(!this.mapTypeId){
26198 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26201 this.gMapContext = this.GMapContext();
26203 this.initOverlayView();
26205 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26209 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26210 _this.setPosition(_this.gMapContext.marker.position);
26213 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26214 _this.fireEvent('mapClick', this, event);
26218 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26219 _this.fireEvent('mapRightClick', this, event);
26223 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26224 _this.fireEvent('markerClick', this, event);
26228 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26229 _this.fireEvent('markerRightClick', this, event);
26233 this.setPosition(this.gMapContext.location);
26235 this.fireEvent('initial', this, this.gMapContext.location);
26238 initOverlayView: function()
26242 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26246 _this.fireEvent('OverlayViewDraw', _this);
26251 _this.fireEvent('OverlayViewOnAdd', _this);
26254 onRemove: function()
26256 _this.fireEvent('OverlayViewOnRemove', _this);
26259 show: function(cpx)
26261 _this.fireEvent('OverlayViewShow', _this, cpx);
26266 _this.fireEvent('OverlayViewHide', _this);
26272 fromLatLngToContainerPixel: function(event)
26274 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26277 isApplied: function()
26279 return this.getGmapContext() == false ? false : true;
26282 getGmapContext: function()
26284 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26287 GMapContext: function()
26289 var position = new google.maps.LatLng(this.latitude, this.longitude);
26291 var _map = new google.maps.Map(this.el.dom, {
26294 mapTypeId: this.mapTypeId,
26295 mapTypeControl: this.mapTypeControl,
26296 disableDoubleClickZoom: this.disableDoubleClickZoom,
26297 scrollwheel: this.scrollwheel,
26298 streetViewControl: this.streetViewControl,
26299 locationName: this.locationName,
26300 draggable: this.draggable,
26301 enableAutocomplete: this.enableAutocomplete,
26302 enableReverseGeocode: this.enableReverseGeocode
26305 var _marker = new google.maps.Marker({
26306 position: position,
26308 title: this.markerTitle,
26309 draggable: this.draggable
26316 location: position,
26317 radius: this.radius,
26318 locationName: this.locationName,
26319 addressComponents: {
26320 formatted_address: null,
26321 addressLine1: null,
26322 addressLine2: null,
26324 streetNumber: null,
26328 stateOrProvince: null
26331 domContainer: this.el.dom,
26332 geodecoder: new google.maps.Geocoder()
26336 drawCircle: function(center, radius, options)
26338 if (this.gMapContext.circle != null) {
26339 this.gMapContext.circle.setMap(null);
26343 options = Roo.apply({}, options, {
26344 strokeColor: "#0000FF",
26345 strokeOpacity: .35,
26347 fillColor: "#0000FF",
26351 options.map = this.gMapContext.map;
26352 options.radius = radius;
26353 options.center = center;
26354 this.gMapContext.circle = new google.maps.Circle(options);
26355 return this.gMapContext.circle;
26361 setPosition: function(location)
26363 this.gMapContext.location = location;
26364 this.gMapContext.marker.setPosition(location);
26365 this.gMapContext.map.panTo(location);
26366 this.drawCircle(location, this.gMapContext.radius, {});
26370 if (this.gMapContext.settings.enableReverseGeocode) {
26371 this.gMapContext.geodecoder.geocode({
26372 latLng: this.gMapContext.location
26373 }, function(results, status) {
26375 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26376 _this.gMapContext.locationName = results[0].formatted_address;
26377 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26379 _this.fireEvent('positionchanged', this, location);
26386 this.fireEvent('positionchanged', this, location);
26391 google.maps.event.trigger(this.gMapContext.map, "resize");
26393 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26395 this.fireEvent('resize', this);
26398 setPositionByLatLng: function(latitude, longitude)
26400 this.setPosition(new google.maps.LatLng(latitude, longitude));
26403 getCurrentPosition: function()
26406 latitude: this.gMapContext.location.lat(),
26407 longitude: this.gMapContext.location.lng()
26411 getAddressName: function()
26413 return this.gMapContext.locationName;
26416 getAddressComponents: function()
26418 return this.gMapContext.addressComponents;
26421 address_component_from_google_geocode: function(address_components)
26425 for (var i = 0; i < address_components.length; i++) {
26426 var component = address_components[i];
26427 if (component.types.indexOf("postal_code") >= 0) {
26428 result.postalCode = component.short_name;
26429 } else if (component.types.indexOf("street_number") >= 0) {
26430 result.streetNumber = component.short_name;
26431 } else if (component.types.indexOf("route") >= 0) {
26432 result.streetName = component.short_name;
26433 } else if (component.types.indexOf("neighborhood") >= 0) {
26434 result.city = component.short_name;
26435 } else if (component.types.indexOf("locality") >= 0) {
26436 result.city = component.short_name;
26437 } else if (component.types.indexOf("sublocality") >= 0) {
26438 result.district = component.short_name;
26439 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26440 result.stateOrProvince = component.short_name;
26441 } else if (component.types.indexOf("country") >= 0) {
26442 result.country = component.short_name;
26446 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26447 result.addressLine2 = "";
26451 setZoomLevel: function(zoom)
26453 this.gMapContext.map.setZoom(zoom);
26466 this.fireEvent('show', this);
26477 this.fireEvent('hide', this);
26482 Roo.apply(Roo.bootstrap.LocationPicker, {
26484 OverlayView : function(map, options)
26486 options = options || {};
26500 * @class Roo.bootstrap.Alert
26501 * @extends Roo.bootstrap.Component
26502 * Bootstrap Alert class
26503 * @cfg {String} title The title of alert
26504 * @cfg {String} html The content of alert
26505 * @cfg {String} weight ( success | info | warning | danger )
26506 * @cfg {String} faicon font-awesomeicon
26509 * Create a new alert
26510 * @param {Object} config The config object
26514 Roo.bootstrap.Alert = function(config){
26515 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26519 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26526 getAutoCreate : function()
26535 cls : 'roo-alert-icon'
26540 cls : 'roo-alert-title',
26545 cls : 'roo-alert-text',
26552 cfg.cn[0].cls += ' fa ' + this.faicon;
26556 cfg.cls += ' alert-' + this.weight;
26562 initEvents: function()
26564 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26567 setTitle : function(str)
26569 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26572 setText : function(str)
26574 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26577 setWeight : function(weight)
26580 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26583 this.weight = weight;
26585 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26588 setIcon : function(icon)
26591 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26594 this.faicon = icon;
26596 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26617 * @class Roo.bootstrap.UploadCropbox
26618 * @extends Roo.bootstrap.Component
26619 * Bootstrap UploadCropbox class
26620 * @cfg {String} emptyText show when image has been loaded
26621 * @cfg {String} rotateNotify show when image too small to rotate
26622 * @cfg {Number} errorTimeout default 3000
26623 * @cfg {Number} minWidth default 300
26624 * @cfg {Number} minHeight default 300
26625 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26626 * @cfg {Boolean} isDocument (true|false) default false
26627 * @cfg {String} url action url
26628 * @cfg {String} paramName default 'imageUpload'
26629 * @cfg {String} method default POST
26630 * @cfg {Boolean} loadMask (true|false) default true
26631 * @cfg {Boolean} loadingText default 'Loading...'
26634 * Create a new UploadCropbox
26635 * @param {Object} config The config object
26638 Roo.bootstrap.UploadCropbox = function(config){
26639 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26643 * @event beforeselectfile
26644 * Fire before select file
26645 * @param {Roo.bootstrap.UploadCropbox} this
26647 "beforeselectfile" : true,
26650 * Fire after initEvent
26651 * @param {Roo.bootstrap.UploadCropbox} this
26656 * Fire after initEvent
26657 * @param {Roo.bootstrap.UploadCropbox} this
26658 * @param {String} data
26663 * Fire when preparing the file data
26664 * @param {Roo.bootstrap.UploadCropbox} this
26665 * @param {Object} file
26670 * Fire when get exception
26671 * @param {Roo.bootstrap.UploadCropbox} this
26672 * @param {XMLHttpRequest} xhr
26674 "exception" : true,
26676 * @event beforeloadcanvas
26677 * Fire before load the canvas
26678 * @param {Roo.bootstrap.UploadCropbox} this
26679 * @param {String} src
26681 "beforeloadcanvas" : true,
26684 * Fire when trash image
26685 * @param {Roo.bootstrap.UploadCropbox} this
26690 * Fire when download the image
26691 * @param {Roo.bootstrap.UploadCropbox} this
26695 * @event footerbuttonclick
26696 * Fire when footerbuttonclick
26697 * @param {Roo.bootstrap.UploadCropbox} this
26698 * @param {String} type
26700 "footerbuttonclick" : true,
26704 * @param {Roo.bootstrap.UploadCropbox} this
26709 * Fire when rotate the image
26710 * @param {Roo.bootstrap.UploadCropbox} this
26711 * @param {String} pos
26716 * Fire when inspect the file
26717 * @param {Roo.bootstrap.UploadCropbox} this
26718 * @param {Object} file
26723 * Fire when xhr upload the file
26724 * @param {Roo.bootstrap.UploadCropbox} this
26725 * @param {Object} data
26730 * Fire when arrange the file data
26731 * @param {Roo.bootstrap.UploadCropbox} this
26732 * @param {Object} formData
26737 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26740 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26742 emptyText : 'Click to upload image',
26743 rotateNotify : 'Image is too small to rotate',
26744 errorTimeout : 3000,
26758 cropType : 'image/jpeg',
26760 canvasLoaded : false,
26761 isDocument : false,
26763 paramName : 'imageUpload',
26765 loadingText : 'Loading...',
26768 getAutoCreate : function()
26772 cls : 'roo-upload-cropbox',
26776 cls : 'roo-upload-cropbox-selector',
26781 cls : 'roo-upload-cropbox-body',
26782 style : 'cursor:pointer',
26786 cls : 'roo-upload-cropbox-preview'
26790 cls : 'roo-upload-cropbox-thumb'
26794 cls : 'roo-upload-cropbox-empty-notify',
26795 html : this.emptyText
26799 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26800 html : this.rotateNotify
26806 cls : 'roo-upload-cropbox-footer',
26809 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26819 onRender : function(ct, position)
26821 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26823 if (this.buttons.length) {
26825 Roo.each(this.buttons, function(bb) {
26827 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26829 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26835 this.maskEl = this.el;
26839 initEvents : function()
26841 this.urlAPI = (window.createObjectURL && window) ||
26842 (window.URL && URL.revokeObjectURL && URL) ||
26843 (window.webkitURL && webkitURL);
26845 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26846 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26848 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26849 this.selectorEl.hide();
26851 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26852 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26854 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26855 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26856 this.thumbEl.hide();
26858 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26859 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26861 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26862 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26863 this.errorEl.hide();
26865 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26866 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26867 this.footerEl.hide();
26869 this.setThumbBoxSize();
26875 this.fireEvent('initial', this);
26882 window.addEventListener("resize", function() { _this.resize(); } );
26884 this.bodyEl.on('click', this.beforeSelectFile, this);
26887 this.bodyEl.on('touchstart', this.onTouchStart, this);
26888 this.bodyEl.on('touchmove', this.onTouchMove, this);
26889 this.bodyEl.on('touchend', this.onTouchEnd, this);
26893 this.bodyEl.on('mousedown', this.onMouseDown, this);
26894 this.bodyEl.on('mousemove', this.onMouseMove, this);
26895 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26896 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26897 Roo.get(document).on('mouseup', this.onMouseUp, this);
26900 this.selectorEl.on('change', this.onFileSelected, this);
26906 this.baseScale = 1;
26908 this.baseRotate = 1;
26909 this.dragable = false;
26910 this.pinching = false;
26913 this.cropData = false;
26914 this.notifyEl.dom.innerHTML = this.emptyText;
26916 this.selectorEl.dom.value = '';
26920 resize : function()
26922 if(this.fireEvent('resize', this) != false){
26923 this.setThumbBoxPosition();
26924 this.setCanvasPosition();
26928 onFooterButtonClick : function(e, el, o, type)
26931 case 'rotate-left' :
26932 this.onRotateLeft(e);
26934 case 'rotate-right' :
26935 this.onRotateRight(e);
26938 this.beforeSelectFile(e);
26953 this.fireEvent('footerbuttonclick', this, type);
26956 beforeSelectFile : function(e)
26958 e.preventDefault();
26960 if(this.fireEvent('beforeselectfile', this) != false){
26961 this.selectorEl.dom.click();
26965 onFileSelected : function(e)
26967 e.preventDefault();
26969 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26973 var file = this.selectorEl.dom.files[0];
26975 if(this.fireEvent('inspect', this, file) != false){
26976 this.prepare(file);
26981 trash : function(e)
26983 this.fireEvent('trash', this);
26986 download : function(e)
26988 this.fireEvent('download', this);
26991 loadCanvas : function(src)
26993 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26997 this.imageEl = document.createElement('img');
27001 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27003 this.imageEl.src = src;
27007 onLoadCanvas : function()
27009 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27010 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27012 this.bodyEl.un('click', this.beforeSelectFile, this);
27014 this.notifyEl.hide();
27015 this.thumbEl.show();
27016 this.footerEl.show();
27018 this.baseRotateLevel();
27020 if(this.isDocument){
27021 this.setThumbBoxSize();
27024 this.setThumbBoxPosition();
27026 this.baseScaleLevel();
27032 this.canvasLoaded = true;
27035 this.maskEl.unmask();
27040 setCanvasPosition : function()
27042 if(!this.canvasEl){
27046 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27047 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27049 this.previewEl.setLeft(pw);
27050 this.previewEl.setTop(ph);
27054 onMouseDown : function(e)
27058 this.dragable = true;
27059 this.pinching = false;
27061 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27062 this.dragable = false;
27066 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27067 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27071 onMouseMove : function(e)
27075 if(!this.canvasLoaded){
27079 if (!this.dragable){
27083 var minX = Math.ceil(this.thumbEl.getLeft(true));
27084 var minY = Math.ceil(this.thumbEl.getTop(true));
27086 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27087 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27089 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27090 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27092 x = x - this.mouseX;
27093 y = y - this.mouseY;
27095 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27096 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27098 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27099 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27101 this.previewEl.setLeft(bgX);
27102 this.previewEl.setTop(bgY);
27104 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27105 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27108 onMouseUp : function(e)
27112 this.dragable = false;
27115 onMouseWheel : function(e)
27119 this.startScale = this.scale;
27121 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27123 if(!this.zoomable()){
27124 this.scale = this.startScale;
27133 zoomable : function()
27135 var minScale = this.thumbEl.getWidth() / this.minWidth;
27137 if(this.minWidth < this.minHeight){
27138 minScale = this.thumbEl.getHeight() / this.minHeight;
27141 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27142 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27146 (this.rotate == 0 || this.rotate == 180) &&
27148 width > this.imageEl.OriginWidth ||
27149 height > this.imageEl.OriginHeight ||
27150 (width < this.minWidth && height < this.minHeight)
27158 (this.rotate == 90 || this.rotate == 270) &&
27160 width > this.imageEl.OriginWidth ||
27161 height > this.imageEl.OriginHeight ||
27162 (width < this.minHeight && height < this.minWidth)
27169 !this.isDocument &&
27170 (this.rotate == 0 || this.rotate == 180) &&
27172 width < this.minWidth ||
27173 width > this.imageEl.OriginWidth ||
27174 height < this.minHeight ||
27175 height > this.imageEl.OriginHeight
27182 !this.isDocument &&
27183 (this.rotate == 90 || this.rotate == 270) &&
27185 width < this.minHeight ||
27186 width > this.imageEl.OriginWidth ||
27187 height < this.minWidth ||
27188 height > this.imageEl.OriginHeight
27198 onRotateLeft : function(e)
27200 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27202 var minScale = this.thumbEl.getWidth() / this.minWidth;
27204 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27205 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27207 this.startScale = this.scale;
27209 while (this.getScaleLevel() < minScale){
27211 this.scale = this.scale + 1;
27213 if(!this.zoomable()){
27218 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27219 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27224 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27231 this.scale = this.startScale;
27233 this.onRotateFail();
27238 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27240 if(this.isDocument){
27241 this.setThumbBoxSize();
27242 this.setThumbBoxPosition();
27243 this.setCanvasPosition();
27248 this.fireEvent('rotate', this, 'left');
27252 onRotateRight : function(e)
27254 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27256 var minScale = this.thumbEl.getWidth() / this.minWidth;
27258 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27259 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27261 this.startScale = this.scale;
27263 while (this.getScaleLevel() < minScale){
27265 this.scale = this.scale + 1;
27267 if(!this.zoomable()){
27272 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27273 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27278 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27285 this.scale = this.startScale;
27287 this.onRotateFail();
27292 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27294 if(this.isDocument){
27295 this.setThumbBoxSize();
27296 this.setThumbBoxPosition();
27297 this.setCanvasPosition();
27302 this.fireEvent('rotate', this, 'right');
27305 onRotateFail : function()
27307 this.errorEl.show(true);
27311 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27316 this.previewEl.dom.innerHTML = '';
27318 var canvasEl = document.createElement("canvas");
27320 var contextEl = canvasEl.getContext("2d");
27322 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27323 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27324 var center = this.imageEl.OriginWidth / 2;
27326 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27327 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27328 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27329 center = this.imageEl.OriginHeight / 2;
27332 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27334 contextEl.translate(center, center);
27335 contextEl.rotate(this.rotate * Math.PI / 180);
27337 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27339 this.canvasEl = document.createElement("canvas");
27341 this.contextEl = this.canvasEl.getContext("2d");
27343 switch (this.rotate) {
27346 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27347 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27349 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27354 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27355 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27357 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27358 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);
27362 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27367 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27368 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27370 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27371 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);
27375 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);
27380 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27381 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27383 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27384 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27388 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);
27395 this.previewEl.appendChild(this.canvasEl);
27397 this.setCanvasPosition();
27402 if(!this.canvasLoaded){
27406 var imageCanvas = document.createElement("canvas");
27408 var imageContext = imageCanvas.getContext("2d");
27410 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27411 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27413 var center = imageCanvas.width / 2;
27415 imageContext.translate(center, center);
27417 imageContext.rotate(this.rotate * Math.PI / 180);
27419 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27421 var canvas = document.createElement("canvas");
27423 var context = canvas.getContext("2d");
27425 canvas.width = this.minWidth;
27426 canvas.height = this.minHeight;
27428 switch (this.rotate) {
27431 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27432 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27434 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27435 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27437 var targetWidth = this.minWidth - 2 * x;
27438 var targetHeight = this.minHeight - 2 * y;
27442 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27443 scale = targetWidth / width;
27446 if(x > 0 && y == 0){
27447 scale = targetHeight / height;
27450 if(x > 0 && y > 0){
27451 scale = targetWidth / width;
27453 if(width < height){
27454 scale = targetHeight / height;
27458 context.scale(scale, scale);
27460 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27461 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27463 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27464 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27466 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27471 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27472 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27474 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27475 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27477 var targetWidth = this.minWidth - 2 * x;
27478 var targetHeight = this.minHeight - 2 * y;
27482 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27483 scale = targetWidth / width;
27486 if(x > 0 && y == 0){
27487 scale = targetHeight / height;
27490 if(x > 0 && y > 0){
27491 scale = targetWidth / width;
27493 if(width < height){
27494 scale = targetHeight / height;
27498 context.scale(scale, scale);
27500 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27501 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27503 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27504 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27506 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27508 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27513 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27514 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27516 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27517 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27519 var targetWidth = this.minWidth - 2 * x;
27520 var targetHeight = this.minHeight - 2 * y;
27524 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27525 scale = targetWidth / width;
27528 if(x > 0 && y == 0){
27529 scale = targetHeight / height;
27532 if(x > 0 && y > 0){
27533 scale = targetWidth / width;
27535 if(width < height){
27536 scale = targetHeight / height;
27540 context.scale(scale, scale);
27542 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27543 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27545 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27546 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27548 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27549 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27551 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27556 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27557 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27559 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27560 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27562 var targetWidth = this.minWidth - 2 * x;
27563 var targetHeight = this.minHeight - 2 * y;
27567 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27568 scale = targetWidth / width;
27571 if(x > 0 && y == 0){
27572 scale = targetHeight / height;
27575 if(x > 0 && y > 0){
27576 scale = targetWidth / width;
27578 if(width < height){
27579 scale = targetHeight / height;
27583 context.scale(scale, scale);
27585 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27586 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27588 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27589 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27591 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27593 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27600 this.cropData = canvas.toDataURL(this.cropType);
27602 if(this.fireEvent('crop', this, this.cropData) !== false){
27603 this.process(this.file, this.cropData);
27610 setThumbBoxSize : function()
27614 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27615 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27616 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27618 this.minWidth = width;
27619 this.minHeight = height;
27621 if(this.rotate == 90 || this.rotate == 270){
27622 this.minWidth = height;
27623 this.minHeight = width;
27628 width = Math.ceil(this.minWidth * height / this.minHeight);
27630 if(this.minWidth > this.minHeight){
27632 height = Math.ceil(this.minHeight * width / this.minWidth);
27635 this.thumbEl.setStyle({
27636 width : width + 'px',
27637 height : height + 'px'
27644 setThumbBoxPosition : function()
27646 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27647 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27649 this.thumbEl.setLeft(x);
27650 this.thumbEl.setTop(y);
27654 baseRotateLevel : function()
27656 this.baseRotate = 1;
27659 typeof(this.exif) != 'undefined' &&
27660 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27661 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27663 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27666 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27670 baseScaleLevel : function()
27674 if(this.isDocument){
27676 if(this.baseRotate == 6 || this.baseRotate == 8){
27678 height = this.thumbEl.getHeight();
27679 this.baseScale = height / this.imageEl.OriginWidth;
27681 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27682 width = this.thumbEl.getWidth();
27683 this.baseScale = width / this.imageEl.OriginHeight;
27689 height = this.thumbEl.getHeight();
27690 this.baseScale = height / this.imageEl.OriginHeight;
27692 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27693 width = this.thumbEl.getWidth();
27694 this.baseScale = width / this.imageEl.OriginWidth;
27700 if(this.baseRotate == 6 || this.baseRotate == 8){
27702 width = this.thumbEl.getHeight();
27703 this.baseScale = width / this.imageEl.OriginHeight;
27705 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27706 height = this.thumbEl.getWidth();
27707 this.baseScale = height / this.imageEl.OriginHeight;
27710 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27711 height = this.thumbEl.getWidth();
27712 this.baseScale = height / this.imageEl.OriginHeight;
27714 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27715 width = this.thumbEl.getHeight();
27716 this.baseScale = width / this.imageEl.OriginWidth;
27723 width = this.thumbEl.getWidth();
27724 this.baseScale = width / this.imageEl.OriginWidth;
27726 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27727 height = this.thumbEl.getHeight();
27728 this.baseScale = height / this.imageEl.OriginHeight;
27731 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27733 height = this.thumbEl.getHeight();
27734 this.baseScale = height / this.imageEl.OriginHeight;
27736 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27737 width = this.thumbEl.getWidth();
27738 this.baseScale = width / this.imageEl.OriginWidth;
27746 getScaleLevel : function()
27748 return this.baseScale * Math.pow(1.1, this.scale);
27751 onTouchStart : function(e)
27753 if(!this.canvasLoaded){
27754 this.beforeSelectFile(e);
27758 var touches = e.browserEvent.touches;
27764 if(touches.length == 1){
27765 this.onMouseDown(e);
27769 if(touches.length != 2){
27775 for(var i = 0, finger; finger = touches[i]; i++){
27776 coords.push(finger.pageX, finger.pageY);
27779 var x = Math.pow(coords[0] - coords[2], 2);
27780 var y = Math.pow(coords[1] - coords[3], 2);
27782 this.startDistance = Math.sqrt(x + y);
27784 this.startScale = this.scale;
27786 this.pinching = true;
27787 this.dragable = false;
27791 onTouchMove : function(e)
27793 if(!this.pinching && !this.dragable){
27797 var touches = e.browserEvent.touches;
27804 this.onMouseMove(e);
27810 for(var i = 0, finger; finger = touches[i]; i++){
27811 coords.push(finger.pageX, finger.pageY);
27814 var x = Math.pow(coords[0] - coords[2], 2);
27815 var y = Math.pow(coords[1] - coords[3], 2);
27817 this.endDistance = Math.sqrt(x + y);
27819 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27821 if(!this.zoomable()){
27822 this.scale = this.startScale;
27830 onTouchEnd : function(e)
27832 this.pinching = false;
27833 this.dragable = false;
27837 process : function(file, crop)
27840 this.maskEl.mask(this.loadingText);
27843 this.xhr = new XMLHttpRequest();
27845 file.xhr = this.xhr;
27847 this.xhr.open(this.method, this.url, true);
27850 "Accept": "application/json",
27851 "Cache-Control": "no-cache",
27852 "X-Requested-With": "XMLHttpRequest"
27855 for (var headerName in headers) {
27856 var headerValue = headers[headerName];
27858 this.xhr.setRequestHeader(headerName, headerValue);
27864 this.xhr.onload = function()
27866 _this.xhrOnLoad(_this.xhr);
27869 this.xhr.onerror = function()
27871 _this.xhrOnError(_this.xhr);
27874 var formData = new FormData();
27876 formData.append('returnHTML', 'NO');
27879 formData.append('crop', crop);
27882 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27883 formData.append(this.paramName, file, file.name);
27886 if(typeof(file.filename) != 'undefined'){
27887 formData.append('filename', file.filename);
27890 if(typeof(file.mimetype) != 'undefined'){
27891 formData.append('mimetype', file.mimetype);
27894 if(this.fireEvent('arrange', this, formData) != false){
27895 this.xhr.send(formData);
27899 xhrOnLoad : function(xhr)
27902 this.maskEl.unmask();
27905 if (xhr.readyState !== 4) {
27906 this.fireEvent('exception', this, xhr);
27910 var response = Roo.decode(xhr.responseText);
27912 if(!response.success){
27913 this.fireEvent('exception', this, xhr);
27917 var response = Roo.decode(xhr.responseText);
27919 this.fireEvent('upload', this, response);
27923 xhrOnError : function()
27926 this.maskEl.unmask();
27929 Roo.log('xhr on error');
27931 var response = Roo.decode(xhr.responseText);
27937 prepare : function(file)
27940 this.maskEl.mask(this.loadingText);
27946 if(typeof(file) === 'string'){
27947 this.loadCanvas(file);
27951 if(!file || !this.urlAPI){
27956 this.cropType = file.type;
27960 if(this.fireEvent('prepare', this, this.file) != false){
27962 var reader = new FileReader();
27964 reader.onload = function (e) {
27965 if (e.target.error) {
27966 Roo.log(e.target.error);
27970 var buffer = e.target.result,
27971 dataView = new DataView(buffer),
27973 maxOffset = dataView.byteLength - 4,
27977 if (dataView.getUint16(0) === 0xffd8) {
27978 while (offset < maxOffset) {
27979 markerBytes = dataView.getUint16(offset);
27981 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27982 markerLength = dataView.getUint16(offset + 2) + 2;
27983 if (offset + markerLength > dataView.byteLength) {
27984 Roo.log('Invalid meta data: Invalid segment size.');
27988 if(markerBytes == 0xffe1){
27989 _this.parseExifData(
27996 offset += markerLength;
28006 var url = _this.urlAPI.createObjectURL(_this.file);
28008 _this.loadCanvas(url);
28013 reader.readAsArrayBuffer(this.file);
28019 parseExifData : function(dataView, offset, length)
28021 var tiffOffset = offset + 10,
28025 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28026 // No Exif data, might be XMP data instead
28030 // Check for the ASCII code for "Exif" (0x45786966):
28031 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28032 // No Exif data, might be XMP data instead
28035 if (tiffOffset + 8 > dataView.byteLength) {
28036 Roo.log('Invalid Exif data: Invalid segment size.');
28039 // Check for the two null bytes:
28040 if (dataView.getUint16(offset + 8) !== 0x0000) {
28041 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28044 // Check the byte alignment:
28045 switch (dataView.getUint16(tiffOffset)) {
28047 littleEndian = true;
28050 littleEndian = false;
28053 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28056 // Check for the TIFF tag marker (0x002A):
28057 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28058 Roo.log('Invalid Exif data: Missing TIFF marker.');
28061 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28062 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28064 this.parseExifTags(
28067 tiffOffset + dirOffset,
28072 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28077 if (dirOffset + 6 > dataView.byteLength) {
28078 Roo.log('Invalid Exif data: Invalid directory offset.');
28081 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28082 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28083 if (dirEndOffset + 4 > dataView.byteLength) {
28084 Roo.log('Invalid Exif data: Invalid directory size.');
28087 for (i = 0; i < tagsNumber; i += 1) {
28091 dirOffset + 2 + 12 * i, // tag offset
28095 // Return the offset to the next directory:
28096 return dataView.getUint32(dirEndOffset, littleEndian);
28099 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28101 var tag = dataView.getUint16(offset, littleEndian);
28103 this.exif[tag] = this.getExifValue(
28107 dataView.getUint16(offset + 2, littleEndian), // tag type
28108 dataView.getUint32(offset + 4, littleEndian), // tag length
28113 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28115 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28124 Roo.log('Invalid Exif data: Invalid tag type.');
28128 tagSize = tagType.size * length;
28129 // Determine if the value is contained in the dataOffset bytes,
28130 // or if the value at the dataOffset is a pointer to the actual data:
28131 dataOffset = tagSize > 4 ?
28132 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28133 if (dataOffset + tagSize > dataView.byteLength) {
28134 Roo.log('Invalid Exif data: Invalid data offset.');
28137 if (length === 1) {
28138 return tagType.getValue(dataView, dataOffset, littleEndian);
28141 for (i = 0; i < length; i += 1) {
28142 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28145 if (tagType.ascii) {
28147 // Concatenate the chars:
28148 for (i = 0; i < values.length; i += 1) {
28150 // Ignore the terminating NULL byte(s):
28151 if (c === '\u0000') {
28163 Roo.apply(Roo.bootstrap.UploadCropbox, {
28165 'Orientation': 0x0112
28169 1: 0, //'top-left',
28171 3: 180, //'bottom-right',
28172 // 4: 'bottom-left',
28174 6: 90, //'right-top',
28175 // 7: 'right-bottom',
28176 8: 270 //'left-bottom'
28180 // byte, 8-bit unsigned int:
28182 getValue: function (dataView, dataOffset) {
28183 return dataView.getUint8(dataOffset);
28187 // ascii, 8-bit byte:
28189 getValue: function (dataView, dataOffset) {
28190 return String.fromCharCode(dataView.getUint8(dataOffset));
28195 // short, 16 bit int:
28197 getValue: function (dataView, dataOffset, littleEndian) {
28198 return dataView.getUint16(dataOffset, littleEndian);
28202 // long, 32 bit int:
28204 getValue: function (dataView, dataOffset, littleEndian) {
28205 return dataView.getUint32(dataOffset, littleEndian);
28209 // rational = two long values, first is numerator, second is denominator:
28211 getValue: function (dataView, dataOffset, littleEndian) {
28212 return dataView.getUint32(dataOffset, littleEndian) /
28213 dataView.getUint32(dataOffset + 4, littleEndian);
28217 // slong, 32 bit signed int:
28219 getValue: function (dataView, dataOffset, littleEndian) {
28220 return dataView.getInt32(dataOffset, littleEndian);
28224 // srational, two slongs, first is numerator, second is denominator:
28226 getValue: function (dataView, dataOffset, littleEndian) {
28227 return dataView.getInt32(dataOffset, littleEndian) /
28228 dataView.getInt32(dataOffset + 4, littleEndian);
28238 cls : 'btn-group roo-upload-cropbox-rotate-left',
28239 action : 'rotate-left',
28243 cls : 'btn btn-default',
28244 html : '<i class="fa fa-undo"></i>'
28250 cls : 'btn-group roo-upload-cropbox-picture',
28251 action : 'picture',
28255 cls : 'btn btn-default',
28256 html : '<i class="fa fa-picture-o"></i>'
28262 cls : 'btn-group roo-upload-cropbox-rotate-right',
28263 action : 'rotate-right',
28267 cls : 'btn btn-default',
28268 html : '<i class="fa fa-repeat"></i>'
28276 cls : 'btn-group roo-upload-cropbox-rotate-left',
28277 action : 'rotate-left',
28281 cls : 'btn btn-default',
28282 html : '<i class="fa fa-undo"></i>'
28288 cls : 'btn-group roo-upload-cropbox-download',
28289 action : 'download',
28293 cls : 'btn btn-default',
28294 html : '<i class="fa fa-download"></i>'
28300 cls : 'btn-group roo-upload-cropbox-crop',
28305 cls : 'btn btn-default',
28306 html : '<i class="fa fa-crop"></i>'
28312 cls : 'btn-group roo-upload-cropbox-trash',
28317 cls : 'btn btn-default',
28318 html : '<i class="fa fa-trash"></i>'
28324 cls : 'btn-group roo-upload-cropbox-rotate-right',
28325 action : 'rotate-right',
28329 cls : 'btn btn-default',
28330 html : '<i class="fa fa-repeat"></i>'
28338 cls : 'btn-group roo-upload-cropbox-rotate-left',
28339 action : 'rotate-left',
28343 cls : 'btn btn-default',
28344 html : '<i class="fa fa-undo"></i>'
28350 cls : 'btn-group roo-upload-cropbox-rotate-right',
28351 action : 'rotate-right',
28355 cls : 'btn btn-default',
28356 html : '<i class="fa fa-repeat"></i>'
28369 * @class Roo.bootstrap.DocumentManager
28370 * @extends Roo.bootstrap.Component
28371 * Bootstrap DocumentManager class
28372 * @cfg {String} paramName default 'imageUpload'
28373 * @cfg {String} toolTipName default 'filename'
28374 * @cfg {String} method default POST
28375 * @cfg {String} url action url
28376 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28377 * @cfg {Boolean} multiple multiple upload default true
28378 * @cfg {Number} thumbSize default 300
28379 * @cfg {String} fieldLabel
28380 * @cfg {Number} labelWidth default 4
28381 * @cfg {String} labelAlign (left|top) default left
28382 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28383 * @cfg {Number} labellg set the width of label (1-12)
28384 * @cfg {Number} labelmd set the width of label (1-12)
28385 * @cfg {Number} labelsm set the width of label (1-12)
28386 * @cfg {Number} labelxs set the width of label (1-12)
28389 * Create a new DocumentManager
28390 * @param {Object} config The config object
28393 Roo.bootstrap.DocumentManager = function(config){
28394 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28397 this.delegates = [];
28402 * Fire when initial the DocumentManager
28403 * @param {Roo.bootstrap.DocumentManager} this
28408 * inspect selected file
28409 * @param {Roo.bootstrap.DocumentManager} this
28410 * @param {File} file
28415 * Fire when xhr load exception
28416 * @param {Roo.bootstrap.DocumentManager} this
28417 * @param {XMLHttpRequest} xhr
28419 "exception" : true,
28421 * @event afterupload
28422 * Fire when xhr load exception
28423 * @param {Roo.bootstrap.DocumentManager} this
28424 * @param {XMLHttpRequest} xhr
28426 "afterupload" : true,
28429 * prepare the form data
28430 * @param {Roo.bootstrap.DocumentManager} this
28431 * @param {Object} formData
28436 * Fire when remove the file
28437 * @param {Roo.bootstrap.DocumentManager} this
28438 * @param {Object} file
28443 * Fire after refresh the file
28444 * @param {Roo.bootstrap.DocumentManager} this
28449 * Fire after click the image
28450 * @param {Roo.bootstrap.DocumentManager} this
28451 * @param {Object} file
28456 * Fire when upload a image and editable set to true
28457 * @param {Roo.bootstrap.DocumentManager} this
28458 * @param {Object} file
28462 * @event beforeselectfile
28463 * Fire before select file
28464 * @param {Roo.bootstrap.DocumentManager} this
28466 "beforeselectfile" : true,
28469 * Fire before process file
28470 * @param {Roo.bootstrap.DocumentManager} this
28471 * @param {Object} file
28475 * @event previewrendered
28476 * Fire when preview rendered
28477 * @param {Roo.bootstrap.DocumentManager} this
28478 * @param {Object} file
28480 "previewrendered" : true
28485 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28494 paramName : 'imageUpload',
28495 toolTipName : 'filename',
28498 labelAlign : 'left',
28508 getAutoCreate : function()
28510 var managerWidget = {
28512 cls : 'roo-document-manager',
28516 cls : 'roo-document-manager-selector',
28521 cls : 'roo-document-manager-uploader',
28525 cls : 'roo-document-manager-upload-btn',
28526 html : '<i class="fa fa-plus"></i>'
28537 cls : 'column col-md-12',
28542 if(this.fieldLabel.length){
28547 cls : 'column col-md-12',
28548 html : this.fieldLabel
28552 cls : 'column col-md-12',
28557 if(this.labelAlign == 'left'){
28562 html : this.fieldLabel
28571 if(this.labelWidth > 12){
28572 content[0].style = "width: " + this.labelWidth + 'px';
28575 if(this.labelWidth < 13 && this.labelmd == 0){
28576 this.labelmd = this.labelWidth;
28579 if(this.labellg > 0){
28580 content[0].cls += ' col-lg-' + this.labellg;
28581 content[1].cls += ' col-lg-' + (12 - this.labellg);
28584 if(this.labelmd > 0){
28585 content[0].cls += ' col-md-' + this.labelmd;
28586 content[1].cls += ' col-md-' + (12 - this.labelmd);
28589 if(this.labelsm > 0){
28590 content[0].cls += ' col-sm-' + this.labelsm;
28591 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28594 if(this.labelxs > 0){
28595 content[0].cls += ' col-xs-' + this.labelxs;
28596 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28604 cls : 'row clearfix',
28612 initEvents : function()
28614 this.managerEl = this.el.select('.roo-document-manager', true).first();
28615 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28617 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28618 this.selectorEl.hide();
28621 this.selectorEl.attr('multiple', 'multiple');
28624 this.selectorEl.on('change', this.onFileSelected, this);
28626 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28627 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28629 this.uploader.on('click', this.onUploaderClick, this);
28631 this.renderProgressDialog();
28635 window.addEventListener("resize", function() { _this.refresh(); } );
28637 this.fireEvent('initial', this);
28640 renderProgressDialog : function()
28644 this.progressDialog = new Roo.bootstrap.Modal({
28645 cls : 'roo-document-manager-progress-dialog',
28646 allow_close : false,
28656 btnclick : function() {
28657 _this.uploadCancel();
28663 this.progressDialog.render(Roo.get(document.body));
28665 this.progress = new Roo.bootstrap.Progress({
28666 cls : 'roo-document-manager-progress',
28671 this.progress.render(this.progressDialog.getChildContainer());
28673 this.progressBar = new Roo.bootstrap.ProgressBar({
28674 cls : 'roo-document-manager-progress-bar',
28677 aria_valuemax : 12,
28681 this.progressBar.render(this.progress.getChildContainer());
28684 onUploaderClick : function(e)
28686 e.preventDefault();
28688 if(this.fireEvent('beforeselectfile', this) != false){
28689 this.selectorEl.dom.click();
28694 onFileSelected : function(e)
28696 e.preventDefault();
28698 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28702 Roo.each(this.selectorEl.dom.files, function(file){
28703 if(this.fireEvent('inspect', this, file) != false){
28704 this.files.push(file);
28714 this.selectorEl.dom.value = '';
28716 if(!this.files || !this.files.length){
28720 if(this.boxes > 0 && this.files.length > this.boxes){
28721 this.files = this.files.slice(0, this.boxes);
28724 this.uploader.show();
28726 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28727 this.uploader.hide();
28736 Roo.each(this.files, function(file){
28738 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28739 var f = this.renderPreview(file);
28744 if(file.type.indexOf('image') != -1){
28745 this.delegates.push(
28747 _this.process(file);
28748 }).createDelegate(this)
28756 _this.process(file);
28757 }).createDelegate(this)
28762 this.files = files;
28764 this.delegates = this.delegates.concat(docs);
28766 if(!this.delegates.length){
28771 this.progressBar.aria_valuemax = this.delegates.length;
28778 arrange : function()
28780 if(!this.delegates.length){
28781 this.progressDialog.hide();
28786 var delegate = this.delegates.shift();
28788 this.progressDialog.show();
28790 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28792 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28797 refresh : function()
28799 this.uploader.show();
28801 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28802 this.uploader.hide();
28805 Roo.isTouch ? this.closable(false) : this.closable(true);
28807 this.fireEvent('refresh', this);
28810 onRemove : function(e, el, o)
28812 e.preventDefault();
28814 this.fireEvent('remove', this, o);
28818 remove : function(o)
28822 Roo.each(this.files, function(file){
28823 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28832 this.files = files;
28839 Roo.each(this.files, function(file){
28844 file.target.remove();
28853 onClick : function(e, el, o)
28855 e.preventDefault();
28857 this.fireEvent('click', this, o);
28861 closable : function(closable)
28863 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28865 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28877 xhrOnLoad : function(xhr)
28879 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28883 if (xhr.readyState !== 4) {
28885 this.fireEvent('exception', this, xhr);
28889 var response = Roo.decode(xhr.responseText);
28891 if(!response.success){
28893 this.fireEvent('exception', this, xhr);
28897 var file = this.renderPreview(response.data);
28899 this.files.push(file);
28903 this.fireEvent('afterupload', this, xhr);
28907 xhrOnError : function(xhr)
28909 Roo.log('xhr on error');
28911 var response = Roo.decode(xhr.responseText);
28918 process : function(file)
28920 if(this.fireEvent('process', this, file) !== false){
28921 if(this.editable && file.type.indexOf('image') != -1){
28922 this.fireEvent('edit', this, file);
28926 this.uploadStart(file, false);
28933 uploadStart : function(file, crop)
28935 this.xhr = new XMLHttpRequest();
28937 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28942 file.xhr = this.xhr;
28944 this.managerEl.createChild({
28946 cls : 'roo-document-manager-loading',
28950 tooltip : file.name,
28951 cls : 'roo-document-manager-thumb',
28952 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28958 this.xhr.open(this.method, this.url, true);
28961 "Accept": "application/json",
28962 "Cache-Control": "no-cache",
28963 "X-Requested-With": "XMLHttpRequest"
28966 for (var headerName in headers) {
28967 var headerValue = headers[headerName];
28969 this.xhr.setRequestHeader(headerName, headerValue);
28975 this.xhr.onload = function()
28977 _this.xhrOnLoad(_this.xhr);
28980 this.xhr.onerror = function()
28982 _this.xhrOnError(_this.xhr);
28985 var formData = new FormData();
28987 formData.append('returnHTML', 'NO');
28990 formData.append('crop', crop);
28993 formData.append(this.paramName, file, file.name);
29000 if(this.fireEvent('prepare', this, formData, options) != false){
29002 if(options.manually){
29006 this.xhr.send(formData);
29010 this.uploadCancel();
29013 uploadCancel : function()
29019 this.delegates = [];
29021 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29028 renderPreview : function(file)
29030 if(typeof(file.target) != 'undefined' && file.target){
29034 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29036 var previewEl = this.managerEl.createChild({
29038 cls : 'roo-document-manager-preview',
29042 tooltip : file[this.toolTipName],
29043 cls : 'roo-document-manager-thumb',
29044 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29049 html : '<i class="fa fa-times-circle"></i>'
29054 var close = previewEl.select('button.close', true).first();
29056 close.on('click', this.onRemove, this, file);
29058 file.target = previewEl;
29060 var image = previewEl.select('img', true).first();
29064 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29066 image.on('click', this.onClick, this, file);
29068 this.fireEvent('previewrendered', this, file);
29074 onPreviewLoad : function(file, image)
29076 if(typeof(file.target) == 'undefined' || !file.target){
29080 var width = image.dom.naturalWidth || image.dom.width;
29081 var height = image.dom.naturalHeight || image.dom.height;
29083 if(width > height){
29084 file.target.addClass('wide');
29088 file.target.addClass('tall');
29093 uploadFromSource : function(file, crop)
29095 this.xhr = new XMLHttpRequest();
29097 this.managerEl.createChild({
29099 cls : 'roo-document-manager-loading',
29103 tooltip : file.name,
29104 cls : 'roo-document-manager-thumb',
29105 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29111 this.xhr.open(this.method, this.url, true);
29114 "Accept": "application/json",
29115 "Cache-Control": "no-cache",
29116 "X-Requested-With": "XMLHttpRequest"
29119 for (var headerName in headers) {
29120 var headerValue = headers[headerName];
29122 this.xhr.setRequestHeader(headerName, headerValue);
29128 this.xhr.onload = function()
29130 _this.xhrOnLoad(_this.xhr);
29133 this.xhr.onerror = function()
29135 _this.xhrOnError(_this.xhr);
29138 var formData = new FormData();
29140 formData.append('returnHTML', 'NO');
29142 formData.append('crop', crop);
29144 if(typeof(file.filename) != 'undefined'){
29145 formData.append('filename', file.filename);
29148 if(typeof(file.mimetype) != 'undefined'){
29149 formData.append('mimetype', file.mimetype);
29154 if(this.fireEvent('prepare', this, formData) != false){
29155 this.xhr.send(formData);
29165 * @class Roo.bootstrap.DocumentViewer
29166 * @extends Roo.bootstrap.Component
29167 * Bootstrap DocumentViewer class
29168 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29169 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29172 * Create a new DocumentViewer
29173 * @param {Object} config The config object
29176 Roo.bootstrap.DocumentViewer = function(config){
29177 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29182 * Fire after initEvent
29183 * @param {Roo.bootstrap.DocumentViewer} this
29189 * @param {Roo.bootstrap.DocumentViewer} this
29194 * Fire after download button
29195 * @param {Roo.bootstrap.DocumentViewer} this
29200 * Fire after trash button
29201 * @param {Roo.bootstrap.DocumentViewer} this
29208 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29210 showDownload : true,
29214 getAutoCreate : function()
29218 cls : 'roo-document-viewer',
29222 cls : 'roo-document-viewer-body',
29226 cls : 'roo-document-viewer-thumb',
29230 cls : 'roo-document-viewer-image'
29238 cls : 'roo-document-viewer-footer',
29241 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29245 cls : 'btn-group roo-document-viewer-download',
29249 cls : 'btn btn-default',
29250 html : '<i class="fa fa-download"></i>'
29256 cls : 'btn-group roo-document-viewer-trash',
29260 cls : 'btn btn-default',
29261 html : '<i class="fa fa-trash"></i>'
29274 initEvents : function()
29276 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29277 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29279 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29280 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29282 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29283 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29285 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29286 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29288 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29289 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29291 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29292 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29294 this.bodyEl.on('click', this.onClick, this);
29295 this.downloadBtn.on('click', this.onDownload, this);
29296 this.trashBtn.on('click', this.onTrash, this);
29298 this.downloadBtn.hide();
29299 this.trashBtn.hide();
29301 if(this.showDownload){
29302 this.downloadBtn.show();
29305 if(this.showTrash){
29306 this.trashBtn.show();
29309 if(!this.showDownload && !this.showTrash) {
29310 this.footerEl.hide();
29315 initial : function()
29317 this.fireEvent('initial', this);
29321 onClick : function(e)
29323 e.preventDefault();
29325 this.fireEvent('click', this);
29328 onDownload : function(e)
29330 e.preventDefault();
29332 this.fireEvent('download', this);
29335 onTrash : function(e)
29337 e.preventDefault();
29339 this.fireEvent('trash', this);
29351 * @class Roo.bootstrap.NavProgressBar
29352 * @extends Roo.bootstrap.Component
29353 * Bootstrap NavProgressBar class
29356 * Create a new nav progress bar
29357 * @param {Object} config The config object
29360 Roo.bootstrap.NavProgressBar = function(config){
29361 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29363 this.bullets = this.bullets || [];
29365 // Roo.bootstrap.NavProgressBar.register(this);
29369 * Fires when the active item changes
29370 * @param {Roo.bootstrap.NavProgressBar} this
29371 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29372 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29379 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29384 getAutoCreate : function()
29386 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29390 cls : 'roo-navigation-bar-group',
29394 cls : 'roo-navigation-top-bar'
29398 cls : 'roo-navigation-bullets-bar',
29402 cls : 'roo-navigation-bar'
29409 cls : 'roo-navigation-bottom-bar'
29419 initEvents: function()
29424 onRender : function(ct, position)
29426 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29428 if(this.bullets.length){
29429 Roo.each(this.bullets, function(b){
29438 addItem : function(cfg)
29440 var item = new Roo.bootstrap.NavProgressItem(cfg);
29442 item.parentId = this.id;
29443 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29446 var top = new Roo.bootstrap.Element({
29448 cls : 'roo-navigation-bar-text'
29451 var bottom = new Roo.bootstrap.Element({
29453 cls : 'roo-navigation-bar-text'
29456 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29457 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29459 var topText = new Roo.bootstrap.Element({
29461 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29464 var bottomText = new Roo.bootstrap.Element({
29466 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29469 topText.onRender(top.el, null);
29470 bottomText.onRender(bottom.el, null);
29473 item.bottomEl = bottom;
29476 this.barItems.push(item);
29481 getActive : function()
29483 var active = false;
29485 Roo.each(this.barItems, function(v){
29487 if (!v.isActive()) {
29499 setActiveItem : function(item)
29503 Roo.each(this.barItems, function(v){
29504 if (v.rid == item.rid) {
29508 if (v.isActive()) {
29509 v.setActive(false);
29514 item.setActive(true);
29516 this.fireEvent('changed', this, item, prev);
29519 getBarItem: function(rid)
29523 Roo.each(this.barItems, function(e) {
29524 if (e.rid != rid) {
29535 indexOfItem : function(item)
29539 Roo.each(this.barItems, function(v, i){
29541 if (v.rid != item.rid) {
29552 setActiveNext : function()
29554 var i = this.indexOfItem(this.getActive());
29556 if (i > this.barItems.length) {
29560 this.setActiveItem(this.barItems[i+1]);
29563 setActivePrev : function()
29565 var i = this.indexOfItem(this.getActive());
29571 this.setActiveItem(this.barItems[i-1]);
29574 format : function()
29576 if(!this.barItems.length){
29580 var width = 100 / this.barItems.length;
29582 Roo.each(this.barItems, function(i){
29583 i.el.setStyle('width', width + '%');
29584 i.topEl.el.setStyle('width', width + '%');
29585 i.bottomEl.el.setStyle('width', width + '%');
29594 * Nav Progress Item
29599 * @class Roo.bootstrap.NavProgressItem
29600 * @extends Roo.bootstrap.Component
29601 * Bootstrap NavProgressItem class
29602 * @cfg {String} rid the reference id
29603 * @cfg {Boolean} active (true|false) Is item active default false
29604 * @cfg {Boolean} disabled (true|false) Is item active default false
29605 * @cfg {String} html
29606 * @cfg {String} position (top|bottom) text position default bottom
29607 * @cfg {String} icon show icon instead of number
29610 * Create a new NavProgressItem
29611 * @param {Object} config The config object
29613 Roo.bootstrap.NavProgressItem = function(config){
29614 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29619 * The raw click event for the entire grid.
29620 * @param {Roo.bootstrap.NavProgressItem} this
29621 * @param {Roo.EventObject} e
29628 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29634 position : 'bottom',
29637 getAutoCreate : function()
29639 var iconCls = 'roo-navigation-bar-item-icon';
29641 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29645 cls: 'roo-navigation-bar-item',
29655 cfg.cls += ' active';
29658 cfg.cls += ' disabled';
29664 disable : function()
29666 this.setDisabled(true);
29669 enable : function()
29671 this.setDisabled(false);
29674 initEvents: function()
29676 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29678 this.iconEl.on('click', this.onClick, this);
29681 onClick : function(e)
29683 e.preventDefault();
29689 if(this.fireEvent('click', this, e) === false){
29693 this.parent().setActiveItem(this);
29696 isActive: function ()
29698 return this.active;
29701 setActive : function(state)
29703 if(this.active == state){
29707 this.active = state;
29710 this.el.addClass('active');
29714 this.el.removeClass('active');
29719 setDisabled : function(state)
29721 if(this.disabled == state){
29725 this.disabled = state;
29728 this.el.addClass('disabled');
29732 this.el.removeClass('disabled');
29735 tooltipEl : function()
29737 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29750 * @class Roo.bootstrap.FieldLabel
29751 * @extends Roo.bootstrap.Component
29752 * Bootstrap FieldLabel class
29753 * @cfg {String} html contents of the element
29754 * @cfg {String} tag tag of the element default label
29755 * @cfg {String} cls class of the element
29756 * @cfg {String} target label target
29757 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29758 * @cfg {String} invalidClass default "text-warning"
29759 * @cfg {String} validClass default "text-success"
29760 * @cfg {String} iconTooltip default "This field is required"
29761 * @cfg {String} indicatorpos (left|right) default left
29764 * Create a new FieldLabel
29765 * @param {Object} config The config object
29768 Roo.bootstrap.FieldLabel = function(config){
29769 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29774 * Fires after the field has been marked as invalid.
29775 * @param {Roo.form.FieldLabel} this
29776 * @param {String} msg The validation message
29781 * Fires after the field has been validated with no errors.
29782 * @param {Roo.form.FieldLabel} this
29788 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29795 invalidClass : 'has-warning',
29796 validClass : 'has-success',
29797 iconTooltip : 'This field is required',
29798 indicatorpos : 'left',
29800 getAutoCreate : function(){
29804 cls : 'roo-bootstrap-field-label ' + this.cls,
29809 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29810 tooltip : this.iconTooltip
29819 if(this.indicatorpos == 'right'){
29822 cls : 'roo-bootstrap-field-label ' + this.cls,
29831 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29832 tooltip : this.iconTooltip
29841 initEvents: function()
29843 Roo.bootstrap.Element.superclass.initEvents.call(this);
29845 this.indicator = this.indicatorEl();
29847 if(this.indicator){
29848 this.indicator.removeClass('visible');
29849 this.indicator.addClass('invisible');
29852 Roo.bootstrap.FieldLabel.register(this);
29855 indicatorEl : function()
29857 var indicator = this.el.select('i.roo-required-indicator',true).first();
29868 * Mark this field as valid
29870 markValid : function()
29872 if(this.indicator){
29873 this.indicator.removeClass('visible');
29874 this.indicator.addClass('invisible');
29877 this.el.removeClass(this.invalidClass);
29879 this.el.addClass(this.validClass);
29881 this.fireEvent('valid', this);
29885 * Mark this field as invalid
29886 * @param {String} msg The validation message
29888 markInvalid : function(msg)
29890 if(this.indicator){
29891 this.indicator.removeClass('invisible');
29892 this.indicator.addClass('visible');
29895 this.el.removeClass(this.validClass);
29897 this.el.addClass(this.invalidClass);
29899 this.fireEvent('invalid', this, msg);
29905 Roo.apply(Roo.bootstrap.FieldLabel, {
29910 * register a FieldLabel Group
29911 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29913 register : function(label)
29915 if(this.groups.hasOwnProperty(label.target)){
29919 this.groups[label.target] = label;
29923 * fetch a FieldLabel Group based on the target
29924 * @param {string} target
29925 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29927 get: function(target) {
29928 if (typeof(this.groups[target]) == 'undefined') {
29932 return this.groups[target] ;
29941 * page DateSplitField.
29947 * @class Roo.bootstrap.DateSplitField
29948 * @extends Roo.bootstrap.Component
29949 * Bootstrap DateSplitField class
29950 * @cfg {string} fieldLabel - the label associated
29951 * @cfg {Number} labelWidth set the width of label (0-12)
29952 * @cfg {String} labelAlign (top|left)
29953 * @cfg {Boolean} dayAllowBlank (true|false) default false
29954 * @cfg {Boolean} monthAllowBlank (true|false) default false
29955 * @cfg {Boolean} yearAllowBlank (true|false) default false
29956 * @cfg {string} dayPlaceholder
29957 * @cfg {string} monthPlaceholder
29958 * @cfg {string} yearPlaceholder
29959 * @cfg {string} dayFormat default 'd'
29960 * @cfg {string} monthFormat default 'm'
29961 * @cfg {string} yearFormat default 'Y'
29962 * @cfg {Number} labellg set the width of label (1-12)
29963 * @cfg {Number} labelmd set the width of label (1-12)
29964 * @cfg {Number} labelsm set the width of label (1-12)
29965 * @cfg {Number} labelxs set the width of label (1-12)
29969 * Create a new DateSplitField
29970 * @param {Object} config The config object
29973 Roo.bootstrap.DateSplitField = function(config){
29974 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29980 * getting the data of years
29981 * @param {Roo.bootstrap.DateSplitField} this
29982 * @param {Object} years
29987 * getting the data of days
29988 * @param {Roo.bootstrap.DateSplitField} this
29989 * @param {Object} days
29994 * Fires after the field has been marked as invalid.
29995 * @param {Roo.form.Field} this
29996 * @param {String} msg The validation message
30001 * Fires after the field has been validated with no errors.
30002 * @param {Roo.form.Field} this
30008 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30011 labelAlign : 'top',
30013 dayAllowBlank : false,
30014 monthAllowBlank : false,
30015 yearAllowBlank : false,
30016 dayPlaceholder : '',
30017 monthPlaceholder : '',
30018 yearPlaceholder : '',
30022 isFormField : true,
30028 getAutoCreate : function()
30032 cls : 'row roo-date-split-field-group',
30037 cls : 'form-hidden-field roo-date-split-field-group-value',
30043 var labelCls = 'col-md-12';
30044 var contentCls = 'col-md-4';
30046 if(this.fieldLabel){
30050 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30054 html : this.fieldLabel
30059 if(this.labelAlign == 'left'){
30061 if(this.labelWidth > 12){
30062 label.style = "width: " + this.labelWidth + 'px';
30065 if(this.labelWidth < 13 && this.labelmd == 0){
30066 this.labelmd = this.labelWidth;
30069 if(this.labellg > 0){
30070 labelCls = ' col-lg-' + this.labellg;
30071 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30074 if(this.labelmd > 0){
30075 labelCls = ' col-md-' + this.labelmd;
30076 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30079 if(this.labelsm > 0){
30080 labelCls = ' col-sm-' + this.labelsm;
30081 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30084 if(this.labelxs > 0){
30085 labelCls = ' col-xs-' + this.labelxs;
30086 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30090 label.cls += ' ' + labelCls;
30092 cfg.cn.push(label);
30095 Roo.each(['day', 'month', 'year'], function(t){
30098 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30105 inputEl: function ()
30107 return this.el.select('.roo-date-split-field-group-value', true).first();
30110 onRender : function(ct, position)
30114 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30116 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30118 this.dayField = new Roo.bootstrap.ComboBox({
30119 allowBlank : this.dayAllowBlank,
30120 alwaysQuery : true,
30121 displayField : 'value',
30124 forceSelection : true,
30126 placeholder : this.dayPlaceholder,
30127 selectOnFocus : true,
30128 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30129 triggerAction : 'all',
30131 valueField : 'value',
30132 store : new Roo.data.SimpleStore({
30133 data : (function() {
30135 _this.fireEvent('days', _this, days);
30138 fields : [ 'value' ]
30141 select : function (_self, record, index)
30143 _this.setValue(_this.getValue());
30148 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30150 this.monthField = new Roo.bootstrap.MonthField({
30151 after : '<i class=\"fa fa-calendar\"></i>',
30152 allowBlank : this.monthAllowBlank,
30153 placeholder : this.monthPlaceholder,
30156 render : function (_self)
30158 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30159 e.preventDefault();
30163 select : function (_self, oldvalue, newvalue)
30165 _this.setValue(_this.getValue());
30170 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30172 this.yearField = new Roo.bootstrap.ComboBox({
30173 allowBlank : this.yearAllowBlank,
30174 alwaysQuery : true,
30175 displayField : 'value',
30178 forceSelection : true,
30180 placeholder : this.yearPlaceholder,
30181 selectOnFocus : true,
30182 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30183 triggerAction : 'all',
30185 valueField : 'value',
30186 store : new Roo.data.SimpleStore({
30187 data : (function() {
30189 _this.fireEvent('years', _this, years);
30192 fields : [ 'value' ]
30195 select : function (_self, record, index)
30197 _this.setValue(_this.getValue());
30202 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30205 setValue : function(v, format)
30207 this.inputEl.dom.value = v;
30209 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30211 var d = Date.parseDate(v, f);
30218 this.setDay(d.format(this.dayFormat));
30219 this.setMonth(d.format(this.monthFormat));
30220 this.setYear(d.format(this.yearFormat));
30227 setDay : function(v)
30229 this.dayField.setValue(v);
30230 this.inputEl.dom.value = this.getValue();
30235 setMonth : function(v)
30237 this.monthField.setValue(v, true);
30238 this.inputEl.dom.value = this.getValue();
30243 setYear : function(v)
30245 this.yearField.setValue(v);
30246 this.inputEl.dom.value = this.getValue();
30251 getDay : function()
30253 return this.dayField.getValue();
30256 getMonth : function()
30258 return this.monthField.getValue();
30261 getYear : function()
30263 return this.yearField.getValue();
30266 getValue : function()
30268 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30270 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30280 this.inputEl.dom.value = '';
30285 validate : function()
30287 var d = this.dayField.validate();
30288 var m = this.monthField.validate();
30289 var y = this.yearField.validate();
30294 (!this.dayAllowBlank && !d) ||
30295 (!this.monthAllowBlank && !m) ||
30296 (!this.yearAllowBlank && !y)
30301 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30310 this.markInvalid();
30315 markValid : function()
30318 var label = this.el.select('label', true).first();
30319 var icon = this.el.select('i.fa-star', true).first();
30325 this.fireEvent('valid', this);
30329 * Mark this field as invalid
30330 * @param {String} msg The validation message
30332 markInvalid : function(msg)
30335 var label = this.el.select('label', true).first();
30336 var icon = this.el.select('i.fa-star', true).first();
30338 if(label && !icon){
30339 this.el.select('.roo-date-split-field-label', true).createChild({
30341 cls : 'text-danger fa fa-lg fa-star',
30342 tooltip : 'This field is required',
30343 style : 'margin-right:5px;'
30347 this.fireEvent('invalid', this, msg);
30350 clearInvalid : function()
30352 var label = this.el.select('label', true).first();
30353 var icon = this.el.select('i.fa-star', true).first();
30359 this.fireEvent('valid', this);
30362 getName: function()
30372 * http://masonry.desandro.com
30374 * The idea is to render all the bricks based on vertical width...
30376 * The original code extends 'outlayer' - we might need to use that....
30382 * @class Roo.bootstrap.LayoutMasonry
30383 * @extends Roo.bootstrap.Component
30384 * Bootstrap Layout Masonry class
30387 * Create a new Element
30388 * @param {Object} config The config object
30391 Roo.bootstrap.LayoutMasonry = function(config){
30393 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30397 Roo.bootstrap.LayoutMasonry.register(this);
30403 * Fire after layout the items
30404 * @param {Roo.bootstrap.LayoutMasonry} this
30405 * @param {Roo.EventObject} e
30412 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30415 * @cfg {Boolean} isLayoutInstant = no animation?
30417 isLayoutInstant : false, // needed?
30420 * @cfg {Number} boxWidth width of the columns
30425 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30430 * @cfg {Number} padWidth padding below box..
30435 * @cfg {Number} gutter gutter width..
30440 * @cfg {Number} maxCols maximum number of columns
30446 * @cfg {Boolean} isAutoInitial defalut true
30448 isAutoInitial : true,
30453 * @cfg {Boolean} isHorizontal defalut false
30455 isHorizontal : false,
30457 currentSize : null,
30463 bricks: null, //CompositeElement
30467 _isLayoutInited : false,
30469 // isAlternative : false, // only use for vertical layout...
30472 * @cfg {Number} alternativePadWidth padding below box..
30474 alternativePadWidth : 50,
30476 selectedBrick : [],
30478 getAutoCreate : function(){
30480 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30484 cls: 'blog-masonary-wrapper ' + this.cls,
30486 cls : 'mas-boxes masonary'
30493 getChildContainer: function( )
30495 if (this.boxesEl) {
30496 return this.boxesEl;
30499 this.boxesEl = this.el.select('.mas-boxes').first();
30501 return this.boxesEl;
30505 initEvents : function()
30509 if(this.isAutoInitial){
30510 Roo.log('hook children rendered');
30511 this.on('childrenrendered', function() {
30512 Roo.log('children rendered');
30518 initial : function()
30520 this.selectedBrick = [];
30522 this.currentSize = this.el.getBox(true);
30524 Roo.EventManager.onWindowResize(this.resize, this);
30526 if(!this.isAutoInitial){
30534 //this.layout.defer(500,this);
30538 resize : function()
30540 var cs = this.el.getBox(true);
30543 this.currentSize.width == cs.width &&
30544 this.currentSize.x == cs.x &&
30545 this.currentSize.height == cs.height &&
30546 this.currentSize.y == cs.y
30548 Roo.log("no change in with or X or Y");
30552 this.currentSize = cs;
30558 layout : function()
30560 this._resetLayout();
30562 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30564 this.layoutItems( isInstant );
30566 this._isLayoutInited = true;
30568 this.fireEvent('layout', this);
30572 _resetLayout : function()
30574 if(this.isHorizontal){
30575 this.horizontalMeasureColumns();
30579 this.verticalMeasureColumns();
30583 verticalMeasureColumns : function()
30585 this.getContainerWidth();
30587 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30588 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30592 var boxWidth = this.boxWidth + this.padWidth;
30594 if(this.containerWidth < this.boxWidth){
30595 boxWidth = this.containerWidth
30598 var containerWidth = this.containerWidth;
30600 var cols = Math.floor(containerWidth / boxWidth);
30602 this.cols = Math.max( cols, 1 );
30604 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30606 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30608 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30610 this.colWidth = boxWidth + avail - this.padWidth;
30612 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30613 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30616 horizontalMeasureColumns : function()
30618 this.getContainerWidth();
30620 var boxWidth = this.boxWidth;
30622 if(this.containerWidth < boxWidth){
30623 boxWidth = this.containerWidth;
30626 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30628 this.el.setHeight(boxWidth);
30632 getContainerWidth : function()
30634 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30637 layoutItems : function( isInstant )
30639 Roo.log(this.bricks);
30641 var items = Roo.apply([], this.bricks);
30643 if(this.isHorizontal){
30644 this._horizontalLayoutItems( items , isInstant );
30648 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30649 // this._verticalAlternativeLayoutItems( items , isInstant );
30653 this._verticalLayoutItems( items , isInstant );
30657 _verticalLayoutItems : function ( items , isInstant)
30659 if ( !items || !items.length ) {
30664 ['xs', 'xs', 'xs', 'tall'],
30665 ['xs', 'xs', 'tall'],
30666 ['xs', 'xs', 'sm'],
30667 ['xs', 'xs', 'xs'],
30673 ['sm', 'xs', 'xs'],
30677 ['tall', 'xs', 'xs', 'xs'],
30678 ['tall', 'xs', 'xs'],
30690 Roo.each(items, function(item, k){
30692 switch (item.size) {
30693 // these layouts take up a full box,
30704 boxes.push([item]);
30727 var filterPattern = function(box, length)
30735 var pattern = box.slice(0, length);
30739 Roo.each(pattern, function(i){
30740 format.push(i.size);
30743 Roo.each(standard, function(s){
30745 if(String(s) != String(format)){
30754 if(!match && length == 1){
30759 filterPattern(box, length - 1);
30763 queue.push(pattern);
30765 box = box.slice(length, box.length);
30767 filterPattern(box, 4);
30773 Roo.each(boxes, function(box, k){
30779 if(box.length == 1){
30784 filterPattern(box, 4);
30788 this._processVerticalLayoutQueue( queue, isInstant );
30792 // _verticalAlternativeLayoutItems : function( items , isInstant )
30794 // if ( !items || !items.length ) {
30798 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30802 _horizontalLayoutItems : function ( items , isInstant)
30804 if ( !items || !items.length || items.length < 3) {
30810 var eItems = items.slice(0, 3);
30812 items = items.slice(3, items.length);
30815 ['xs', 'xs', 'xs', 'wide'],
30816 ['xs', 'xs', 'wide'],
30817 ['xs', 'xs', 'sm'],
30818 ['xs', 'xs', 'xs'],
30824 ['sm', 'xs', 'xs'],
30828 ['wide', 'xs', 'xs', 'xs'],
30829 ['wide', 'xs', 'xs'],
30842 Roo.each(items, function(item, k){
30844 switch (item.size) {
30855 boxes.push([item]);
30879 var filterPattern = function(box, length)
30887 var pattern = box.slice(0, length);
30891 Roo.each(pattern, function(i){
30892 format.push(i.size);
30895 Roo.each(standard, function(s){
30897 if(String(s) != String(format)){
30906 if(!match && length == 1){
30911 filterPattern(box, length - 1);
30915 queue.push(pattern);
30917 box = box.slice(length, box.length);
30919 filterPattern(box, 4);
30925 Roo.each(boxes, function(box, k){
30931 if(box.length == 1){
30936 filterPattern(box, 4);
30943 var pos = this.el.getBox(true);
30947 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30949 var hit_end = false;
30951 Roo.each(queue, function(box){
30955 Roo.each(box, function(b){
30957 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30967 Roo.each(box, function(b){
30969 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30972 mx = Math.max(mx, b.x);
30976 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30980 Roo.each(box, function(b){
30982 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30996 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30999 /** Sets position of item in DOM
31000 * @param {Element} item
31001 * @param {Number} x - horizontal position
31002 * @param {Number} y - vertical position
31003 * @param {Boolean} isInstant - disables transitions
31005 _processVerticalLayoutQueue : function( queue, isInstant )
31007 var pos = this.el.getBox(true);
31012 for (var i = 0; i < this.cols; i++){
31016 Roo.each(queue, function(box, k){
31018 var col = k % this.cols;
31020 Roo.each(box, function(b,kk){
31022 b.el.position('absolute');
31024 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31025 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31027 if(b.size == 'md-left' || b.size == 'md-right'){
31028 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31029 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31032 b.el.setWidth(width);
31033 b.el.setHeight(height);
31035 b.el.select('iframe',true).setSize(width,height);
31039 for (var i = 0; i < this.cols; i++){
31041 if(maxY[i] < maxY[col]){
31046 col = Math.min(col, i);
31050 x = pos.x + col * (this.colWidth + this.padWidth);
31054 var positions = [];
31056 switch (box.length){
31058 positions = this.getVerticalOneBoxColPositions(x, y, box);
31061 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31064 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31067 positions = this.getVerticalFourBoxColPositions(x, y, box);
31073 Roo.each(box, function(b,kk){
31075 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31077 var sz = b.el.getSize();
31079 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31087 for (var i = 0; i < this.cols; i++){
31088 mY = Math.max(mY, maxY[i]);
31091 this.el.setHeight(mY - pos.y);
31095 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31097 // var pos = this.el.getBox(true);
31100 // var maxX = pos.right;
31102 // var maxHeight = 0;
31104 // Roo.each(items, function(item, k){
31108 // item.el.position('absolute');
31110 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31112 // item.el.setWidth(width);
31114 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31116 // item.el.setHeight(height);
31119 // item.el.setXY([x, y], isInstant ? false : true);
31121 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31124 // y = y + height + this.alternativePadWidth;
31126 // maxHeight = maxHeight + height + this.alternativePadWidth;
31130 // this.el.setHeight(maxHeight);
31134 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31136 var pos = this.el.getBox(true);
31141 var maxX = pos.right;
31143 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31145 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31147 Roo.each(queue, function(box, k){
31149 Roo.each(box, function(b, kk){
31151 b.el.position('absolute');
31153 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31154 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31156 if(b.size == 'md-left' || b.size == 'md-right'){
31157 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31158 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31161 b.el.setWidth(width);
31162 b.el.setHeight(height);
31170 var positions = [];
31172 switch (box.length){
31174 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31177 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31180 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31183 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31189 Roo.each(box, function(b,kk){
31191 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31193 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31201 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31203 Roo.each(eItems, function(b,k){
31205 b.size = (k == 0) ? 'sm' : 'xs';
31206 b.x = (k == 0) ? 2 : 1;
31207 b.y = (k == 0) ? 2 : 1;
31209 b.el.position('absolute');
31211 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31213 b.el.setWidth(width);
31215 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31217 b.el.setHeight(height);
31221 var positions = [];
31224 x : maxX - this.unitWidth * 2 - this.gutter,
31229 x : maxX - this.unitWidth,
31230 y : minY + (this.unitWidth + this.gutter) * 2
31234 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31238 Roo.each(eItems, function(b,k){
31240 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31246 getVerticalOneBoxColPositions : function(x, y, box)
31250 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31252 if(box[0].size == 'md-left'){
31256 if(box[0].size == 'md-right'){
31261 x : x + (this.unitWidth + this.gutter) * rand,
31268 getVerticalTwoBoxColPositions : function(x, y, box)
31272 if(box[0].size == 'xs'){
31276 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31280 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31294 x : x + (this.unitWidth + this.gutter) * 2,
31295 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31302 getVerticalThreeBoxColPositions : function(x, y, box)
31306 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31314 x : x + (this.unitWidth + this.gutter) * 1,
31319 x : x + (this.unitWidth + this.gutter) * 2,
31327 if(box[0].size == 'xs' && box[1].size == 'xs'){
31336 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31340 x : x + (this.unitWidth + this.gutter) * 1,
31354 x : x + (this.unitWidth + this.gutter) * 2,
31359 x : x + (this.unitWidth + this.gutter) * 2,
31360 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31367 getVerticalFourBoxColPositions : function(x, y, box)
31371 if(box[0].size == 'xs'){
31380 y : y + (this.unitHeight + this.gutter) * 1
31385 y : y + (this.unitHeight + this.gutter) * 2
31389 x : x + (this.unitWidth + this.gutter) * 1,
31403 x : x + (this.unitWidth + this.gutter) * 2,
31408 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31409 y : y + (this.unitHeight + this.gutter) * 1
31413 x : x + (this.unitWidth + this.gutter) * 2,
31414 y : y + (this.unitWidth + this.gutter) * 2
31421 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31425 if(box[0].size == 'md-left'){
31427 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31434 if(box[0].size == 'md-right'){
31436 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31437 y : minY + (this.unitWidth + this.gutter) * 1
31443 var rand = Math.floor(Math.random() * (4 - box[0].y));
31446 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31447 y : minY + (this.unitWidth + this.gutter) * rand
31454 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31458 if(box[0].size == 'xs'){
31461 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31466 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31467 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31475 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31480 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31481 y : minY + (this.unitWidth + this.gutter) * 2
31488 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31492 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31495 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31500 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31501 y : minY + (this.unitWidth + this.gutter) * 1
31505 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31506 y : minY + (this.unitWidth + this.gutter) * 2
31513 if(box[0].size == 'xs' && box[1].size == 'xs'){
31516 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31521 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31526 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31527 y : minY + (this.unitWidth + this.gutter) * 1
31535 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31540 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31541 y : minY + (this.unitWidth + this.gutter) * 2
31545 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31546 y : minY + (this.unitWidth + this.gutter) * 2
31553 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31557 if(box[0].size == 'xs'){
31560 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31565 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31570 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),
31575 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31576 y : minY + (this.unitWidth + this.gutter) * 1
31584 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31589 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31590 y : minY + (this.unitWidth + this.gutter) * 2
31594 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31595 y : minY + (this.unitWidth + this.gutter) * 2
31599 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),
31600 y : minY + (this.unitWidth + this.gutter) * 2
31608 * remove a Masonry Brick
31609 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31611 removeBrick : function(brick_id)
31617 for (var i = 0; i<this.bricks.length; i++) {
31618 if (this.bricks[i].id == brick_id) {
31619 this.bricks.splice(i,1);
31620 this.el.dom.removeChild(Roo.get(brick_id).dom);
31627 * adds a Masonry Brick
31628 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31630 addBrick : function(cfg)
31632 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31633 //this.register(cn);
31634 cn.parentId = this.id;
31635 cn.onRender(this.el, null);
31640 * register a Masonry Brick
31641 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31644 register : function(brick)
31646 this.bricks.push(brick);
31647 brick.masonryId = this.id;
31651 * clear all the Masonry Brick
31653 clearAll : function()
31656 //this.getChildContainer().dom.innerHTML = "";
31657 this.el.dom.innerHTML = '';
31660 getSelected : function()
31662 if (!this.selectedBrick) {
31666 return this.selectedBrick;
31670 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31674 * register a Masonry Layout
31675 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31678 register : function(layout)
31680 this.groups[layout.id] = layout;
31683 * fetch a Masonry Layout based on the masonry layout ID
31684 * @param {string} the masonry layout to add
31685 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31688 get: function(layout_id) {
31689 if (typeof(this.groups[layout_id]) == 'undefined') {
31692 return this.groups[layout_id] ;
31704 * http://masonry.desandro.com
31706 * The idea is to render all the bricks based on vertical width...
31708 * The original code extends 'outlayer' - we might need to use that....
31714 * @class Roo.bootstrap.LayoutMasonryAuto
31715 * @extends Roo.bootstrap.Component
31716 * Bootstrap Layout Masonry class
31719 * Create a new Element
31720 * @param {Object} config The config object
31723 Roo.bootstrap.LayoutMasonryAuto = function(config){
31724 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31727 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31730 * @cfg {Boolean} isFitWidth - resize the width..
31732 isFitWidth : false, // options..
31734 * @cfg {Boolean} isOriginLeft = left align?
31736 isOriginLeft : true,
31738 * @cfg {Boolean} isOriginTop = top align?
31740 isOriginTop : false,
31742 * @cfg {Boolean} isLayoutInstant = no animation?
31744 isLayoutInstant : false, // needed?
31746 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31748 isResizingContainer : true,
31750 * @cfg {Number} columnWidth width of the columns
31756 * @cfg {Number} maxCols maximum number of columns
31761 * @cfg {Number} padHeight padding below box..
31767 * @cfg {Boolean} isAutoInitial defalut true
31770 isAutoInitial : true,
31776 initialColumnWidth : 0,
31777 currentSize : null,
31779 colYs : null, // array.
31786 bricks: null, //CompositeElement
31787 cols : 0, // array?
31788 // element : null, // wrapped now this.el
31789 _isLayoutInited : null,
31792 getAutoCreate : function(){
31796 cls: 'blog-masonary-wrapper ' + this.cls,
31798 cls : 'mas-boxes masonary'
31805 getChildContainer: function( )
31807 if (this.boxesEl) {
31808 return this.boxesEl;
31811 this.boxesEl = this.el.select('.mas-boxes').first();
31813 return this.boxesEl;
31817 initEvents : function()
31821 if(this.isAutoInitial){
31822 Roo.log('hook children rendered');
31823 this.on('childrenrendered', function() {
31824 Roo.log('children rendered');
31831 initial : function()
31833 this.reloadItems();
31835 this.currentSize = this.el.getBox(true);
31837 /// was window resize... - let's see if this works..
31838 Roo.EventManager.onWindowResize(this.resize, this);
31840 if(!this.isAutoInitial){
31845 this.layout.defer(500,this);
31848 reloadItems: function()
31850 this.bricks = this.el.select('.masonry-brick', true);
31852 this.bricks.each(function(b) {
31853 //Roo.log(b.getSize());
31854 if (!b.attr('originalwidth')) {
31855 b.attr('originalwidth', b.getSize().width);
31860 Roo.log(this.bricks.elements.length);
31863 resize : function()
31866 var cs = this.el.getBox(true);
31868 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31869 Roo.log("no change in with or X");
31872 this.currentSize = cs;
31876 layout : function()
31879 this._resetLayout();
31880 //this._manageStamps();
31882 // don't animate first layout
31883 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31884 this.layoutItems( isInstant );
31886 // flag for initalized
31887 this._isLayoutInited = true;
31890 layoutItems : function( isInstant )
31892 //var items = this._getItemsForLayout( this.items );
31893 // original code supports filtering layout items.. we just ignore it..
31895 this._layoutItems( this.bricks , isInstant );
31897 this._postLayout();
31899 _layoutItems : function ( items , isInstant)
31901 //this.fireEvent( 'layout', this, items );
31904 if ( !items || !items.elements.length ) {
31905 // no items, emit event with empty array
31910 items.each(function(item) {
31911 Roo.log("layout item");
31913 // get x/y object from method
31914 var position = this._getItemLayoutPosition( item );
31916 position.item = item;
31917 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31918 queue.push( position );
31921 this._processLayoutQueue( queue );
31923 /** Sets position of item in DOM
31924 * @param {Element} item
31925 * @param {Number} x - horizontal position
31926 * @param {Number} y - vertical position
31927 * @param {Boolean} isInstant - disables transitions
31929 _processLayoutQueue : function( queue )
31931 for ( var i=0, len = queue.length; i < len; i++ ) {
31932 var obj = queue[i];
31933 obj.item.position('absolute');
31934 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31940 * Any logic you want to do after each layout,
31941 * i.e. size the container
31943 _postLayout : function()
31945 this.resizeContainer();
31948 resizeContainer : function()
31950 if ( !this.isResizingContainer ) {
31953 var size = this._getContainerSize();
31955 this.el.setSize(size.width,size.height);
31956 this.boxesEl.setSize(size.width,size.height);
31962 _resetLayout : function()
31964 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31965 this.colWidth = this.el.getWidth();
31966 //this.gutter = this.el.getWidth();
31968 this.measureColumns();
31974 this.colYs.push( 0 );
31980 measureColumns : function()
31982 this.getContainerWidth();
31983 // if columnWidth is 0, default to outerWidth of first item
31984 if ( !this.columnWidth ) {
31985 var firstItem = this.bricks.first();
31986 Roo.log(firstItem);
31987 this.columnWidth = this.containerWidth;
31988 if (firstItem && firstItem.attr('originalwidth') ) {
31989 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31991 // columnWidth fall back to item of first element
31992 Roo.log("set column width?");
31993 this.initialColumnWidth = this.columnWidth ;
31995 // if first elem has no width, default to size of container
32000 if (this.initialColumnWidth) {
32001 this.columnWidth = this.initialColumnWidth;
32006 // column width is fixed at the top - however if container width get's smaller we should
32009 // this bit calcs how man columns..
32011 var columnWidth = this.columnWidth += this.gutter;
32013 // calculate columns
32014 var containerWidth = this.containerWidth + this.gutter;
32016 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32017 // fix rounding errors, typically with gutters
32018 var excess = columnWidth - containerWidth % columnWidth;
32021 // if overshoot is less than a pixel, round up, otherwise floor it
32022 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32023 cols = Math[ mathMethod ]( cols );
32024 this.cols = Math.max( cols, 1 );
32025 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32027 // padding positioning..
32028 var totalColWidth = this.cols * this.columnWidth;
32029 var padavail = this.containerWidth - totalColWidth;
32030 // so for 2 columns - we need 3 'pads'
32032 var padNeeded = (1+this.cols) * this.padWidth;
32034 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32036 this.columnWidth += padExtra
32037 //this.padWidth = Math.floor(padavail / ( this.cols));
32039 // adjust colum width so that padding is fixed??
32041 // we have 3 columns ... total = width * 3
32042 // we have X left over... that should be used by
32044 //if (this.expandC) {
32052 getContainerWidth : function()
32054 /* // container is parent if fit width
32055 var container = this.isFitWidth ? this.element.parentNode : this.element;
32056 // check that this.size and size are there
32057 // IE8 triggers resize on body size change, so they might not be
32059 var size = getSize( container ); //FIXME
32060 this.containerWidth = size && size.innerWidth; //FIXME
32063 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32067 _getItemLayoutPosition : function( item ) // what is item?
32069 // we resize the item to our columnWidth..
32071 item.setWidth(this.columnWidth);
32072 item.autoBoxAdjust = false;
32074 var sz = item.getSize();
32076 // how many columns does this brick span
32077 var remainder = this.containerWidth % this.columnWidth;
32079 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32080 // round if off by 1 pixel, otherwise use ceil
32081 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32082 colSpan = Math.min( colSpan, this.cols );
32084 // normally this should be '1' as we dont' currently allow multi width columns..
32086 var colGroup = this._getColGroup( colSpan );
32087 // get the minimum Y value from the columns
32088 var minimumY = Math.min.apply( Math, colGroup );
32089 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32091 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32093 // position the brick
32095 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32096 y: this.currentSize.y + minimumY + this.padHeight
32100 // apply setHeight to necessary columns
32101 var setHeight = minimumY + sz.height + this.padHeight;
32102 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32104 var setSpan = this.cols + 1 - colGroup.length;
32105 for ( var i = 0; i < setSpan; i++ ) {
32106 this.colYs[ shortColIndex + i ] = setHeight ;
32113 * @param {Number} colSpan - number of columns the element spans
32114 * @returns {Array} colGroup
32116 _getColGroup : function( colSpan )
32118 if ( colSpan < 2 ) {
32119 // if brick spans only one column, use all the column Ys
32124 // how many different places could this brick fit horizontally
32125 var groupCount = this.cols + 1 - colSpan;
32126 // for each group potential horizontal position
32127 for ( var i = 0; i < groupCount; i++ ) {
32128 // make an array of colY values for that one group
32129 var groupColYs = this.colYs.slice( i, i + colSpan );
32130 // and get the max value of the array
32131 colGroup[i] = Math.max.apply( Math, groupColYs );
32136 _manageStamp : function( stamp )
32138 var stampSize = stamp.getSize();
32139 var offset = stamp.getBox();
32140 // get the columns that this stamp affects
32141 var firstX = this.isOriginLeft ? offset.x : offset.right;
32142 var lastX = firstX + stampSize.width;
32143 var firstCol = Math.floor( firstX / this.columnWidth );
32144 firstCol = Math.max( 0, firstCol );
32146 var lastCol = Math.floor( lastX / this.columnWidth );
32147 // lastCol should not go over if multiple of columnWidth #425
32148 lastCol -= lastX % this.columnWidth ? 0 : 1;
32149 lastCol = Math.min( this.cols - 1, lastCol );
32151 // set colYs to bottom of the stamp
32152 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32155 for ( var i = firstCol; i <= lastCol; i++ ) {
32156 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32161 _getContainerSize : function()
32163 this.maxY = Math.max.apply( Math, this.colYs );
32168 if ( this.isFitWidth ) {
32169 size.width = this._getContainerFitWidth();
32175 _getContainerFitWidth : function()
32177 var unusedCols = 0;
32178 // count unused columns
32181 if ( this.colYs[i] !== 0 ) {
32186 // fit container to columns that have been used
32187 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32190 needsResizeLayout : function()
32192 var previousWidth = this.containerWidth;
32193 this.getContainerWidth();
32194 return previousWidth !== this.containerWidth;
32209 * @class Roo.bootstrap.MasonryBrick
32210 * @extends Roo.bootstrap.Component
32211 * Bootstrap MasonryBrick class
32214 * Create a new MasonryBrick
32215 * @param {Object} config The config object
32218 Roo.bootstrap.MasonryBrick = function(config){
32220 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32222 Roo.bootstrap.MasonryBrick.register(this);
32228 * When a MasonryBrick is clcik
32229 * @param {Roo.bootstrap.MasonryBrick} this
32230 * @param {Roo.EventObject} e
32236 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32239 * @cfg {String} title
32243 * @cfg {String} html
32247 * @cfg {String} bgimage
32251 * @cfg {String} videourl
32255 * @cfg {String} cls
32259 * @cfg {String} href
32263 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32268 * @cfg {String} placetitle (center|bottom)
32273 * @cfg {Boolean} isFitContainer defalut true
32275 isFitContainer : true,
32278 * @cfg {Boolean} preventDefault defalut false
32280 preventDefault : false,
32283 * @cfg {Boolean} inverse defalut false
32285 maskInverse : false,
32287 getAutoCreate : function()
32289 if(!this.isFitContainer){
32290 return this.getSplitAutoCreate();
32293 var cls = 'masonry-brick masonry-brick-full';
32295 if(this.href.length){
32296 cls += ' masonry-brick-link';
32299 if(this.bgimage.length){
32300 cls += ' masonry-brick-image';
32303 if(this.maskInverse){
32304 cls += ' mask-inverse';
32307 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32308 cls += ' enable-mask';
32312 cls += ' masonry-' + this.size + '-brick';
32315 if(this.placetitle.length){
32317 switch (this.placetitle) {
32319 cls += ' masonry-center-title';
32322 cls += ' masonry-bottom-title';
32329 if(!this.html.length && !this.bgimage.length){
32330 cls += ' masonry-center-title';
32333 if(!this.html.length && this.bgimage.length){
32334 cls += ' masonry-bottom-title';
32339 cls += ' ' + this.cls;
32343 tag: (this.href.length) ? 'a' : 'div',
32348 cls: 'masonry-brick-mask'
32352 cls: 'masonry-brick-paragraph',
32358 if(this.href.length){
32359 cfg.href = this.href;
32362 var cn = cfg.cn[1].cn;
32364 if(this.title.length){
32367 cls: 'masonry-brick-title',
32372 if(this.html.length){
32375 cls: 'masonry-brick-text',
32380 if (!this.title.length && !this.html.length) {
32381 cfg.cn[1].cls += ' hide';
32384 if(this.bgimage.length){
32387 cls: 'masonry-brick-image-view',
32392 if(this.videourl.length){
32393 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32394 // youtube support only?
32397 cls: 'masonry-brick-image-view',
32400 allowfullscreen : true
32408 getSplitAutoCreate : function()
32410 var cls = 'masonry-brick masonry-brick-split';
32412 if(this.href.length){
32413 cls += ' masonry-brick-link';
32416 if(this.bgimage.length){
32417 cls += ' masonry-brick-image';
32421 cls += ' masonry-' + this.size + '-brick';
32424 switch (this.placetitle) {
32426 cls += ' masonry-center-title';
32429 cls += ' masonry-bottom-title';
32432 if(!this.bgimage.length){
32433 cls += ' masonry-center-title';
32436 if(this.bgimage.length){
32437 cls += ' masonry-bottom-title';
32443 cls += ' ' + this.cls;
32447 tag: (this.href.length) ? 'a' : 'div',
32452 cls: 'masonry-brick-split-head',
32456 cls: 'masonry-brick-paragraph',
32463 cls: 'masonry-brick-split-body',
32469 if(this.href.length){
32470 cfg.href = this.href;
32473 if(this.title.length){
32474 cfg.cn[0].cn[0].cn.push({
32476 cls: 'masonry-brick-title',
32481 if(this.html.length){
32482 cfg.cn[1].cn.push({
32484 cls: 'masonry-brick-text',
32489 if(this.bgimage.length){
32490 cfg.cn[0].cn.push({
32492 cls: 'masonry-brick-image-view',
32497 if(this.videourl.length){
32498 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32499 // youtube support only?
32500 cfg.cn[0].cn.cn.push({
32502 cls: 'masonry-brick-image-view',
32505 allowfullscreen : true
32512 initEvents: function()
32514 switch (this.size) {
32547 this.el.on('touchstart', this.onTouchStart, this);
32548 this.el.on('touchmove', this.onTouchMove, this);
32549 this.el.on('touchend', this.onTouchEnd, this);
32550 this.el.on('contextmenu', this.onContextMenu, this);
32552 this.el.on('mouseenter' ,this.enter, this);
32553 this.el.on('mouseleave', this.leave, this);
32554 this.el.on('click', this.onClick, this);
32557 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32558 this.parent().bricks.push(this);
32563 onClick: function(e, el)
32565 var time = this.endTimer - this.startTimer;
32566 // Roo.log(e.preventDefault());
32569 e.preventDefault();
32574 if(!this.preventDefault){
32578 e.preventDefault();
32580 if (this.activcClass != '') {
32581 this.selectBrick();
32584 this.fireEvent('click', this);
32587 enter: function(e, el)
32589 e.preventDefault();
32591 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32595 if(this.bgimage.length && this.html.length){
32596 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32600 leave: function(e, el)
32602 e.preventDefault();
32604 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32608 if(this.bgimage.length && this.html.length){
32609 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32613 onTouchStart: function(e, el)
32615 // e.preventDefault();
32617 this.touchmoved = false;
32619 if(!this.isFitContainer){
32623 if(!this.bgimage.length || !this.html.length){
32627 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32629 this.timer = new Date().getTime();
32633 onTouchMove: function(e, el)
32635 this.touchmoved = true;
32638 onContextMenu : function(e,el)
32640 e.preventDefault();
32641 e.stopPropagation();
32645 onTouchEnd: function(e, el)
32647 // e.preventDefault();
32649 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32656 if(!this.bgimage.length || !this.html.length){
32658 if(this.href.length){
32659 window.location.href = this.href;
32665 if(!this.isFitContainer){
32669 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32671 window.location.href = this.href;
32674 //selection on single brick only
32675 selectBrick : function() {
32677 if (!this.parentId) {
32681 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32682 var index = m.selectedBrick.indexOf(this.id);
32685 m.selectedBrick.splice(index,1);
32686 this.el.removeClass(this.activeClass);
32690 for(var i = 0; i < m.selectedBrick.length; i++) {
32691 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32692 b.el.removeClass(b.activeClass);
32695 m.selectedBrick = [];
32697 m.selectedBrick.push(this.id);
32698 this.el.addClass(this.activeClass);
32704 Roo.apply(Roo.bootstrap.MasonryBrick, {
32707 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32709 * register a Masonry Brick
32710 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32713 register : function(brick)
32715 //this.groups[brick.id] = brick;
32716 this.groups.add(brick.id, brick);
32719 * fetch a masonry brick based on the masonry brick ID
32720 * @param {string} the masonry brick to add
32721 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32724 get: function(brick_id)
32726 // if (typeof(this.groups[brick_id]) == 'undefined') {
32729 // return this.groups[brick_id] ;
32731 if(this.groups.key(brick_id)) {
32732 return this.groups.key(brick_id);
32750 * @class Roo.bootstrap.Brick
32751 * @extends Roo.bootstrap.Component
32752 * Bootstrap Brick class
32755 * Create a new Brick
32756 * @param {Object} config The config object
32759 Roo.bootstrap.Brick = function(config){
32760 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32766 * When a Brick is click
32767 * @param {Roo.bootstrap.Brick} this
32768 * @param {Roo.EventObject} e
32774 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32777 * @cfg {String} title
32781 * @cfg {String} html
32785 * @cfg {String} bgimage
32789 * @cfg {String} cls
32793 * @cfg {String} href
32797 * @cfg {String} video
32801 * @cfg {Boolean} square
32805 getAutoCreate : function()
32807 var cls = 'roo-brick';
32809 if(this.href.length){
32810 cls += ' roo-brick-link';
32813 if(this.bgimage.length){
32814 cls += ' roo-brick-image';
32817 if(!this.html.length && !this.bgimage.length){
32818 cls += ' roo-brick-center-title';
32821 if(!this.html.length && this.bgimage.length){
32822 cls += ' roo-brick-bottom-title';
32826 cls += ' ' + this.cls;
32830 tag: (this.href.length) ? 'a' : 'div',
32835 cls: 'roo-brick-paragraph',
32841 if(this.href.length){
32842 cfg.href = this.href;
32845 var cn = cfg.cn[0].cn;
32847 if(this.title.length){
32850 cls: 'roo-brick-title',
32855 if(this.html.length){
32858 cls: 'roo-brick-text',
32865 if(this.bgimage.length){
32868 cls: 'roo-brick-image-view',
32876 initEvents: function()
32878 if(this.title.length || this.html.length){
32879 this.el.on('mouseenter' ,this.enter, this);
32880 this.el.on('mouseleave', this.leave, this);
32883 Roo.EventManager.onWindowResize(this.resize, this);
32885 if(this.bgimage.length){
32886 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32887 this.imageEl.on('load', this.onImageLoad, this);
32894 onImageLoad : function()
32899 resize : function()
32901 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32903 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32905 if(this.bgimage.length){
32906 var image = this.el.select('.roo-brick-image-view', true).first();
32908 image.setWidth(paragraph.getWidth());
32911 image.setHeight(paragraph.getWidth());
32914 this.el.setHeight(image.getHeight());
32915 paragraph.setHeight(image.getHeight());
32921 enter: function(e, el)
32923 e.preventDefault();
32925 if(this.bgimage.length){
32926 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32927 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32931 leave: function(e, el)
32933 e.preventDefault();
32935 if(this.bgimage.length){
32936 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32937 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32953 * @class Roo.bootstrap.NumberField
32954 * @extends Roo.bootstrap.Input
32955 * Bootstrap NumberField class
32961 * Create a new NumberField
32962 * @param {Object} config The config object
32965 Roo.bootstrap.NumberField = function(config){
32966 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32969 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32972 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32974 allowDecimals : true,
32976 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32978 decimalSeparator : ".",
32980 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32982 decimalPrecision : 2,
32984 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32986 allowNegative : true,
32988 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32990 minValue : Number.NEGATIVE_INFINITY,
32992 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32994 maxValue : Number.MAX_VALUE,
32996 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32998 minText : "The minimum value for this field is {0}",
33000 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33002 maxText : "The maximum value for this field is {0}",
33004 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33005 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33007 nanText : "{0} is not a valid number",
33009 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33014 initEvents : function()
33016 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33018 var allowed = "0123456789";
33020 if(this.allowDecimals){
33021 allowed += this.decimalSeparator;
33024 if(this.allowNegative){
33028 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33030 var keyPress = function(e){
33032 var k = e.getKey();
33034 var c = e.getCharCode();
33037 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33038 allowed.indexOf(String.fromCharCode(c)) === -1
33044 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33048 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33053 this.el.on("keypress", keyPress, this);
33056 validateValue : function(value)
33059 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33063 var num = this.parseValue(value);
33066 this.markInvalid(String.format(this.nanText, value));
33070 if(num < this.minValue){
33071 this.markInvalid(String.format(this.minText, this.minValue));
33075 if(num > this.maxValue){
33076 this.markInvalid(String.format(this.maxText, this.maxValue));
33083 getValue : function()
33085 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33088 parseValue : function(value)
33090 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33091 return isNaN(value) ? '' : value;
33094 fixPrecision : function(value)
33096 var nan = isNaN(value);
33098 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33099 return nan ? '' : value;
33101 return parseFloat(value).toFixed(this.decimalPrecision);
33104 setValue : function(v)
33106 v = this.fixPrecision(v);
33107 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33110 decimalPrecisionFcn : function(v)
33112 return Math.floor(v);
33115 beforeBlur : function()
33121 var v = this.parseValue(this.getRawValue());
33136 * @class Roo.bootstrap.DocumentSlider
33137 * @extends Roo.bootstrap.Component
33138 * Bootstrap DocumentSlider class
33141 * Create a new DocumentViewer
33142 * @param {Object} config The config object
33145 Roo.bootstrap.DocumentSlider = function(config){
33146 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33153 * Fire after initEvent
33154 * @param {Roo.bootstrap.DocumentSlider} this
33159 * Fire after update
33160 * @param {Roo.bootstrap.DocumentSlider} this
33166 * @param {Roo.bootstrap.DocumentSlider} this
33172 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33178 getAutoCreate : function()
33182 cls : 'roo-document-slider',
33186 cls : 'roo-document-slider-header',
33190 cls : 'roo-document-slider-header-title'
33196 cls : 'roo-document-slider-body',
33200 cls : 'roo-document-slider-prev',
33204 cls : 'fa fa-chevron-left'
33210 cls : 'roo-document-slider-thumb',
33214 cls : 'roo-document-slider-image'
33220 cls : 'roo-document-slider-next',
33224 cls : 'fa fa-chevron-right'
33236 initEvents : function()
33238 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33239 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33241 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33242 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33244 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33245 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33247 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33248 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33250 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33251 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33253 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33254 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33256 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33257 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33259 this.thumbEl.on('click', this.onClick, this);
33261 this.prevIndicator.on('click', this.prev, this);
33263 this.nextIndicator.on('click', this.next, this);
33267 initial : function()
33269 if(this.files.length){
33270 this.indicator = 1;
33274 this.fireEvent('initial', this);
33277 update : function()
33279 this.imageEl.attr('src', this.files[this.indicator - 1]);
33281 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33283 this.prevIndicator.show();
33285 if(this.indicator == 1){
33286 this.prevIndicator.hide();
33289 this.nextIndicator.show();
33291 if(this.indicator == this.files.length){
33292 this.nextIndicator.hide();
33295 this.thumbEl.scrollTo('top');
33297 this.fireEvent('update', this);
33300 onClick : function(e)
33302 e.preventDefault();
33304 this.fireEvent('click', this);
33309 e.preventDefault();
33311 this.indicator = Math.max(1, this.indicator - 1);
33318 e.preventDefault();
33320 this.indicator = Math.min(this.files.length, this.indicator + 1);
33334 * @class Roo.bootstrap.RadioSet
33335 * @extends Roo.bootstrap.Input
33336 * Bootstrap RadioSet class
33337 * @cfg {String} indicatorpos (left|right) default left
33338 * @cfg {Boolean} inline (true|false) inline the element (default true)
33339 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33341 * Create a new RadioSet
33342 * @param {Object} config The config object
33345 Roo.bootstrap.RadioSet = function(config){
33347 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33351 Roo.bootstrap.RadioSet.register(this);
33356 * Fires when the element is checked or unchecked.
33357 * @param {Roo.bootstrap.RadioSet} this This radio
33358 * @param {Roo.bootstrap.Radio} item The checked item
33365 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33373 indicatorpos : 'left',
33375 getAutoCreate : function()
33379 cls : 'roo-radio-set-label',
33383 html : this.fieldLabel
33388 if(this.indicatorpos == 'left'){
33391 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33392 tooltip : 'This field is required'
33397 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33398 tooltip : 'This field is required'
33404 cls : 'roo-radio-set-items'
33407 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33409 if (align === 'left' && this.fieldLabel.length) {
33412 cls : "roo-radio-set-right",
33418 if(this.labelWidth > 12){
33419 label.style = "width: " + this.labelWidth + 'px';
33422 if(this.labelWidth < 13 && this.labelmd == 0){
33423 this.labelmd = this.labelWidth;
33426 if(this.labellg > 0){
33427 label.cls += ' col-lg-' + this.labellg;
33428 items.cls += ' col-lg-' + (12 - this.labellg);
33431 if(this.labelmd > 0){
33432 label.cls += ' col-md-' + this.labelmd;
33433 items.cls += ' col-md-' + (12 - this.labelmd);
33436 if(this.labelsm > 0){
33437 label.cls += ' col-sm-' + this.labelsm;
33438 items.cls += ' col-sm-' + (12 - this.labelsm);
33441 if(this.labelxs > 0){
33442 label.cls += ' col-xs-' + this.labelxs;
33443 items.cls += ' col-xs-' + (12 - this.labelxs);
33449 cls : 'roo-radio-set',
33453 cls : 'roo-radio-set-input',
33456 value : this.value ? this.value : ''
33463 if(this.weight.length){
33464 cfg.cls += ' roo-radio-' + this.weight;
33468 cfg.cls += ' roo-radio-set-inline';
33472 ['xs','sm','md','lg'].map(function(size){
33473 if (settings[size]) {
33474 cfg.cls += ' col-' + size + '-' + settings[size];
33482 initEvents : function()
33484 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33485 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33487 if(!this.fieldLabel.length){
33488 this.labelEl.hide();
33491 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33492 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33494 this.indicatorEl().addClass('invisible');
33496 this.originalValue = this.getValue();
33500 inputEl: function ()
33502 return this.el.select('.roo-radio-set-input', true).first();
33505 getChildContainer : function()
33507 return this.itemsEl;
33510 register : function(item)
33512 this.radioes.push(item);
33516 validate : function()
33520 Roo.each(this.radioes, function(i){
33529 if(this.allowBlank) {
33533 if(this.disabled || valid){
33538 this.markInvalid();
33543 markValid : function()
33545 if(this.labelEl.isVisible(true)){
33546 this.indicatorEl().removeClass('visible');
33547 this.indicatorEl().addClass('invisible');
33550 this.el.removeClass([this.invalidClass, this.validClass]);
33551 this.el.addClass(this.validClass);
33553 this.fireEvent('valid', this);
33556 markInvalid : function(msg)
33558 if(this.allowBlank || this.disabled){
33562 if(this.labelEl.isVisible(true)){
33563 this.indicatorEl().removeClass('invisible');
33564 this.indicatorEl().addClass('visible');
33567 this.el.removeClass([this.invalidClass, this.validClass]);
33568 this.el.addClass(this.invalidClass);
33570 this.fireEvent('invalid', this, msg);
33574 setValue : function(v, suppressEvent)
33576 if(this.value === v){
33583 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33586 Roo.each(this.radioes, function(i){
33589 i.el.removeClass('checked');
33591 if(i.value === v || i.value.toString() === v.toString()){
33593 i.el.addClass('checked');
33595 if(suppressEvent !== true){
33596 this.fireEvent('check', this, i);
33605 clearInvalid : function(){
33607 if(!this.el || this.preventMark){
33611 this.el.removeClass([this.invalidClass]);
33613 this.fireEvent('valid', this);
33618 Roo.apply(Roo.bootstrap.RadioSet, {
33622 register : function(set)
33624 this.groups[set.name] = set;
33627 get: function(name)
33629 if (typeof(this.groups[name]) == 'undefined') {
33633 return this.groups[name] ;
33639 * Ext JS Library 1.1.1
33640 * Copyright(c) 2006-2007, Ext JS, LLC.
33642 * Originally Released Under LGPL - original licence link has changed is not relivant.
33645 * <script type="text/javascript">
33650 * @class Roo.bootstrap.SplitBar
33651 * @extends Roo.util.Observable
33652 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33656 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33657 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33658 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33659 split.minSize = 100;
33660 split.maxSize = 600;
33661 split.animate = true;
33662 split.on('moved', splitterMoved);
33665 * Create a new SplitBar
33666 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33667 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33668 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33669 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33670 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33671 position of the SplitBar).
33673 Roo.bootstrap.SplitBar = function(cfg){
33678 // dragElement : elm
33679 // resizingElement: el,
33681 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33682 // placement : Roo.bootstrap.SplitBar.LEFT ,
33683 // existingProxy ???
33686 this.el = Roo.get(cfg.dragElement, true);
33687 this.el.dom.unselectable = "on";
33689 this.resizingEl = Roo.get(cfg.resizingElement, true);
33693 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33694 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33697 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33700 * The minimum size of the resizing element. (Defaults to 0)
33706 * The maximum size of the resizing element. (Defaults to 2000)
33709 this.maxSize = 2000;
33712 * Whether to animate the transition to the new size
33715 this.animate = false;
33718 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33721 this.useShim = false;
33726 if(!cfg.existingProxy){
33728 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33730 this.proxy = Roo.get(cfg.existingProxy).dom;
33733 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33736 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33739 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33742 this.dragSpecs = {};
33745 * @private The adapter to use to positon and resize elements
33747 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33748 this.adapter.init(this);
33750 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33752 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33753 this.el.addClass("roo-splitbar-h");
33756 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33757 this.el.addClass("roo-splitbar-v");
33763 * Fires when the splitter is moved (alias for {@link #event-moved})
33764 * @param {Roo.bootstrap.SplitBar} this
33765 * @param {Number} newSize the new width or height
33770 * Fires when the splitter is moved
33771 * @param {Roo.bootstrap.SplitBar} this
33772 * @param {Number} newSize the new width or height
33776 * @event beforeresize
33777 * Fires before the splitter is dragged
33778 * @param {Roo.bootstrap.SplitBar} this
33780 "beforeresize" : true,
33782 "beforeapply" : true
33785 Roo.util.Observable.call(this);
33788 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33789 onStartProxyDrag : function(x, y){
33790 this.fireEvent("beforeresize", this);
33792 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33794 o.enableDisplayMode("block");
33795 // all splitbars share the same overlay
33796 Roo.bootstrap.SplitBar.prototype.overlay = o;
33798 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33799 this.overlay.show();
33800 Roo.get(this.proxy).setDisplayed("block");
33801 var size = this.adapter.getElementSize(this);
33802 this.activeMinSize = this.getMinimumSize();;
33803 this.activeMaxSize = this.getMaximumSize();;
33804 var c1 = size - this.activeMinSize;
33805 var c2 = Math.max(this.activeMaxSize - size, 0);
33806 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33807 this.dd.resetConstraints();
33808 this.dd.setXConstraint(
33809 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33810 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33812 this.dd.setYConstraint(0, 0);
33814 this.dd.resetConstraints();
33815 this.dd.setXConstraint(0, 0);
33816 this.dd.setYConstraint(
33817 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33818 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33821 this.dragSpecs.startSize = size;
33822 this.dragSpecs.startPoint = [x, y];
33823 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33827 * @private Called after the drag operation by the DDProxy
33829 onEndProxyDrag : function(e){
33830 Roo.get(this.proxy).setDisplayed(false);
33831 var endPoint = Roo.lib.Event.getXY(e);
33833 this.overlay.hide();
33836 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33837 newSize = this.dragSpecs.startSize +
33838 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33839 endPoint[0] - this.dragSpecs.startPoint[0] :
33840 this.dragSpecs.startPoint[0] - endPoint[0]
33843 newSize = this.dragSpecs.startSize +
33844 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33845 endPoint[1] - this.dragSpecs.startPoint[1] :
33846 this.dragSpecs.startPoint[1] - endPoint[1]
33849 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33850 if(newSize != this.dragSpecs.startSize){
33851 if(this.fireEvent('beforeapply', this, newSize) !== false){
33852 this.adapter.setElementSize(this, newSize);
33853 this.fireEvent("moved", this, newSize);
33854 this.fireEvent("resize", this, newSize);
33860 * Get the adapter this SplitBar uses
33861 * @return The adapter object
33863 getAdapter : function(){
33864 return this.adapter;
33868 * Set the adapter this SplitBar uses
33869 * @param {Object} adapter A SplitBar adapter object
33871 setAdapter : function(adapter){
33872 this.adapter = adapter;
33873 this.adapter.init(this);
33877 * Gets the minimum size for the resizing element
33878 * @return {Number} The minimum size
33880 getMinimumSize : function(){
33881 return this.minSize;
33885 * Sets the minimum size for the resizing element
33886 * @param {Number} minSize The minimum size
33888 setMinimumSize : function(minSize){
33889 this.minSize = minSize;
33893 * Gets the maximum size for the resizing element
33894 * @return {Number} The maximum size
33896 getMaximumSize : function(){
33897 return this.maxSize;
33901 * Sets the maximum size for the resizing element
33902 * @param {Number} maxSize The maximum size
33904 setMaximumSize : function(maxSize){
33905 this.maxSize = maxSize;
33909 * Sets the initialize size for the resizing element
33910 * @param {Number} size The initial size
33912 setCurrentSize : function(size){
33913 var oldAnimate = this.animate;
33914 this.animate = false;
33915 this.adapter.setElementSize(this, size);
33916 this.animate = oldAnimate;
33920 * Destroy this splitbar.
33921 * @param {Boolean} removeEl True to remove the element
33923 destroy : function(removeEl){
33925 this.shim.remove();
33928 this.proxy.parentNode.removeChild(this.proxy);
33936 * @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.
33938 Roo.bootstrap.SplitBar.createProxy = function(dir){
33939 var proxy = new Roo.Element(document.createElement("div"));
33940 proxy.unselectable();
33941 var cls = 'roo-splitbar-proxy';
33942 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33943 document.body.appendChild(proxy.dom);
33948 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33949 * Default Adapter. It assumes the splitter and resizing element are not positioned
33950 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33952 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33955 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33956 // do nothing for now
33957 init : function(s){
33961 * Called before drag operations to get the current size of the resizing element.
33962 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33964 getElementSize : function(s){
33965 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33966 return s.resizingEl.getWidth();
33968 return s.resizingEl.getHeight();
33973 * Called after drag operations to set the size of the resizing element.
33974 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33975 * @param {Number} newSize The new size to set
33976 * @param {Function} onComplete A function to be invoked when resizing is complete
33978 setElementSize : function(s, newSize, onComplete){
33979 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33981 s.resizingEl.setWidth(newSize);
33983 onComplete(s, newSize);
33986 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33991 s.resizingEl.setHeight(newSize);
33993 onComplete(s, newSize);
33996 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34003 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34004 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34005 * Adapter that moves the splitter element to align with the resized sizing element.
34006 * Used with an absolute positioned SplitBar.
34007 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34008 * document.body, make sure you assign an id to the body element.
34010 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34011 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34012 this.container = Roo.get(container);
34015 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34016 init : function(s){
34017 this.basic.init(s);
34020 getElementSize : function(s){
34021 return this.basic.getElementSize(s);
34024 setElementSize : function(s, newSize, onComplete){
34025 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34028 moveSplitter : function(s){
34029 var yes = Roo.bootstrap.SplitBar;
34030 switch(s.placement){
34032 s.el.setX(s.resizingEl.getRight());
34035 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34038 s.el.setY(s.resizingEl.getBottom());
34041 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34048 * Orientation constant - Create a vertical SplitBar
34052 Roo.bootstrap.SplitBar.VERTICAL = 1;
34055 * Orientation constant - Create a horizontal SplitBar
34059 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34062 * Placement constant - The resizing element is to the left of the splitter element
34066 Roo.bootstrap.SplitBar.LEFT = 1;
34069 * Placement constant - The resizing element is to the right of the splitter element
34073 Roo.bootstrap.SplitBar.RIGHT = 2;
34076 * Placement constant - The resizing element is positioned above the splitter element
34080 Roo.bootstrap.SplitBar.TOP = 3;
34083 * Placement constant - The resizing element is positioned under splitter element
34087 Roo.bootstrap.SplitBar.BOTTOM = 4;
34088 Roo.namespace("Roo.bootstrap.layout");/*
34090 * Ext JS Library 1.1.1
34091 * Copyright(c) 2006-2007, Ext JS, LLC.
34093 * Originally Released Under LGPL - original licence link has changed is not relivant.
34096 * <script type="text/javascript">
34100 * @class Roo.bootstrap.layout.Manager
34101 * @extends Roo.bootstrap.Component
34102 * Base class for layout managers.
34104 Roo.bootstrap.layout.Manager = function(config)
34106 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34112 /** false to disable window resize monitoring @type Boolean */
34113 this.monitorWindowResize = true;
34118 * Fires when a layout is performed.
34119 * @param {Roo.LayoutManager} this
34123 * @event regionresized
34124 * Fires when the user resizes a region.
34125 * @param {Roo.LayoutRegion} region The resized region
34126 * @param {Number} newSize The new size (width for east/west, height for north/south)
34128 "regionresized" : true,
34130 * @event regioncollapsed
34131 * Fires when a region is collapsed.
34132 * @param {Roo.LayoutRegion} region The collapsed region
34134 "regioncollapsed" : true,
34136 * @event regionexpanded
34137 * Fires when a region is expanded.
34138 * @param {Roo.LayoutRegion} region The expanded region
34140 "regionexpanded" : true
34142 this.updating = false;
34145 this.el = Roo.get(config.el);
34151 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34156 monitorWindowResize : true,
34162 onRender : function(ct, position)
34165 this.el = Roo.get(ct);
34168 //this.fireEvent('render',this);
34172 initEvents: function()
34176 // ie scrollbar fix
34177 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34178 document.body.scroll = "no";
34179 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34180 this.el.position('relative');
34182 this.id = this.el.id;
34183 this.el.addClass("roo-layout-container");
34184 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34185 if(this.el.dom != document.body ) {
34186 this.el.on('resize', this.layout,this);
34187 this.el.on('show', this.layout,this);
34193 * Returns true if this layout is currently being updated
34194 * @return {Boolean}
34196 isUpdating : function(){
34197 return this.updating;
34201 * Suspend the LayoutManager from doing auto-layouts while
34202 * making multiple add or remove calls
34204 beginUpdate : function(){
34205 this.updating = true;
34209 * Restore auto-layouts and optionally disable the manager from performing a layout
34210 * @param {Boolean} noLayout true to disable a layout update
34212 endUpdate : function(noLayout){
34213 this.updating = false;
34219 layout: function(){
34223 onRegionResized : function(region, newSize){
34224 this.fireEvent("regionresized", region, newSize);
34228 onRegionCollapsed : function(region){
34229 this.fireEvent("regioncollapsed", region);
34232 onRegionExpanded : function(region){
34233 this.fireEvent("regionexpanded", region);
34237 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34238 * performs box-model adjustments.
34239 * @return {Object} The size as an object {width: (the width), height: (the height)}
34241 getViewSize : function()
34244 if(this.el.dom != document.body){
34245 size = this.el.getSize();
34247 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34249 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34250 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34255 * Returns the Element this layout is bound to.
34256 * @return {Roo.Element}
34258 getEl : function(){
34263 * Returns the specified region.
34264 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34265 * @return {Roo.LayoutRegion}
34267 getRegion : function(target){
34268 return this.regions[target.toLowerCase()];
34271 onWindowResize : function(){
34272 if(this.monitorWindowResize){
34279 * Ext JS Library 1.1.1
34280 * Copyright(c) 2006-2007, Ext JS, LLC.
34282 * Originally Released Under LGPL - original licence link has changed is not relivant.
34285 * <script type="text/javascript">
34288 * @class Roo.bootstrap.layout.Border
34289 * @extends Roo.bootstrap.layout.Manager
34290 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34291 * please see: examples/bootstrap/nested.html<br><br>
34293 <b>The container the layout is rendered into can be either the body element or any other element.
34294 If it is not the body element, the container needs to either be an absolute positioned element,
34295 or you will need to add "position:relative" to the css of the container. You will also need to specify
34296 the container size if it is not the body element.</b>
34299 * Create a new Border
34300 * @param {Object} config Configuration options
34302 Roo.bootstrap.layout.Border = function(config){
34303 config = config || {};
34304 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34308 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34309 if(config[region]){
34310 config[region].region = region;
34311 this.addRegion(config[region]);
34317 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34319 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34321 * Creates and adds a new region if it doesn't already exist.
34322 * @param {String} target The target region key (north, south, east, west or center).
34323 * @param {Object} config The regions config object
34324 * @return {BorderLayoutRegion} The new region
34326 addRegion : function(config)
34328 if(!this.regions[config.region]){
34329 var r = this.factory(config);
34330 this.bindRegion(r);
34332 return this.regions[config.region];
34336 bindRegion : function(r){
34337 this.regions[r.config.region] = r;
34339 r.on("visibilitychange", this.layout, this);
34340 r.on("paneladded", this.layout, this);
34341 r.on("panelremoved", this.layout, this);
34342 r.on("invalidated", this.layout, this);
34343 r.on("resized", this.onRegionResized, this);
34344 r.on("collapsed", this.onRegionCollapsed, this);
34345 r.on("expanded", this.onRegionExpanded, this);
34349 * Performs a layout update.
34351 layout : function()
34353 if(this.updating) {
34357 // render all the rebions if they have not been done alreayd?
34358 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34359 if(this.regions[region] && !this.regions[region].bodyEl){
34360 this.regions[region].onRender(this.el)
34364 var size = this.getViewSize();
34365 var w = size.width;
34366 var h = size.height;
34371 //var x = 0, y = 0;
34373 var rs = this.regions;
34374 var north = rs["north"];
34375 var south = rs["south"];
34376 var west = rs["west"];
34377 var east = rs["east"];
34378 var center = rs["center"];
34379 //if(this.hideOnLayout){ // not supported anymore
34380 //c.el.setStyle("display", "none");
34382 if(north && north.isVisible()){
34383 var b = north.getBox();
34384 var m = north.getMargins();
34385 b.width = w - (m.left+m.right);
34388 centerY = b.height + b.y + m.bottom;
34389 centerH -= centerY;
34390 north.updateBox(this.safeBox(b));
34392 if(south && south.isVisible()){
34393 var b = south.getBox();
34394 var m = south.getMargins();
34395 b.width = w - (m.left+m.right);
34397 var totalHeight = (b.height + m.top + m.bottom);
34398 b.y = h - totalHeight + m.top;
34399 centerH -= totalHeight;
34400 south.updateBox(this.safeBox(b));
34402 if(west && west.isVisible()){
34403 var b = west.getBox();
34404 var m = west.getMargins();
34405 b.height = centerH - (m.top+m.bottom);
34407 b.y = centerY + m.top;
34408 var totalWidth = (b.width + m.left + m.right);
34409 centerX += totalWidth;
34410 centerW -= totalWidth;
34411 west.updateBox(this.safeBox(b));
34413 if(east && east.isVisible()){
34414 var b = east.getBox();
34415 var m = east.getMargins();
34416 b.height = centerH - (m.top+m.bottom);
34417 var totalWidth = (b.width + m.left + m.right);
34418 b.x = w - totalWidth + m.left;
34419 b.y = centerY + m.top;
34420 centerW -= totalWidth;
34421 east.updateBox(this.safeBox(b));
34424 var m = center.getMargins();
34426 x: centerX + m.left,
34427 y: centerY + m.top,
34428 width: centerW - (m.left+m.right),
34429 height: centerH - (m.top+m.bottom)
34431 //if(this.hideOnLayout){
34432 //center.el.setStyle("display", "block");
34434 center.updateBox(this.safeBox(centerBox));
34437 this.fireEvent("layout", this);
34441 safeBox : function(box){
34442 box.width = Math.max(0, box.width);
34443 box.height = Math.max(0, box.height);
34448 * Adds a ContentPanel (or subclass) to this layout.
34449 * @param {String} target The target region key (north, south, east, west or center).
34450 * @param {Roo.ContentPanel} panel The panel to add
34451 * @return {Roo.ContentPanel} The added panel
34453 add : function(target, panel){
34455 target = target.toLowerCase();
34456 return this.regions[target].add(panel);
34460 * Remove a ContentPanel (or subclass) to this layout.
34461 * @param {String} target The target region key (north, south, east, west or center).
34462 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34463 * @return {Roo.ContentPanel} The removed panel
34465 remove : function(target, panel){
34466 target = target.toLowerCase();
34467 return this.regions[target].remove(panel);
34471 * Searches all regions for a panel with the specified id
34472 * @param {String} panelId
34473 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34475 findPanel : function(panelId){
34476 var rs = this.regions;
34477 for(var target in rs){
34478 if(typeof rs[target] != "function"){
34479 var p = rs[target].getPanel(panelId);
34489 * Searches all regions for a panel with the specified id and activates (shows) it.
34490 * @param {String/ContentPanel} panelId The panels id or the panel itself
34491 * @return {Roo.ContentPanel} The shown panel or null
34493 showPanel : function(panelId) {
34494 var rs = this.regions;
34495 for(var target in rs){
34496 var r = rs[target];
34497 if(typeof r != "function"){
34498 if(r.hasPanel(panelId)){
34499 return r.showPanel(panelId);
34507 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34508 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34511 restoreState : function(provider){
34513 provider = Roo.state.Manager;
34515 var sm = new Roo.LayoutStateManager();
34516 sm.init(this, provider);
34522 * Adds a xtype elements to the layout.
34526 xtype : 'ContentPanel',
34533 xtype : 'NestedLayoutPanel',
34539 items : [ ... list of content panels or nested layout panels.. ]
34543 * @param {Object} cfg Xtype definition of item to add.
34545 addxtype : function(cfg)
34547 // basically accepts a pannel...
34548 // can accept a layout region..!?!?
34549 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34552 // theory? children can only be panels??
34554 //if (!cfg.xtype.match(/Panel$/)) {
34559 if (typeof(cfg.region) == 'undefined') {
34560 Roo.log("Failed to add Panel, region was not set");
34564 var region = cfg.region;
34570 xitems = cfg.items;
34577 case 'Content': // ContentPanel (el, cfg)
34578 case 'Scroll': // ContentPanel (el, cfg)
34580 cfg.autoCreate = true;
34581 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34583 // var el = this.el.createChild();
34584 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34587 this.add(region, ret);
34591 case 'TreePanel': // our new panel!
34592 cfg.el = this.el.createChild();
34593 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34594 this.add(region, ret);
34599 // create a new Layout (which is a Border Layout...
34601 var clayout = cfg.layout;
34602 clayout.el = this.el.createChild();
34603 clayout.items = clayout.items || [];
34607 // replace this exitems with the clayout ones..
34608 xitems = clayout.items;
34610 // force background off if it's in center...
34611 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34612 cfg.background = false;
34614 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34617 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34618 //console.log('adding nested layout panel ' + cfg.toSource());
34619 this.add(region, ret);
34620 nb = {}; /// find first...
34625 // needs grid and region
34627 //var el = this.getRegion(region).el.createChild();
34629 *var el = this.el.createChild();
34630 // create the grid first...
34631 cfg.grid.container = el;
34632 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34635 if (region == 'center' && this.active ) {
34636 cfg.background = false;
34639 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34641 this.add(region, ret);
34643 if (cfg.background) {
34644 // render grid on panel activation (if panel background)
34645 ret.on('activate', function(gp) {
34646 if (!gp.grid.rendered) {
34647 // gp.grid.render(el);
34651 // cfg.grid.render(el);
34657 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34658 // it was the old xcomponent building that caused this before.
34659 // espeically if border is the top element in the tree.
34669 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34671 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34672 this.add(region, ret);
34676 throw "Can not add '" + cfg.xtype + "' to Border";
34682 this.beginUpdate();
34686 Roo.each(xitems, function(i) {
34687 region = nb && i.region ? i.region : false;
34689 var add = ret.addxtype(i);
34692 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34693 if (!i.background) {
34694 abn[region] = nb[region] ;
34701 // make the last non-background panel active..
34702 //if (nb) { Roo.log(abn); }
34705 for(var r in abn) {
34706 region = this.getRegion(r);
34708 // tried using nb[r], but it does not work..
34710 region.showPanel(abn[r]);
34721 factory : function(cfg)
34724 var validRegions = Roo.bootstrap.layout.Border.regions;
34726 var target = cfg.region;
34729 var r = Roo.bootstrap.layout;
34733 return new r.North(cfg);
34735 return new r.South(cfg);
34737 return new r.East(cfg);
34739 return new r.West(cfg);
34741 return new r.Center(cfg);
34743 throw 'Layout region "'+target+'" not supported.';
34750 * Ext JS Library 1.1.1
34751 * Copyright(c) 2006-2007, Ext JS, LLC.
34753 * Originally Released Under LGPL - original licence link has changed is not relivant.
34756 * <script type="text/javascript">
34760 * @class Roo.bootstrap.layout.Basic
34761 * @extends Roo.util.Observable
34762 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34763 * and does not have a titlebar, tabs or any other features. All it does is size and position
34764 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34765 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34766 * @cfg {string} region the region that it inhabits..
34767 * @cfg {bool} skipConfig skip config?
34771 Roo.bootstrap.layout.Basic = function(config){
34773 this.mgr = config.mgr;
34775 this.position = config.region;
34777 var skipConfig = config.skipConfig;
34781 * @scope Roo.BasicLayoutRegion
34785 * @event beforeremove
34786 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34787 * @param {Roo.LayoutRegion} this
34788 * @param {Roo.ContentPanel} panel The panel
34789 * @param {Object} e The cancel event object
34791 "beforeremove" : true,
34793 * @event invalidated
34794 * Fires when the layout for this region is changed.
34795 * @param {Roo.LayoutRegion} this
34797 "invalidated" : true,
34799 * @event visibilitychange
34800 * Fires when this region is shown or hidden
34801 * @param {Roo.LayoutRegion} this
34802 * @param {Boolean} visibility true or false
34804 "visibilitychange" : true,
34806 * @event paneladded
34807 * Fires when a panel is added.
34808 * @param {Roo.LayoutRegion} this
34809 * @param {Roo.ContentPanel} panel The panel
34811 "paneladded" : true,
34813 * @event panelremoved
34814 * Fires when a panel is removed.
34815 * @param {Roo.LayoutRegion} this
34816 * @param {Roo.ContentPanel} panel The panel
34818 "panelremoved" : true,
34820 * @event beforecollapse
34821 * Fires when this region before collapse.
34822 * @param {Roo.LayoutRegion} this
34824 "beforecollapse" : true,
34827 * Fires when this region is collapsed.
34828 * @param {Roo.LayoutRegion} this
34830 "collapsed" : true,
34833 * Fires when this region is expanded.
34834 * @param {Roo.LayoutRegion} this
34839 * Fires when this region is slid into view.
34840 * @param {Roo.LayoutRegion} this
34842 "slideshow" : true,
34845 * Fires when this region slides out of view.
34846 * @param {Roo.LayoutRegion} this
34848 "slidehide" : true,
34850 * @event panelactivated
34851 * Fires when a panel is activated.
34852 * @param {Roo.LayoutRegion} this
34853 * @param {Roo.ContentPanel} panel The activated panel
34855 "panelactivated" : true,
34858 * Fires when the user resizes this region.
34859 * @param {Roo.LayoutRegion} this
34860 * @param {Number} newSize The new size (width for east/west, height for north/south)
34864 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34865 this.panels = new Roo.util.MixedCollection();
34866 this.panels.getKey = this.getPanelId.createDelegate(this);
34868 this.activePanel = null;
34869 // ensure listeners are added...
34871 if (config.listeners || config.events) {
34872 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34873 listeners : config.listeners || {},
34874 events : config.events || {}
34878 if(skipConfig !== true){
34879 this.applyConfig(config);
34883 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34885 getPanelId : function(p){
34889 applyConfig : function(config){
34890 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34891 this.config = config;
34896 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34897 * the width, for horizontal (north, south) the height.
34898 * @param {Number} newSize The new width or height
34900 resizeTo : function(newSize){
34901 var el = this.el ? this.el :
34902 (this.activePanel ? this.activePanel.getEl() : null);
34904 switch(this.position){
34907 el.setWidth(newSize);
34908 this.fireEvent("resized", this, newSize);
34912 el.setHeight(newSize);
34913 this.fireEvent("resized", this, newSize);
34919 getBox : function(){
34920 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34923 getMargins : function(){
34924 return this.margins;
34927 updateBox : function(box){
34929 var el = this.activePanel.getEl();
34930 el.dom.style.left = box.x + "px";
34931 el.dom.style.top = box.y + "px";
34932 this.activePanel.setSize(box.width, box.height);
34936 * Returns the container element for this region.
34937 * @return {Roo.Element}
34939 getEl : function(){
34940 return this.activePanel;
34944 * Returns true if this region is currently visible.
34945 * @return {Boolean}
34947 isVisible : function(){
34948 return this.activePanel ? true : false;
34951 setActivePanel : function(panel){
34952 panel = this.getPanel(panel);
34953 if(this.activePanel && this.activePanel != panel){
34954 this.activePanel.setActiveState(false);
34955 this.activePanel.getEl().setLeftTop(-10000,-10000);
34957 this.activePanel = panel;
34958 panel.setActiveState(true);
34960 panel.setSize(this.box.width, this.box.height);
34962 this.fireEvent("panelactivated", this, panel);
34963 this.fireEvent("invalidated");
34967 * Show the specified panel.
34968 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34969 * @return {Roo.ContentPanel} The shown panel or null
34971 showPanel : function(panel){
34972 panel = this.getPanel(panel);
34974 this.setActivePanel(panel);
34980 * Get the active panel for this region.
34981 * @return {Roo.ContentPanel} The active panel or null
34983 getActivePanel : function(){
34984 return this.activePanel;
34988 * Add the passed ContentPanel(s)
34989 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34990 * @return {Roo.ContentPanel} The panel added (if only one was added)
34992 add : function(panel){
34993 if(arguments.length > 1){
34994 for(var i = 0, len = arguments.length; i < len; i++) {
34995 this.add(arguments[i]);
34999 if(this.hasPanel(panel)){
35000 this.showPanel(panel);
35003 var el = panel.getEl();
35004 if(el.dom.parentNode != this.mgr.el.dom){
35005 this.mgr.el.dom.appendChild(el.dom);
35007 if(panel.setRegion){
35008 panel.setRegion(this);
35010 this.panels.add(panel);
35011 el.setStyle("position", "absolute");
35012 if(!panel.background){
35013 this.setActivePanel(panel);
35014 if(this.config.initialSize && this.panels.getCount()==1){
35015 this.resizeTo(this.config.initialSize);
35018 this.fireEvent("paneladded", this, panel);
35023 * Returns true if the panel is in this region.
35024 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35025 * @return {Boolean}
35027 hasPanel : function(panel){
35028 if(typeof panel == "object"){ // must be panel obj
35029 panel = panel.getId();
35031 return this.getPanel(panel) ? true : false;
35035 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35036 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35037 * @param {Boolean} preservePanel Overrides the config preservePanel option
35038 * @return {Roo.ContentPanel} The panel that was removed
35040 remove : function(panel, preservePanel){
35041 panel = this.getPanel(panel);
35046 this.fireEvent("beforeremove", this, panel, e);
35047 if(e.cancel === true){
35050 var panelId = panel.getId();
35051 this.panels.removeKey(panelId);
35056 * Returns the panel specified or null if it's not in this region.
35057 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35058 * @return {Roo.ContentPanel}
35060 getPanel : function(id){
35061 if(typeof id == "object"){ // must be panel obj
35064 return this.panels.get(id);
35068 * Returns this regions position (north/south/east/west/center).
35071 getPosition: function(){
35072 return this.position;
35076 * Ext JS Library 1.1.1
35077 * Copyright(c) 2006-2007, Ext JS, LLC.
35079 * Originally Released Under LGPL - original licence link has changed is not relivant.
35082 * <script type="text/javascript">
35086 * @class Roo.bootstrap.layout.Region
35087 * @extends Roo.bootstrap.layout.Basic
35088 * This class represents a region in a layout manager.
35090 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35091 * @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})
35092 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35093 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35094 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35095 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35096 * @cfg {String} title The title for the region (overrides panel titles)
35097 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35098 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35099 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35100 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35101 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35102 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35103 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35104 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35105 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35106 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35108 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35109 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35110 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35111 * @cfg {Number} width For East/West panels
35112 * @cfg {Number} height For North/South panels
35113 * @cfg {Boolean} split To show the splitter
35114 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35116 * @cfg {string} cls Extra CSS classes to add to region
35118 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35119 * @cfg {string} region the region that it inhabits..
35122 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35123 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35125 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35126 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35127 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35129 Roo.bootstrap.layout.Region = function(config)
35131 this.applyConfig(config);
35133 var mgr = config.mgr;
35134 var pos = config.region;
35135 config.skipConfig = true;
35136 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35139 this.onRender(mgr.el);
35142 this.visible = true;
35143 this.collapsed = false;
35144 this.unrendered_panels = [];
35147 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35149 position: '', // set by wrapper (eg. north/south etc..)
35150 unrendered_panels : null, // unrendered panels.
35151 createBody : function(){
35152 /** This region's body element
35153 * @type Roo.Element */
35154 this.bodyEl = this.el.createChild({
35156 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35160 onRender: function(ctr, pos)
35162 var dh = Roo.DomHelper;
35163 /** This region's container element
35164 * @type Roo.Element */
35165 this.el = dh.append(ctr.dom, {
35167 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35169 /** This region's title element
35170 * @type Roo.Element */
35172 this.titleEl = dh.append(this.el.dom,
35175 unselectable: "on",
35176 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35178 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35179 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35182 this.titleEl.enableDisplayMode();
35183 /** This region's title text element
35184 * @type HTMLElement */
35185 this.titleTextEl = this.titleEl.dom.firstChild;
35186 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35188 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35189 this.closeBtn.enableDisplayMode();
35190 this.closeBtn.on("click", this.closeClicked, this);
35191 this.closeBtn.hide();
35193 this.createBody(this.config);
35194 if(this.config.hideWhenEmpty){
35196 this.on("paneladded", this.validateVisibility, this);
35197 this.on("panelremoved", this.validateVisibility, this);
35199 if(this.autoScroll){
35200 this.bodyEl.setStyle("overflow", "auto");
35202 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35204 //if(c.titlebar !== false){
35205 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35206 this.titleEl.hide();
35208 this.titleEl.show();
35209 if(this.config.title){
35210 this.titleTextEl.innerHTML = this.config.title;
35214 if(this.config.collapsed){
35215 this.collapse(true);
35217 if(this.config.hidden){
35221 if (this.unrendered_panels && this.unrendered_panels.length) {
35222 for (var i =0;i< this.unrendered_panels.length; i++) {
35223 this.add(this.unrendered_panels[i]);
35225 this.unrendered_panels = null;
35231 applyConfig : function(c)
35234 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35235 var dh = Roo.DomHelper;
35236 if(c.titlebar !== false){
35237 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35238 this.collapseBtn.on("click", this.collapse, this);
35239 this.collapseBtn.enableDisplayMode();
35241 if(c.showPin === true || this.showPin){
35242 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35243 this.stickBtn.enableDisplayMode();
35244 this.stickBtn.on("click", this.expand, this);
35245 this.stickBtn.hide();
35250 /** This region's collapsed element
35251 * @type Roo.Element */
35254 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35255 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35258 if(c.floatable !== false){
35259 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35260 this.collapsedEl.on("click", this.collapseClick, this);
35263 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35264 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35265 id: "message", unselectable: "on", style:{"float":"left"}});
35266 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35268 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35269 this.expandBtn.on("click", this.expand, this);
35273 if(this.collapseBtn){
35274 this.collapseBtn.setVisible(c.collapsible == true);
35277 this.cmargins = c.cmargins || this.cmargins ||
35278 (this.position == "west" || this.position == "east" ?
35279 {top: 0, left: 2, right:2, bottom: 0} :
35280 {top: 2, left: 0, right:0, bottom: 2});
35282 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35285 this.bottomTabs = c.tabPosition != "top";
35287 this.autoScroll = c.autoScroll || false;
35292 this.duration = c.duration || .30;
35293 this.slideDuration = c.slideDuration || .45;
35298 * Returns true if this region is currently visible.
35299 * @return {Boolean}
35301 isVisible : function(){
35302 return this.visible;
35306 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35307 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35309 //setCollapsedTitle : function(title){
35310 // title = title || " ";
35311 // if(this.collapsedTitleTextEl){
35312 // this.collapsedTitleTextEl.innerHTML = title;
35316 getBox : function(){
35318 // if(!this.collapsed){
35319 b = this.el.getBox(false, true);
35321 // b = this.collapsedEl.getBox(false, true);
35326 getMargins : function(){
35327 return this.margins;
35328 //return this.collapsed ? this.cmargins : this.margins;
35331 highlight : function(){
35332 this.el.addClass("x-layout-panel-dragover");
35335 unhighlight : function(){
35336 this.el.removeClass("x-layout-panel-dragover");
35339 updateBox : function(box)
35341 if (!this.bodyEl) {
35342 return; // not rendered yet..
35346 if(!this.collapsed){
35347 this.el.dom.style.left = box.x + "px";
35348 this.el.dom.style.top = box.y + "px";
35349 this.updateBody(box.width, box.height);
35351 this.collapsedEl.dom.style.left = box.x + "px";
35352 this.collapsedEl.dom.style.top = box.y + "px";
35353 this.collapsedEl.setSize(box.width, box.height);
35356 this.tabs.autoSizeTabs();
35360 updateBody : function(w, h)
35363 this.el.setWidth(w);
35364 w -= this.el.getBorderWidth("rl");
35365 if(this.config.adjustments){
35366 w += this.config.adjustments[0];
35369 if(h !== null && h > 0){
35370 this.el.setHeight(h);
35371 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35372 h -= this.el.getBorderWidth("tb");
35373 if(this.config.adjustments){
35374 h += this.config.adjustments[1];
35376 this.bodyEl.setHeight(h);
35378 h = this.tabs.syncHeight(h);
35381 if(this.panelSize){
35382 w = w !== null ? w : this.panelSize.width;
35383 h = h !== null ? h : this.panelSize.height;
35385 if(this.activePanel){
35386 var el = this.activePanel.getEl();
35387 w = w !== null ? w : el.getWidth();
35388 h = h !== null ? h : el.getHeight();
35389 this.panelSize = {width: w, height: h};
35390 this.activePanel.setSize(w, h);
35392 if(Roo.isIE && this.tabs){
35393 this.tabs.el.repaint();
35398 * Returns the container element for this region.
35399 * @return {Roo.Element}
35401 getEl : function(){
35406 * Hides this region.
35409 //if(!this.collapsed){
35410 this.el.dom.style.left = "-2000px";
35413 // this.collapsedEl.dom.style.left = "-2000px";
35414 // this.collapsedEl.hide();
35416 this.visible = false;
35417 this.fireEvent("visibilitychange", this, false);
35421 * Shows this region if it was previously hidden.
35424 //if(!this.collapsed){
35427 // this.collapsedEl.show();
35429 this.visible = true;
35430 this.fireEvent("visibilitychange", this, true);
35433 closeClicked : function(){
35434 if(this.activePanel){
35435 this.remove(this.activePanel);
35439 collapseClick : function(e){
35441 e.stopPropagation();
35444 e.stopPropagation();
35450 * Collapses this region.
35451 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35454 collapse : function(skipAnim, skipCheck = false){
35455 if(this.collapsed) {
35459 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35461 this.collapsed = true;
35463 this.split.el.hide();
35465 if(this.config.animate && skipAnim !== true){
35466 this.fireEvent("invalidated", this);
35467 this.animateCollapse();
35469 this.el.setLocation(-20000,-20000);
35471 this.collapsedEl.show();
35472 this.fireEvent("collapsed", this);
35473 this.fireEvent("invalidated", this);
35479 animateCollapse : function(){
35484 * Expands this region if it was previously collapsed.
35485 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35486 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35489 expand : function(e, skipAnim){
35491 e.stopPropagation();
35493 if(!this.collapsed || this.el.hasActiveFx()) {
35497 this.afterSlideIn();
35500 this.collapsed = false;
35501 if(this.config.animate && skipAnim !== true){
35502 this.animateExpand();
35506 this.split.el.show();
35508 this.collapsedEl.setLocation(-2000,-2000);
35509 this.collapsedEl.hide();
35510 this.fireEvent("invalidated", this);
35511 this.fireEvent("expanded", this);
35515 animateExpand : function(){
35519 initTabs : function()
35521 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35523 var ts = new Roo.bootstrap.panel.Tabs({
35524 el: this.bodyEl.dom,
35525 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35526 disableTooltips: this.config.disableTabTips,
35527 toolbar : this.config.toolbar
35530 if(this.config.hideTabs){
35531 ts.stripWrap.setDisplayed(false);
35534 ts.resizeTabs = this.config.resizeTabs === true;
35535 ts.minTabWidth = this.config.minTabWidth || 40;
35536 ts.maxTabWidth = this.config.maxTabWidth || 250;
35537 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35538 ts.monitorResize = false;
35539 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35540 ts.bodyEl.addClass('roo-layout-tabs-body');
35541 this.panels.each(this.initPanelAsTab, this);
35544 initPanelAsTab : function(panel){
35545 var ti = this.tabs.addTab(
35549 this.config.closeOnTab && panel.isClosable(),
35552 if(panel.tabTip !== undefined){
35553 ti.setTooltip(panel.tabTip);
35555 ti.on("activate", function(){
35556 this.setActivePanel(panel);
35559 if(this.config.closeOnTab){
35560 ti.on("beforeclose", function(t, e){
35562 this.remove(panel);
35566 panel.tabItem = ti;
35571 updatePanelTitle : function(panel, title)
35573 if(this.activePanel == panel){
35574 this.updateTitle(title);
35577 var ti = this.tabs.getTab(panel.getEl().id);
35579 if(panel.tabTip !== undefined){
35580 ti.setTooltip(panel.tabTip);
35585 updateTitle : function(title){
35586 if(this.titleTextEl && !this.config.title){
35587 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35591 setActivePanel : function(panel)
35593 panel = this.getPanel(panel);
35594 if(this.activePanel && this.activePanel != panel){
35595 if(this.activePanel.setActiveState(false) === false){
35599 this.activePanel = panel;
35600 panel.setActiveState(true);
35601 if(this.panelSize){
35602 panel.setSize(this.panelSize.width, this.panelSize.height);
35605 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35607 this.updateTitle(panel.getTitle());
35609 this.fireEvent("invalidated", this);
35611 this.fireEvent("panelactivated", this, panel);
35615 * Shows the specified panel.
35616 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35617 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35619 showPanel : function(panel)
35621 panel = this.getPanel(panel);
35624 var tab = this.tabs.getTab(panel.getEl().id);
35625 if(tab.isHidden()){
35626 this.tabs.unhideTab(tab.id);
35630 this.setActivePanel(panel);
35637 * Get the active panel for this region.
35638 * @return {Roo.ContentPanel} The active panel or null
35640 getActivePanel : function(){
35641 return this.activePanel;
35644 validateVisibility : function(){
35645 if(this.panels.getCount() < 1){
35646 this.updateTitle(" ");
35647 this.closeBtn.hide();
35650 if(!this.isVisible()){
35657 * Adds the passed ContentPanel(s) to this region.
35658 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35659 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35661 add : function(panel)
35663 if(arguments.length > 1){
35664 for(var i = 0, len = arguments.length; i < len; i++) {
35665 this.add(arguments[i]);
35670 // if we have not been rendered yet, then we can not really do much of this..
35671 if (!this.bodyEl) {
35672 this.unrendered_panels.push(panel);
35679 if(this.hasPanel(panel)){
35680 this.showPanel(panel);
35683 panel.setRegion(this);
35684 this.panels.add(panel);
35685 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35686 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35687 // and hide them... ???
35688 this.bodyEl.dom.appendChild(panel.getEl().dom);
35689 if(panel.background !== true){
35690 this.setActivePanel(panel);
35692 this.fireEvent("paneladded", this, panel);
35699 this.initPanelAsTab(panel);
35703 if(panel.background !== true){
35704 this.tabs.activate(panel.getEl().id);
35706 this.fireEvent("paneladded", this, panel);
35711 * Hides the tab for the specified panel.
35712 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35714 hidePanel : function(panel){
35715 if(this.tabs && (panel = this.getPanel(panel))){
35716 this.tabs.hideTab(panel.getEl().id);
35721 * Unhides the tab for a previously hidden panel.
35722 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35724 unhidePanel : function(panel){
35725 if(this.tabs && (panel = this.getPanel(panel))){
35726 this.tabs.unhideTab(panel.getEl().id);
35730 clearPanels : function(){
35731 while(this.panels.getCount() > 0){
35732 this.remove(this.panels.first());
35737 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35738 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35739 * @param {Boolean} preservePanel Overrides the config preservePanel option
35740 * @return {Roo.ContentPanel} The panel that was removed
35742 remove : function(panel, preservePanel)
35744 panel = this.getPanel(panel);
35749 this.fireEvent("beforeremove", this, panel, e);
35750 if(e.cancel === true){
35753 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35754 var panelId = panel.getId();
35755 this.panels.removeKey(panelId);
35757 document.body.appendChild(panel.getEl().dom);
35760 this.tabs.removeTab(panel.getEl().id);
35761 }else if (!preservePanel){
35762 this.bodyEl.dom.removeChild(panel.getEl().dom);
35764 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35765 var p = this.panels.first();
35766 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35767 tempEl.appendChild(p.getEl().dom);
35768 this.bodyEl.update("");
35769 this.bodyEl.dom.appendChild(p.getEl().dom);
35771 this.updateTitle(p.getTitle());
35773 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35774 this.setActivePanel(p);
35776 panel.setRegion(null);
35777 if(this.activePanel == panel){
35778 this.activePanel = null;
35780 if(this.config.autoDestroy !== false && preservePanel !== true){
35781 try{panel.destroy();}catch(e){}
35783 this.fireEvent("panelremoved", this, panel);
35788 * Returns the TabPanel component used by this region
35789 * @return {Roo.TabPanel}
35791 getTabs : function(){
35795 createTool : function(parentEl, className){
35796 var btn = Roo.DomHelper.append(parentEl, {
35798 cls: "x-layout-tools-button",
35801 cls: "roo-layout-tools-button-inner " + className,
35805 btn.addClassOnOver("roo-layout-tools-button-over");
35810 * Ext JS Library 1.1.1
35811 * Copyright(c) 2006-2007, Ext JS, LLC.
35813 * Originally Released Under LGPL - original licence link has changed is not relivant.
35816 * <script type="text/javascript">
35822 * @class Roo.SplitLayoutRegion
35823 * @extends Roo.LayoutRegion
35824 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35826 Roo.bootstrap.layout.Split = function(config){
35827 this.cursor = config.cursor;
35828 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35831 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35833 splitTip : "Drag to resize.",
35834 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35835 useSplitTips : false,
35837 applyConfig : function(config){
35838 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35841 onRender : function(ctr,pos) {
35843 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35844 if(!this.config.split){
35849 var splitEl = Roo.DomHelper.append(ctr.dom, {
35851 id: this.el.id + "-split",
35852 cls: "roo-layout-split roo-layout-split-"+this.position,
35855 /** The SplitBar for this region
35856 * @type Roo.SplitBar */
35857 // does not exist yet...
35858 Roo.log([this.position, this.orientation]);
35860 this.split = new Roo.bootstrap.SplitBar({
35861 dragElement : splitEl,
35862 resizingElement: this.el,
35863 orientation : this.orientation
35866 this.split.on("moved", this.onSplitMove, this);
35867 this.split.useShim = this.config.useShim === true;
35868 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35869 if(this.useSplitTips){
35870 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35872 //if(config.collapsible){
35873 // this.split.el.on("dblclick", this.collapse, this);
35876 if(typeof this.config.minSize != "undefined"){
35877 this.split.minSize = this.config.minSize;
35879 if(typeof this.config.maxSize != "undefined"){
35880 this.split.maxSize = this.config.maxSize;
35882 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35883 this.hideSplitter();
35888 getHMaxSize : function(){
35889 var cmax = this.config.maxSize || 10000;
35890 var center = this.mgr.getRegion("center");
35891 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35894 getVMaxSize : function(){
35895 var cmax = this.config.maxSize || 10000;
35896 var center = this.mgr.getRegion("center");
35897 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35900 onSplitMove : function(split, newSize){
35901 this.fireEvent("resized", this, newSize);
35905 * Returns the {@link Roo.SplitBar} for this region.
35906 * @return {Roo.SplitBar}
35908 getSplitBar : function(){
35913 this.hideSplitter();
35914 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35917 hideSplitter : function(){
35919 this.split.el.setLocation(-2000,-2000);
35920 this.split.el.hide();
35926 this.split.el.show();
35928 Roo.bootstrap.layout.Split.superclass.show.call(this);
35931 beforeSlide: function(){
35932 if(Roo.isGecko){// firefox overflow auto bug workaround
35933 this.bodyEl.clip();
35935 this.tabs.bodyEl.clip();
35937 if(this.activePanel){
35938 this.activePanel.getEl().clip();
35940 if(this.activePanel.beforeSlide){
35941 this.activePanel.beforeSlide();
35947 afterSlide : function(){
35948 if(Roo.isGecko){// firefox overflow auto bug workaround
35949 this.bodyEl.unclip();
35951 this.tabs.bodyEl.unclip();
35953 if(this.activePanel){
35954 this.activePanel.getEl().unclip();
35955 if(this.activePanel.afterSlide){
35956 this.activePanel.afterSlide();
35962 initAutoHide : function(){
35963 if(this.autoHide !== false){
35964 if(!this.autoHideHd){
35965 var st = new Roo.util.DelayedTask(this.slideIn, this);
35966 this.autoHideHd = {
35967 "mouseout": function(e){
35968 if(!e.within(this.el, true)){
35972 "mouseover" : function(e){
35978 this.el.on(this.autoHideHd);
35982 clearAutoHide : function(){
35983 if(this.autoHide !== false){
35984 this.el.un("mouseout", this.autoHideHd.mouseout);
35985 this.el.un("mouseover", this.autoHideHd.mouseover);
35989 clearMonitor : function(){
35990 Roo.get(document).un("click", this.slideInIf, this);
35993 // these names are backwards but not changed for compat
35994 slideOut : function(){
35995 if(this.isSlid || this.el.hasActiveFx()){
35998 this.isSlid = true;
35999 if(this.collapseBtn){
36000 this.collapseBtn.hide();
36002 this.closeBtnState = this.closeBtn.getStyle('display');
36003 this.closeBtn.hide();
36005 this.stickBtn.show();
36008 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36009 this.beforeSlide();
36010 this.el.setStyle("z-index", 10001);
36011 this.el.slideIn(this.getSlideAnchor(), {
36012 callback: function(){
36014 this.initAutoHide();
36015 Roo.get(document).on("click", this.slideInIf, this);
36016 this.fireEvent("slideshow", this);
36023 afterSlideIn : function(){
36024 this.clearAutoHide();
36025 this.isSlid = false;
36026 this.clearMonitor();
36027 this.el.setStyle("z-index", "");
36028 if(this.collapseBtn){
36029 this.collapseBtn.show();
36031 this.closeBtn.setStyle('display', this.closeBtnState);
36033 this.stickBtn.hide();
36035 this.fireEvent("slidehide", this);
36038 slideIn : function(cb){
36039 if(!this.isSlid || this.el.hasActiveFx()){
36043 this.isSlid = false;
36044 this.beforeSlide();
36045 this.el.slideOut(this.getSlideAnchor(), {
36046 callback: function(){
36047 this.el.setLeftTop(-10000, -10000);
36049 this.afterSlideIn();
36057 slideInIf : function(e){
36058 if(!e.within(this.el)){
36063 animateCollapse : function(){
36064 this.beforeSlide();
36065 this.el.setStyle("z-index", 20000);
36066 var anchor = this.getSlideAnchor();
36067 this.el.slideOut(anchor, {
36068 callback : function(){
36069 this.el.setStyle("z-index", "");
36070 this.collapsedEl.slideIn(anchor, {duration:.3});
36072 this.el.setLocation(-10000,-10000);
36074 this.fireEvent("collapsed", this);
36081 animateExpand : function(){
36082 this.beforeSlide();
36083 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36084 this.el.setStyle("z-index", 20000);
36085 this.collapsedEl.hide({
36088 this.el.slideIn(this.getSlideAnchor(), {
36089 callback : function(){
36090 this.el.setStyle("z-index", "");
36093 this.split.el.show();
36095 this.fireEvent("invalidated", this);
36096 this.fireEvent("expanded", this);
36124 getAnchor : function(){
36125 return this.anchors[this.position];
36128 getCollapseAnchor : function(){
36129 return this.canchors[this.position];
36132 getSlideAnchor : function(){
36133 return this.sanchors[this.position];
36136 getAlignAdj : function(){
36137 var cm = this.cmargins;
36138 switch(this.position){
36154 getExpandAdj : function(){
36155 var c = this.collapsedEl, cm = this.cmargins;
36156 switch(this.position){
36158 return [-(cm.right+c.getWidth()+cm.left), 0];
36161 return [cm.right+c.getWidth()+cm.left, 0];
36164 return [0, -(cm.top+cm.bottom+c.getHeight())];
36167 return [0, cm.top+cm.bottom+c.getHeight()];
36173 * Ext JS Library 1.1.1
36174 * Copyright(c) 2006-2007, Ext JS, LLC.
36176 * Originally Released Under LGPL - original licence link has changed is not relivant.
36179 * <script type="text/javascript">
36182 * These classes are private internal classes
36184 Roo.bootstrap.layout.Center = function(config){
36185 config.region = "center";
36186 Roo.bootstrap.layout.Region.call(this, config);
36187 this.visible = true;
36188 this.minWidth = config.minWidth || 20;
36189 this.minHeight = config.minHeight || 20;
36192 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36194 // center panel can't be hidden
36198 // center panel can't be hidden
36201 getMinWidth: function(){
36202 return this.minWidth;
36205 getMinHeight: function(){
36206 return this.minHeight;
36219 Roo.bootstrap.layout.North = function(config)
36221 config.region = 'north';
36222 config.cursor = 'n-resize';
36224 Roo.bootstrap.layout.Split.call(this, config);
36228 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36229 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36230 this.split.el.addClass("roo-layout-split-v");
36232 var size = config.initialSize || config.height;
36233 if(typeof size != "undefined"){
36234 this.el.setHeight(size);
36237 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36239 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36243 getBox : function(){
36244 if(this.collapsed){
36245 return this.collapsedEl.getBox();
36247 var box = this.el.getBox();
36249 box.height += this.split.el.getHeight();
36254 updateBox : function(box){
36255 if(this.split && !this.collapsed){
36256 box.height -= this.split.el.getHeight();
36257 this.split.el.setLeft(box.x);
36258 this.split.el.setTop(box.y+box.height);
36259 this.split.el.setWidth(box.width);
36261 if(this.collapsed){
36262 this.updateBody(box.width, null);
36264 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36272 Roo.bootstrap.layout.South = function(config){
36273 config.region = 'south';
36274 config.cursor = 's-resize';
36275 Roo.bootstrap.layout.Split.call(this, config);
36277 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36278 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36279 this.split.el.addClass("roo-layout-split-v");
36281 var size = config.initialSize || config.height;
36282 if(typeof size != "undefined"){
36283 this.el.setHeight(size);
36287 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36288 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36289 getBox : function(){
36290 if(this.collapsed){
36291 return this.collapsedEl.getBox();
36293 var box = this.el.getBox();
36295 var sh = this.split.el.getHeight();
36302 updateBox : function(box){
36303 if(this.split && !this.collapsed){
36304 var sh = this.split.el.getHeight();
36307 this.split.el.setLeft(box.x);
36308 this.split.el.setTop(box.y-sh);
36309 this.split.el.setWidth(box.width);
36311 if(this.collapsed){
36312 this.updateBody(box.width, null);
36314 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36318 Roo.bootstrap.layout.East = function(config){
36319 config.region = "east";
36320 config.cursor = "e-resize";
36321 Roo.bootstrap.layout.Split.call(this, config);
36323 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36324 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36325 this.split.el.addClass("roo-layout-split-h");
36327 var size = config.initialSize || config.width;
36328 if(typeof size != "undefined"){
36329 this.el.setWidth(size);
36332 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36333 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36334 getBox : function(){
36335 if(this.collapsed){
36336 return this.collapsedEl.getBox();
36338 var box = this.el.getBox();
36340 var sw = this.split.el.getWidth();
36347 updateBox : function(box){
36348 if(this.split && !this.collapsed){
36349 var sw = this.split.el.getWidth();
36351 this.split.el.setLeft(box.x);
36352 this.split.el.setTop(box.y);
36353 this.split.el.setHeight(box.height);
36356 if(this.collapsed){
36357 this.updateBody(null, box.height);
36359 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36363 Roo.bootstrap.layout.West = function(config){
36364 config.region = "west";
36365 config.cursor = "w-resize";
36367 Roo.bootstrap.layout.Split.call(this, config);
36369 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36370 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36371 this.split.el.addClass("roo-layout-split-h");
36375 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36376 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36378 onRender: function(ctr, pos)
36380 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36381 var size = this.config.initialSize || this.config.width;
36382 if(typeof size != "undefined"){
36383 this.el.setWidth(size);
36387 getBox : function(){
36388 if(this.collapsed){
36389 return this.collapsedEl.getBox();
36391 var box = this.el.getBox();
36393 box.width += this.split.el.getWidth();
36398 updateBox : function(box){
36399 if(this.split && !this.collapsed){
36400 var sw = this.split.el.getWidth();
36402 this.split.el.setLeft(box.x+box.width);
36403 this.split.el.setTop(box.y);
36404 this.split.el.setHeight(box.height);
36406 if(this.collapsed){
36407 this.updateBody(null, box.height);
36409 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36412 Roo.namespace("Roo.bootstrap.panel");/*
36414 * Ext JS Library 1.1.1
36415 * Copyright(c) 2006-2007, Ext JS, LLC.
36417 * Originally Released Under LGPL - original licence link has changed is not relivant.
36420 * <script type="text/javascript">
36423 * @class Roo.ContentPanel
36424 * @extends Roo.util.Observable
36425 * A basic ContentPanel element.
36426 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36427 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36428 * @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
36429 * @cfg {Boolean} closable True if the panel can be closed/removed
36430 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36431 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36432 * @cfg {Toolbar} toolbar A toolbar for this panel
36433 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36434 * @cfg {String} title The title for this panel
36435 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36436 * @cfg {String} url Calls {@link #setUrl} with this value
36437 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36438 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36439 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36440 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36441 * @cfg {Boolean} badges render the badges
36444 * Create a new ContentPanel.
36445 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36446 * @param {String/Object} config A string to set only the title or a config object
36447 * @param {String} content (optional) Set the HTML content for this panel
36448 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36450 Roo.bootstrap.panel.Content = function( config){
36452 this.tpl = config.tpl || false;
36454 var el = config.el;
36455 var content = config.content;
36457 if(config.autoCreate){ // xtype is available if this is called from factory
36460 this.el = Roo.get(el);
36461 if(!this.el && config && config.autoCreate){
36462 if(typeof config.autoCreate == "object"){
36463 if(!config.autoCreate.id){
36464 config.autoCreate.id = config.id||el;
36466 this.el = Roo.DomHelper.append(document.body,
36467 config.autoCreate, true);
36469 var elcfg = { tag: "div",
36470 cls: "roo-layout-inactive-content",
36474 elcfg.html = config.html;
36478 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36481 this.closable = false;
36482 this.loaded = false;
36483 this.active = false;
36486 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36488 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36490 this.wrapEl = this.el; //this.el.wrap();
36492 if (config.toolbar.items) {
36493 ti = config.toolbar.items ;
36494 delete config.toolbar.items ;
36498 this.toolbar.render(this.wrapEl, 'before');
36499 for(var i =0;i < ti.length;i++) {
36500 // Roo.log(['add child', items[i]]);
36501 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36503 this.toolbar.items = nitems;
36504 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36505 delete config.toolbar;
36509 // xtype created footer. - not sure if will work as we normally have to render first..
36510 if (this.footer && !this.footer.el && this.footer.xtype) {
36511 if (!this.wrapEl) {
36512 this.wrapEl = this.el.wrap();
36515 this.footer.container = this.wrapEl.createChild();
36517 this.footer = Roo.factory(this.footer, Roo);
36522 if(typeof config == "string"){
36523 this.title = config;
36525 Roo.apply(this, config);
36529 this.resizeEl = Roo.get(this.resizeEl, true);
36531 this.resizeEl = this.el;
36533 // handle view.xtype
36541 * Fires when this panel is activated.
36542 * @param {Roo.ContentPanel} this
36546 * @event deactivate
36547 * Fires when this panel is activated.
36548 * @param {Roo.ContentPanel} this
36550 "deactivate" : true,
36554 * Fires when this panel is resized if fitToFrame is true.
36555 * @param {Roo.ContentPanel} this
36556 * @param {Number} width The width after any component adjustments
36557 * @param {Number} height The height after any component adjustments
36563 * Fires when this tab is created
36564 * @param {Roo.ContentPanel} this
36575 if(this.autoScroll){
36576 this.resizeEl.setStyle("overflow", "auto");
36578 // fix randome scrolling
36579 //this.el.on('scroll', function() {
36580 // Roo.log('fix random scolling');
36581 // this.scrollTo('top',0);
36584 content = content || this.content;
36586 this.setContent(content);
36588 if(config && config.url){
36589 this.setUrl(this.url, this.params, this.loadOnce);
36594 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36596 if (this.view && typeof(this.view.xtype) != 'undefined') {
36597 this.view.el = this.el.appendChild(document.createElement("div"));
36598 this.view = Roo.factory(this.view);
36599 this.view.render && this.view.render(false, '');
36603 this.fireEvent('render', this);
36606 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36610 setRegion : function(region){
36611 this.region = region;
36612 this.setActiveClass(region && !this.background);
36616 setActiveClass: function(state)
36619 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36620 this.el.setStyle('position','relative');
36622 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36623 this.el.setStyle('position', 'absolute');
36628 * Returns the toolbar for this Panel if one was configured.
36629 * @return {Roo.Toolbar}
36631 getToolbar : function(){
36632 return this.toolbar;
36635 setActiveState : function(active)
36637 this.active = active;
36638 this.setActiveClass(active);
36640 if(this.fireEvent("deactivate", this) === false){
36645 this.fireEvent("activate", this);
36649 * Updates this panel's element
36650 * @param {String} content The new content
36651 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36653 setContent : function(content, loadScripts){
36654 this.el.update(content, loadScripts);
36657 ignoreResize : function(w, h){
36658 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36661 this.lastSize = {width: w, height: h};
36666 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36667 * @return {Roo.UpdateManager} The UpdateManager
36669 getUpdateManager : function(){
36670 return this.el.getUpdateManager();
36673 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36674 * @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:
36677 url: "your-url.php",
36678 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36679 callback: yourFunction,
36680 scope: yourObject, //(optional scope)
36683 text: "Loading...",
36688 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36689 * 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.
36690 * @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}
36691 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36692 * @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.
36693 * @return {Roo.ContentPanel} this
36696 var um = this.el.getUpdateManager();
36697 um.update.apply(um, arguments);
36703 * 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.
36704 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36705 * @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)
36706 * @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)
36707 * @return {Roo.UpdateManager} The UpdateManager
36709 setUrl : function(url, params, loadOnce){
36710 if(this.refreshDelegate){
36711 this.removeListener("activate", this.refreshDelegate);
36713 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36714 this.on("activate", this.refreshDelegate);
36715 return this.el.getUpdateManager();
36718 _handleRefresh : function(url, params, loadOnce){
36719 if(!loadOnce || !this.loaded){
36720 var updater = this.el.getUpdateManager();
36721 updater.update(url, params, this._setLoaded.createDelegate(this));
36725 _setLoaded : function(){
36726 this.loaded = true;
36730 * Returns this panel's id
36733 getId : function(){
36738 * Returns this panel's element - used by regiosn to add.
36739 * @return {Roo.Element}
36741 getEl : function(){
36742 return this.wrapEl || this.el;
36747 adjustForComponents : function(width, height)
36749 //Roo.log('adjustForComponents ');
36750 if(this.resizeEl != this.el){
36751 width -= this.el.getFrameWidth('lr');
36752 height -= this.el.getFrameWidth('tb');
36755 var te = this.toolbar.getEl();
36756 te.setWidth(width);
36757 height -= te.getHeight();
36760 var te = this.footer.getEl();
36761 te.setWidth(width);
36762 height -= te.getHeight();
36766 if(this.adjustments){
36767 width += this.adjustments[0];
36768 height += this.adjustments[1];
36770 return {"width": width, "height": height};
36773 setSize : function(width, height){
36774 if(this.fitToFrame && !this.ignoreResize(width, height)){
36775 if(this.fitContainer && this.resizeEl != this.el){
36776 this.el.setSize(width, height);
36778 var size = this.adjustForComponents(width, height);
36779 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36780 this.fireEvent('resize', this, size.width, size.height);
36785 * Returns this panel's title
36788 getTitle : function(){
36790 if (typeof(this.title) != 'object') {
36795 for (var k in this.title) {
36796 if (!this.title.hasOwnProperty(k)) {
36800 if (k.indexOf('-') >= 0) {
36801 var s = k.split('-');
36802 for (var i = 0; i<s.length; i++) {
36803 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36806 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36813 * Set this panel's title
36814 * @param {String} title
36816 setTitle : function(title){
36817 this.title = title;
36819 this.region.updatePanelTitle(this, title);
36824 * Returns true is this panel was configured to be closable
36825 * @return {Boolean}
36827 isClosable : function(){
36828 return this.closable;
36831 beforeSlide : function(){
36833 this.resizeEl.clip();
36836 afterSlide : function(){
36838 this.resizeEl.unclip();
36842 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36843 * Will fail silently if the {@link #setUrl} method has not been called.
36844 * This does not activate the panel, just updates its content.
36846 refresh : function(){
36847 if(this.refreshDelegate){
36848 this.loaded = false;
36849 this.refreshDelegate();
36854 * Destroys this panel
36856 destroy : function(){
36857 this.el.removeAllListeners();
36858 var tempEl = document.createElement("span");
36859 tempEl.appendChild(this.el.dom);
36860 tempEl.innerHTML = "";
36866 * form - if the content panel contains a form - this is a reference to it.
36867 * @type {Roo.form.Form}
36871 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36872 * This contains a reference to it.
36878 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36888 * @param {Object} cfg Xtype definition of item to add.
36892 getChildContainer: function () {
36893 return this.getEl();
36898 var ret = new Roo.factory(cfg);
36903 if (cfg.xtype.match(/^Form$/)) {
36906 //if (this.footer) {
36907 // el = this.footer.container.insertSibling(false, 'before');
36909 el = this.el.createChild();
36912 this.form = new Roo.form.Form(cfg);
36915 if ( this.form.allItems.length) {
36916 this.form.render(el.dom);
36920 // should only have one of theses..
36921 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36922 // views.. should not be just added - used named prop 'view''
36924 cfg.el = this.el.appendChild(document.createElement("div"));
36927 var ret = new Roo.factory(cfg);
36929 ret.render && ret.render(false, ''); // render blank..
36939 * @class Roo.bootstrap.panel.Grid
36940 * @extends Roo.bootstrap.panel.Content
36942 * Create a new GridPanel.
36943 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36944 * @param {Object} config A the config object
36950 Roo.bootstrap.panel.Grid = function(config)
36954 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36955 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36957 config.el = this.wrapper;
36958 //this.el = this.wrapper;
36960 if (config.container) {
36961 // ctor'ed from a Border/panel.grid
36964 this.wrapper.setStyle("overflow", "hidden");
36965 this.wrapper.addClass('roo-grid-container');
36970 if(config.toolbar){
36971 var tool_el = this.wrapper.createChild();
36972 this.toolbar = Roo.factory(config.toolbar);
36974 if (config.toolbar.items) {
36975 ti = config.toolbar.items ;
36976 delete config.toolbar.items ;
36980 this.toolbar.render(tool_el);
36981 for(var i =0;i < ti.length;i++) {
36982 // Roo.log(['add child', items[i]]);
36983 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36985 this.toolbar.items = nitems;
36987 delete config.toolbar;
36990 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36991 config.grid.scrollBody = true;;
36992 config.grid.monitorWindowResize = false; // turn off autosizing
36993 config.grid.autoHeight = false;
36994 config.grid.autoWidth = false;
36996 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36998 if (config.background) {
36999 // render grid on panel activation (if panel background)
37000 this.on('activate', function(gp) {
37001 if (!gp.grid.rendered) {
37002 gp.grid.render(this.wrapper);
37003 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37008 this.grid.render(this.wrapper);
37009 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37012 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37013 // ??? needed ??? config.el = this.wrapper;
37018 // xtype created footer. - not sure if will work as we normally have to render first..
37019 if (this.footer && !this.footer.el && this.footer.xtype) {
37021 var ctr = this.grid.getView().getFooterPanel(true);
37022 this.footer.dataSource = this.grid.dataSource;
37023 this.footer = Roo.factory(this.footer, Roo);
37024 this.footer.render(ctr);
37034 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37035 getId : function(){
37036 return this.grid.id;
37040 * Returns the grid for this panel
37041 * @return {Roo.bootstrap.Table}
37043 getGrid : function(){
37047 setSize : function(width, height){
37048 if(!this.ignoreResize(width, height)){
37049 var grid = this.grid;
37050 var size = this.adjustForComponents(width, height);
37051 var gridel = grid.getGridEl();
37052 gridel.setSize(size.width, size.height);
37054 var thd = grid.getGridEl().select('thead',true).first();
37055 var tbd = grid.getGridEl().select('tbody', true).first();
37057 tbd.setSize(width, height - thd.getHeight());
37066 beforeSlide : function(){
37067 this.grid.getView().scroller.clip();
37070 afterSlide : function(){
37071 this.grid.getView().scroller.unclip();
37074 destroy : function(){
37075 this.grid.destroy();
37077 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37082 * @class Roo.bootstrap.panel.Nest
37083 * @extends Roo.bootstrap.panel.Content
37085 * Create a new Panel, that can contain a layout.Border.
37088 * @param {Roo.BorderLayout} layout The layout for this panel
37089 * @param {String/Object} config A string to set only the title or a config object
37091 Roo.bootstrap.panel.Nest = function(config)
37093 // construct with only one argument..
37094 /* FIXME - implement nicer consturctors
37095 if (layout.layout) {
37097 layout = config.layout;
37098 delete config.layout;
37100 if (layout.xtype && !layout.getEl) {
37101 // then layout needs constructing..
37102 layout = Roo.factory(layout, Roo);
37106 config.el = config.layout.getEl();
37108 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37110 config.layout.monitorWindowResize = false; // turn off autosizing
37111 this.layout = config.layout;
37112 this.layout.getEl().addClass("roo-layout-nested-layout");
37119 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37121 setSize : function(width, height){
37122 if(!this.ignoreResize(width, height)){
37123 var size = this.adjustForComponents(width, height);
37124 var el = this.layout.getEl();
37125 if (size.height < 1) {
37126 el.setWidth(size.width);
37128 el.setSize(size.width, size.height);
37130 var touch = el.dom.offsetWidth;
37131 this.layout.layout();
37132 // ie requires a double layout on the first pass
37133 if(Roo.isIE && !this.initialized){
37134 this.initialized = true;
37135 this.layout.layout();
37140 // activate all subpanels if not currently active..
37142 setActiveState : function(active){
37143 this.active = active;
37144 this.setActiveClass(active);
37147 this.fireEvent("deactivate", this);
37151 this.fireEvent("activate", this);
37152 // not sure if this should happen before or after..
37153 if (!this.layout) {
37154 return; // should not happen..
37157 for (var r in this.layout.regions) {
37158 reg = this.layout.getRegion(r);
37159 if (reg.getActivePanel()) {
37160 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37161 reg.setActivePanel(reg.getActivePanel());
37164 if (!reg.panels.length) {
37167 reg.showPanel(reg.getPanel(0));
37176 * Returns the nested BorderLayout for this panel
37177 * @return {Roo.BorderLayout}
37179 getLayout : function(){
37180 return this.layout;
37184 * Adds a xtype elements to the layout of the nested panel
37188 xtype : 'ContentPanel',
37195 xtype : 'NestedLayoutPanel',
37201 items : [ ... list of content panels or nested layout panels.. ]
37205 * @param {Object} cfg Xtype definition of item to add.
37207 addxtype : function(cfg) {
37208 return this.layout.addxtype(cfg);
37213 * Ext JS Library 1.1.1
37214 * Copyright(c) 2006-2007, Ext JS, LLC.
37216 * Originally Released Under LGPL - original licence link has changed is not relivant.
37219 * <script type="text/javascript">
37222 * @class Roo.TabPanel
37223 * @extends Roo.util.Observable
37224 * A lightweight tab container.
37228 // basic tabs 1, built from existing content
37229 var tabs = new Roo.TabPanel("tabs1");
37230 tabs.addTab("script", "View Script");
37231 tabs.addTab("markup", "View Markup");
37232 tabs.activate("script");
37234 // more advanced tabs, built from javascript
37235 var jtabs = new Roo.TabPanel("jtabs");
37236 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37238 // set up the UpdateManager
37239 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37240 var updater = tab2.getUpdateManager();
37241 updater.setDefaultUrl("ajax1.htm");
37242 tab2.on('activate', updater.refresh, updater, true);
37244 // Use setUrl for Ajax loading
37245 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37246 tab3.setUrl("ajax2.htm", null, true);
37249 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37252 jtabs.activate("jtabs-1");
37255 * Create a new TabPanel.
37256 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37257 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37259 Roo.bootstrap.panel.Tabs = function(config){
37261 * The container element for this TabPanel.
37262 * @type Roo.Element
37264 this.el = Roo.get(config.el);
37267 if(typeof config == "boolean"){
37268 this.tabPosition = config ? "bottom" : "top";
37270 Roo.apply(this, config);
37274 if(this.tabPosition == "bottom"){
37275 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37276 this.el.addClass("roo-tabs-bottom");
37278 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37279 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37280 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37282 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37284 if(this.tabPosition != "bottom"){
37285 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37286 * @type Roo.Element
37288 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37289 this.el.addClass("roo-tabs-top");
37293 this.bodyEl.setStyle("position", "relative");
37295 this.active = null;
37296 this.activateDelegate = this.activate.createDelegate(this);
37301 * Fires when the active tab changes
37302 * @param {Roo.TabPanel} this
37303 * @param {Roo.TabPanelItem} activePanel The new active tab
37307 * @event beforetabchange
37308 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37309 * @param {Roo.TabPanel} this
37310 * @param {Object} e Set cancel to true on this object to cancel the tab change
37311 * @param {Roo.TabPanelItem} tab The tab being changed to
37313 "beforetabchange" : true
37316 Roo.EventManager.onWindowResize(this.onResize, this);
37317 this.cpad = this.el.getPadding("lr");
37318 this.hiddenCount = 0;
37321 // toolbar on the tabbar support...
37322 if (this.toolbar) {
37323 alert("no toolbar support yet");
37324 this.toolbar = false;
37326 var tcfg = this.toolbar;
37327 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37328 this.toolbar = new Roo.Toolbar(tcfg);
37329 if (Roo.isSafari) {
37330 var tbl = tcfg.container.child('table', true);
37331 tbl.setAttribute('width', '100%');
37339 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37342 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37344 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37346 tabPosition : "top",
37348 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37350 currentTabWidth : 0,
37352 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37356 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37360 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37362 preferredTabWidth : 175,
37364 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37366 resizeTabs : false,
37368 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37370 monitorResize : true,
37372 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37377 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37378 * @param {String} id The id of the div to use <b>or create</b>
37379 * @param {String} text The text for the tab
37380 * @param {String} content (optional) Content to put in the TabPanelItem body
37381 * @param {Boolean} closable (optional) True to create a close icon on the tab
37382 * @return {Roo.TabPanelItem} The created TabPanelItem
37384 addTab : function(id, text, content, closable, tpl)
37386 var item = new Roo.bootstrap.panel.TabItem({
37390 closable : closable,
37393 this.addTabItem(item);
37395 item.setContent(content);
37401 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37402 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37403 * @return {Roo.TabPanelItem}
37405 getTab : function(id){
37406 return this.items[id];
37410 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37411 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37413 hideTab : function(id){
37414 var t = this.items[id];
37417 this.hiddenCount++;
37418 this.autoSizeTabs();
37423 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37424 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37426 unhideTab : function(id){
37427 var t = this.items[id];
37429 t.setHidden(false);
37430 this.hiddenCount--;
37431 this.autoSizeTabs();
37436 * Adds an existing {@link Roo.TabPanelItem}.
37437 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37439 addTabItem : function(item){
37440 this.items[item.id] = item;
37441 this.items.push(item);
37442 // if(this.resizeTabs){
37443 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37444 // this.autoSizeTabs();
37446 // item.autoSize();
37451 * Removes a {@link Roo.TabPanelItem}.
37452 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37454 removeTab : function(id){
37455 var items = this.items;
37456 var tab = items[id];
37457 if(!tab) { return; }
37458 var index = items.indexOf(tab);
37459 if(this.active == tab && items.length > 1){
37460 var newTab = this.getNextAvailable(index);
37465 this.stripEl.dom.removeChild(tab.pnode.dom);
37466 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37467 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37469 items.splice(index, 1);
37470 delete this.items[tab.id];
37471 tab.fireEvent("close", tab);
37472 tab.purgeListeners();
37473 this.autoSizeTabs();
37476 getNextAvailable : function(start){
37477 var items = this.items;
37479 // look for a next tab that will slide over to
37480 // replace the one being removed
37481 while(index < items.length){
37482 var item = items[++index];
37483 if(item && !item.isHidden()){
37487 // if one isn't found select the previous tab (on the left)
37490 var item = items[--index];
37491 if(item && !item.isHidden()){
37499 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37500 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37502 disableTab : function(id){
37503 var tab = this.items[id];
37504 if(tab && this.active != tab){
37510 * Enables a {@link Roo.TabPanelItem} that is disabled.
37511 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37513 enableTab : function(id){
37514 var tab = this.items[id];
37519 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37520 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37521 * @return {Roo.TabPanelItem} The TabPanelItem.
37523 activate : function(id){
37524 var tab = this.items[id];
37528 if(tab == this.active || tab.disabled){
37532 this.fireEvent("beforetabchange", this, e, tab);
37533 if(e.cancel !== true && !tab.disabled){
37535 this.active.hide();
37537 this.active = this.items[id];
37538 this.active.show();
37539 this.fireEvent("tabchange", this, this.active);
37545 * Gets the active {@link Roo.TabPanelItem}.
37546 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37548 getActiveTab : function(){
37549 return this.active;
37553 * Updates the tab body element to fit the height of the container element
37554 * for overflow scrolling
37555 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37557 syncHeight : function(targetHeight){
37558 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37559 var bm = this.bodyEl.getMargins();
37560 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37561 this.bodyEl.setHeight(newHeight);
37565 onResize : function(){
37566 if(this.monitorResize){
37567 this.autoSizeTabs();
37572 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37574 beginUpdate : function(){
37575 this.updating = true;
37579 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37581 endUpdate : function(){
37582 this.updating = false;
37583 this.autoSizeTabs();
37587 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37589 autoSizeTabs : function(){
37590 var count = this.items.length;
37591 var vcount = count - this.hiddenCount;
37592 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37595 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37596 var availWidth = Math.floor(w / vcount);
37597 var b = this.stripBody;
37598 if(b.getWidth() > w){
37599 var tabs = this.items;
37600 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37601 if(availWidth < this.minTabWidth){
37602 /*if(!this.sleft){ // incomplete scrolling code
37603 this.createScrollButtons();
37606 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37609 if(this.currentTabWidth < this.preferredTabWidth){
37610 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37616 * Returns the number of tabs in this TabPanel.
37619 getCount : function(){
37620 return this.items.length;
37624 * Resizes all the tabs to the passed width
37625 * @param {Number} The new width
37627 setTabWidth : function(width){
37628 this.currentTabWidth = width;
37629 for(var i = 0, len = this.items.length; i < len; i++) {
37630 if(!this.items[i].isHidden()) {
37631 this.items[i].setWidth(width);
37637 * Destroys this TabPanel
37638 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37640 destroy : function(removeEl){
37641 Roo.EventManager.removeResizeListener(this.onResize, this);
37642 for(var i = 0, len = this.items.length; i < len; i++){
37643 this.items[i].purgeListeners();
37645 if(removeEl === true){
37646 this.el.update("");
37651 createStrip : function(container)
37653 var strip = document.createElement("nav");
37654 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37655 container.appendChild(strip);
37659 createStripList : function(strip)
37661 // div wrapper for retard IE
37662 // returns the "tr" element.
37663 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37664 //'<div class="x-tabs-strip-wrap">'+
37665 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37666 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37667 return strip.firstChild; //.firstChild.firstChild.firstChild;
37669 createBody : function(container)
37671 var body = document.createElement("div");
37672 Roo.id(body, "tab-body");
37673 //Roo.fly(body).addClass("x-tabs-body");
37674 Roo.fly(body).addClass("tab-content");
37675 container.appendChild(body);
37678 createItemBody :function(bodyEl, id){
37679 var body = Roo.getDom(id);
37681 body = document.createElement("div");
37684 //Roo.fly(body).addClass("x-tabs-item-body");
37685 Roo.fly(body).addClass("tab-pane");
37686 bodyEl.insertBefore(body, bodyEl.firstChild);
37690 createStripElements : function(stripEl, text, closable, tpl)
37692 var td = document.createElement("li"); // was td..
37695 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37698 stripEl.appendChild(td);
37700 td.className = "x-tabs-closable";
37701 if(!this.closeTpl){
37702 this.closeTpl = new Roo.Template(
37703 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37704 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37705 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37708 var el = this.closeTpl.overwrite(td, {"text": text});
37709 var close = el.getElementsByTagName("div")[0];
37710 var inner = el.getElementsByTagName("em")[0];
37711 return {"el": el, "close": close, "inner": inner};
37714 // not sure what this is..
37715 // if(!this.tabTpl){
37716 //this.tabTpl = new Roo.Template(
37717 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37718 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37720 // this.tabTpl = new Roo.Template(
37721 // '<a href="#">' +
37722 // '<span unselectable="on"' +
37723 // (this.disableTooltips ? '' : ' title="{text}"') +
37724 // ' >{text}</span></a>'
37730 var template = tpl || this.tabTpl || false;
37734 template = new Roo.Template(
37736 '<span unselectable="on"' +
37737 (this.disableTooltips ? '' : ' title="{text}"') +
37738 ' >{text}</span></a>'
37742 switch (typeof(template)) {
37746 template = new Roo.Template(template);
37752 var el = template.overwrite(td, {"text": text});
37754 var inner = el.getElementsByTagName("span")[0];
37756 return {"el": el, "inner": inner};
37764 * @class Roo.TabPanelItem
37765 * @extends Roo.util.Observable
37766 * Represents an individual item (tab plus body) in a TabPanel.
37767 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37768 * @param {String} id The id of this TabPanelItem
37769 * @param {String} text The text for the tab of this TabPanelItem
37770 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37772 Roo.bootstrap.panel.TabItem = function(config){
37774 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37775 * @type Roo.TabPanel
37777 this.tabPanel = config.panel;
37779 * The id for this TabPanelItem
37782 this.id = config.id;
37784 this.disabled = false;
37786 this.text = config.text;
37788 this.loaded = false;
37789 this.closable = config.closable;
37792 * The body element for this TabPanelItem.
37793 * @type Roo.Element
37795 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37796 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37797 this.bodyEl.setStyle("display", "block");
37798 this.bodyEl.setStyle("zoom", "1");
37799 //this.hideAction();
37801 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37803 this.el = Roo.get(els.el);
37804 this.inner = Roo.get(els.inner, true);
37805 this.textEl = Roo.get(this.el.dom.firstChild, true);
37806 this.pnode = Roo.get(els.el.parentNode, true);
37807 // this.el.on("mousedown", this.onTabMouseDown, this);
37808 this.el.on("click", this.onTabClick, this);
37810 if(config.closable){
37811 var c = Roo.get(els.close, true);
37812 c.dom.title = this.closeText;
37813 c.addClassOnOver("close-over");
37814 c.on("click", this.closeClick, this);
37820 * Fires when this tab becomes the active tab.
37821 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37822 * @param {Roo.TabPanelItem} this
37826 * @event beforeclose
37827 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37828 * @param {Roo.TabPanelItem} this
37829 * @param {Object} e Set cancel to true on this object to cancel the close.
37831 "beforeclose": true,
37834 * Fires when this tab is closed.
37835 * @param {Roo.TabPanelItem} this
37839 * @event deactivate
37840 * Fires when this tab is no longer the active tab.
37841 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37842 * @param {Roo.TabPanelItem} this
37844 "deactivate" : true
37846 this.hidden = false;
37848 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37851 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37853 purgeListeners : function(){
37854 Roo.util.Observable.prototype.purgeListeners.call(this);
37855 this.el.removeAllListeners();
37858 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37861 this.pnode.addClass("active");
37864 this.tabPanel.stripWrap.repaint();
37866 this.fireEvent("activate", this.tabPanel, this);
37870 * Returns true if this tab is the active tab.
37871 * @return {Boolean}
37873 isActive : function(){
37874 return this.tabPanel.getActiveTab() == this;
37878 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37881 this.pnode.removeClass("active");
37883 this.fireEvent("deactivate", this.tabPanel, this);
37886 hideAction : function(){
37887 this.bodyEl.hide();
37888 this.bodyEl.setStyle("position", "absolute");
37889 this.bodyEl.setLeft("-20000px");
37890 this.bodyEl.setTop("-20000px");
37893 showAction : function(){
37894 this.bodyEl.setStyle("position", "relative");
37895 this.bodyEl.setTop("");
37896 this.bodyEl.setLeft("");
37897 this.bodyEl.show();
37901 * Set the tooltip for the tab.
37902 * @param {String} tooltip The tab's tooltip
37904 setTooltip : function(text){
37905 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37906 this.textEl.dom.qtip = text;
37907 this.textEl.dom.removeAttribute('title');
37909 this.textEl.dom.title = text;
37913 onTabClick : function(e){
37914 e.preventDefault();
37915 this.tabPanel.activate(this.id);
37918 onTabMouseDown : function(e){
37919 e.preventDefault();
37920 this.tabPanel.activate(this.id);
37923 getWidth : function(){
37924 return this.inner.getWidth();
37927 setWidth : function(width){
37928 var iwidth = width - this.pnode.getPadding("lr");
37929 this.inner.setWidth(iwidth);
37930 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37931 this.pnode.setWidth(width);
37935 * Show or hide the tab
37936 * @param {Boolean} hidden True to hide or false to show.
37938 setHidden : function(hidden){
37939 this.hidden = hidden;
37940 this.pnode.setStyle("display", hidden ? "none" : "");
37944 * Returns true if this tab is "hidden"
37945 * @return {Boolean}
37947 isHidden : function(){
37948 return this.hidden;
37952 * Returns the text for this tab
37955 getText : function(){
37959 autoSize : function(){
37960 //this.el.beginMeasure();
37961 this.textEl.setWidth(1);
37963 * #2804 [new] Tabs in Roojs
37964 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37966 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37967 //this.el.endMeasure();
37971 * Sets the text for the tab (Note: this also sets the tooltip text)
37972 * @param {String} text The tab's text and tooltip
37974 setText : function(text){
37976 this.textEl.update(text);
37977 this.setTooltip(text);
37978 //if(!this.tabPanel.resizeTabs){
37979 // this.autoSize();
37983 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37985 activate : function(){
37986 this.tabPanel.activate(this.id);
37990 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37992 disable : function(){
37993 if(this.tabPanel.active != this){
37994 this.disabled = true;
37995 this.pnode.addClass("disabled");
38000 * Enables this TabPanelItem if it was previously disabled.
38002 enable : function(){
38003 this.disabled = false;
38004 this.pnode.removeClass("disabled");
38008 * Sets the content for this TabPanelItem.
38009 * @param {String} content The content
38010 * @param {Boolean} loadScripts true to look for and load scripts
38012 setContent : function(content, loadScripts){
38013 this.bodyEl.update(content, loadScripts);
38017 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38018 * @return {Roo.UpdateManager} The UpdateManager
38020 getUpdateManager : function(){
38021 return this.bodyEl.getUpdateManager();
38025 * Set a URL to be used to load the content for this TabPanelItem.
38026 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38027 * @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)
38028 * @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)
38029 * @return {Roo.UpdateManager} The UpdateManager
38031 setUrl : function(url, params, loadOnce){
38032 if(this.refreshDelegate){
38033 this.un('activate', this.refreshDelegate);
38035 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38036 this.on("activate", this.refreshDelegate);
38037 return this.bodyEl.getUpdateManager();
38041 _handleRefresh : function(url, params, loadOnce){
38042 if(!loadOnce || !this.loaded){
38043 var updater = this.bodyEl.getUpdateManager();
38044 updater.update(url, params, this._setLoaded.createDelegate(this));
38049 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38050 * Will fail silently if the setUrl method has not been called.
38051 * This does not activate the panel, just updates its content.
38053 refresh : function(){
38054 if(this.refreshDelegate){
38055 this.loaded = false;
38056 this.refreshDelegate();
38061 _setLoaded : function(){
38062 this.loaded = true;
38066 closeClick : function(e){
38069 this.fireEvent("beforeclose", this, o);
38070 if(o.cancel !== true){
38071 this.tabPanel.removeTab(this.id);
38075 * The text displayed in the tooltip for the close icon.
38078 closeText : "Close this tab"
38081 * This script refer to:
38082 * Title: International Telephone Input
38083 * Author: Jack O'Connor
38084 * Code version: v12.1.12
38085 * Availability: https://github.com/jackocnr/intl-tel-input.git
38088 Roo.bootstrap.PhoneInputData = function() {
38091 "Afghanistan (افغانستان)",
38096 "Albania (Shqipëri)",
38101 "Algeria (الجزائر)",
38126 "Antigua and Barbuda",
38136 "Armenia (Հայաստան)",
38152 "Austria (Österreich)",
38157 "Azerbaijan (Azərbaycan)",
38167 "Bahrain (البحرين)",
38172 "Bangladesh (বাংলাদেশ)",
38182 "Belarus (Беларусь)",
38187 "Belgium (België)",
38217 "Bosnia and Herzegovina (Босна и Херцеговина)",
38232 "British Indian Ocean Territory",
38237 "British Virgin Islands",
38247 "Bulgaria (България)",
38257 "Burundi (Uburundi)",
38262 "Cambodia (កម្ពុជា)",
38267 "Cameroon (Cameroun)",
38276 ["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"]
38279 "Cape Verde (Kabu Verdi)",
38284 "Caribbean Netherlands",
38295 "Central African Republic (République centrafricaine)",
38315 "Christmas Island",
38321 "Cocos (Keeling) Islands",
38332 "Comoros (جزر القمر)",
38337 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38342 "Congo (Republic) (Congo-Brazzaville)",
38362 "Croatia (Hrvatska)",
38383 "Czech Republic (Česká republika)",
38388 "Denmark (Danmark)",
38403 "Dominican Republic (República Dominicana)",
38407 ["809", "829", "849"]
38425 "Equatorial Guinea (Guinea Ecuatorial)",
38445 "Falkland Islands (Islas Malvinas)",
38450 "Faroe Islands (Føroyar)",
38471 "French Guiana (Guyane française)",
38476 "French Polynesia (Polynésie française)",
38491 "Georgia (საქართველო)",
38496 "Germany (Deutschland)",
38516 "Greenland (Kalaallit Nunaat)",
38553 "Guinea-Bissau (Guiné Bissau)",
38578 "Hungary (Magyarország)",
38583 "Iceland (Ísland)",
38603 "Iraq (العراق)",
38619 "Israel (ישראל)",
38646 "Jordan (الأردن)",
38651 "Kazakhstan (Казахстан)",
38672 "Kuwait (الكويت)",
38677 "Kyrgyzstan (Кыргызстан)",
38687 "Latvia (Latvija)",
38692 "Lebanon (لبنان)",
38707 "Libya (ليبيا)",
38717 "Lithuania (Lietuva)",
38732 "Macedonia (FYROM) (Македонија)",
38737 "Madagascar (Madagasikara)",
38767 "Marshall Islands",
38777 "Mauritania (موريتانيا)",
38782 "Mauritius (Moris)",
38803 "Moldova (Republica Moldova)",
38813 "Mongolia (Монгол)",
38818 "Montenegro (Crna Gora)",
38828 "Morocco (المغرب)",
38834 "Mozambique (Moçambique)",
38839 "Myanmar (Burma) (မြန်မာ)",
38844 "Namibia (Namibië)",
38859 "Netherlands (Nederland)",
38864 "New Caledonia (Nouvelle-Calédonie)",
38899 "North Korea (조선 민주주의 인민 공화국)",
38904 "Northern Mariana Islands",
38920 "Pakistan (پاکستان)",
38930 "Palestine (فلسطين)",
38940 "Papua New Guinea",
38982 "Réunion (La Réunion)",
38988 "Romania (România)",
39004 "Saint Barthélemy",
39015 "Saint Kitts and Nevis",
39025 "Saint Martin (Saint-Martin (partie française))",
39031 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39036 "Saint Vincent and the Grenadines",
39051 "São Tomé and Príncipe (São Tomé e Príncipe)",
39056 "Saudi Arabia (المملكة العربية السعودية)",
39061 "Senegal (Sénégal)",
39091 "Slovakia (Slovensko)",
39096 "Slovenia (Slovenija)",
39106 "Somalia (Soomaaliya)",
39116 "South Korea (대한민국)",
39121 "South Sudan (جنوب السودان)",
39131 "Sri Lanka (ශ්රී ලංකාව)",
39136 "Sudan (السودان)",
39146 "Svalbard and Jan Mayen",
39157 "Sweden (Sverige)",
39162 "Switzerland (Schweiz)",
39167 "Syria (سوريا)",
39212 "Trinidad and Tobago",
39217 "Tunisia (تونس)",
39222 "Turkey (Türkiye)",
39232 "Turks and Caicos Islands",
39242 "U.S. Virgin Islands",
39252 "Ukraine (Україна)",
39257 "United Arab Emirates (الإمارات العربية المتحدة)",
39279 "Uzbekistan (Oʻzbekiston)",
39289 "Vatican City (Città del Vaticano)",
39300 "Vietnam (Việt Nam)",
39305 "Wallis and Futuna (Wallis-et-Futuna)",
39310 "Western Sahara (الصحراء الغربية)",
39316 "Yemen (اليمن)",
39340 * This script refer to:
39341 * Title: International Telephone Input
39342 * Author: Jack O'Connor
39343 * Code version: v12.1.12
39344 * Availability: https://github.com/jackocnr/intl-tel-input.git
39348 * @class Roo.bootstrap.PhoneInput
39349 * @extends Roo.bootstrap.TriggerField
39350 * An input with International dial-code selection
39352 * @cfg {String} defaultDialCode default '+852'
39353 * @cfg {Array} preferedCountries default []
39356 * Create a new PhoneInput.
39357 * @param {Object} config Configuration options
39360 Roo.bootstrap.PhoneInput = function(config) {
39361 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39364 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39366 listWidth: undefined,
39368 selectedClass: 'active',
39370 invalidClass : "has-warning",
39372 validClass: 'has-success',
39374 allowed: '0123456789',
39377 * @cfg {String} defaultDialCode The default dial code when initializing the input
39379 defaultDialCode: '+852',
39382 * @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
39384 preferedCountries: false,
39386 getAutoCreate : function()
39388 var data = Roo.bootstrap.PhoneInputData();
39389 var align = this.labelAlign || this.parentLabelAlign();
39392 this.allCountries = [];
39393 this.dialCodeMapping = [];
39395 for (var i = 0; i < data.length; i++) {
39397 this.allCountries[i] = {
39401 priority: c[3] || 0,
39402 areaCodes: c[4] || null
39404 this.dialCodeMapping[c[2]] = {
39407 priority: c[3] || 0,
39408 areaCodes: c[4] || null
39420 cls : 'form-control tel-input',
39421 autocomplete: 'new-password'
39424 var hiddenInput = {
39427 cls: 'hidden-tel-input'
39431 hiddenInput.name = this.name;
39434 if (this.disabled) {
39435 input.disabled = true;
39438 var flag_container = {
39455 cls: this.hasFeedback ? 'has-feedback' : '',
39461 cls: 'dial-code-holder',
39468 cls: 'roo-select2-container input-group',
39475 if (this.fieldLabel.length) {
39478 tooltip: 'This field is required'
39484 cls: 'control-label',
39490 html: this.fieldLabel
39493 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39499 if(this.indicatorpos == 'right') {
39500 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39507 if(align == 'left') {
39515 if(this.labelWidth > 12){
39516 label.style = "width: " + this.labelWidth + 'px';
39518 if(this.labelWidth < 13 && this.labelmd == 0){
39519 this.labelmd = this.labelWidth;
39521 if(this.labellg > 0){
39522 label.cls += ' col-lg-' + this.labellg;
39523 input.cls += ' col-lg-' + (12 - this.labellg);
39525 if(this.labelmd > 0){
39526 label.cls += ' col-md-' + this.labelmd;
39527 container.cls += ' col-md-' + (12 - this.labelmd);
39529 if(this.labelsm > 0){
39530 label.cls += ' col-sm-' + this.labelsm;
39531 container.cls += ' col-sm-' + (12 - this.labelsm);
39533 if(this.labelxs > 0){
39534 label.cls += ' col-xs-' + this.labelxs;
39535 container.cls += ' col-xs-' + (12 - this.labelxs);
39545 var settings = this;
39547 ['xs','sm','md','lg'].map(function(size){
39548 if (settings[size]) {
39549 cfg.cls += ' col-' + size + '-' + settings[size];
39553 this.store = new Roo.data.Store({
39554 proxy : new Roo.data.MemoryProxy({}),
39555 reader : new Roo.data.JsonReader({
39566 'name' : 'dialCode',
39570 'name' : 'priority',
39574 'name' : 'areaCodes',
39581 if(!this.preferedCountries) {
39582 this.preferedCountries = [
39589 var p = this.preferedCountries.reverse();
39592 for (var i = 0; i < p.length; i++) {
39593 for (var j = 0; j < this.allCountries.length; j++) {
39594 if(this.allCountries[j].iso2 == p[i]) {
39595 var t = this.allCountries[j];
39596 this.allCountries.splice(j,1);
39597 this.allCountries.unshift(t);
39603 this.store.proxy.data = {
39605 data: this.allCountries
39611 initEvents : function()
39614 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39616 this.indicator = this.indicatorEl();
39617 this.flag = this.flagEl();
39618 this.dialCodeHolder = this.dialCodeHolderEl();
39620 this.trigger = this.el.select('div.flag-box',true).first();
39621 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39626 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39627 _this.list.setWidth(lw);
39630 this.list.on('mouseover', this.onViewOver, this);
39631 this.list.on('mousemove', this.onViewMove, this);
39632 this.inputEl().on("keyup", this.onKeyUp, this);
39634 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39636 this.view = new Roo.View(this.list, this.tpl, {
39637 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39640 this.view.on('click', this.onViewClick, this);
39641 this.setValue(this.defaultDialCode);
39644 onTriggerClick : function(e)
39646 Roo.log('trigger click');
39651 if(this.isExpanded()){
39653 this.hasFocus = false;
39655 this.store.load({});
39656 this.hasFocus = true;
39661 isExpanded : function()
39663 return this.list.isVisible();
39666 collapse : function()
39668 if(!this.isExpanded()){
39672 Roo.get(document).un('mousedown', this.collapseIf, this);
39673 Roo.get(document).un('mousewheel', this.collapseIf, this);
39674 this.fireEvent('collapse', this);
39678 expand : function()
39682 if(this.isExpanded() || !this.hasFocus){
39686 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39687 this.list.setWidth(lw);
39690 this.restrictHeight();
39692 Roo.get(document).on('mousedown', this.collapseIf, this);
39693 Roo.get(document).on('mousewheel', this.collapseIf, this);
39695 this.fireEvent('expand', this);
39698 restrictHeight : function()
39700 this.list.alignTo(this.inputEl(), this.listAlign);
39701 this.list.alignTo(this.inputEl(), this.listAlign);
39704 onViewOver : function(e, t)
39706 if(this.inKeyMode){
39709 var item = this.view.findItemFromChild(t);
39712 var index = this.view.indexOf(item);
39713 this.select(index, false);
39718 onViewClick : function(view, doFocus, el, e)
39720 var index = this.view.getSelectedIndexes()[0];
39722 var r = this.store.getAt(index);
39725 this.onSelect(r, index);
39727 if(doFocus !== false && !this.blockFocus){
39728 this.inputEl().focus();
39732 onViewMove : function(e, t)
39734 this.inKeyMode = false;
39737 select : function(index, scrollIntoView)
39739 this.selectedIndex = index;
39740 this.view.select(index);
39741 if(scrollIntoView !== false){
39742 var el = this.view.getNode(index);
39744 this.list.scrollChildIntoView(el, false);
39749 createList : function()
39751 this.list = Roo.get(document.body).createChild({
39753 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39754 style: 'display:none'
39756 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39759 collapseIf : function(e)
39761 var in_combo = e.within(this.el);
39762 var in_list = e.within(this.list);
39763 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39765 if (in_combo || in_list || is_list) {
39771 onSelect : function(record, index)
39773 if(this.fireEvent('beforeselect', this, record, index) !== false){
39775 this.setFlagClass(record.data.iso2);
39776 this.setDialCode(record.data.dialCode);
39777 this.hasFocus = false;
39779 this.fireEvent('select', this, record, index);
39783 flagEl : function()
39785 var flag = this.el.select('div.flag',true).first();
39792 dialCodeHolderEl : function()
39794 var d = this.el.select('input.dial-code-holder',true).first();
39801 setDialCode : function(v)
39803 this.dialCodeHolder.dom.value = '+'+v;
39806 setFlagClass : function(n)
39808 this.flag.dom.className = 'flag '+n;
39811 getValue : function()
39813 var v = this.inputEl().getValue();
39814 if(this.dialCodeHolder) {
39815 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39820 setValue : function(v)
39822 var d = this.getDialCode(v);
39824 //invalid dial code
39825 if(v.length == 0 || !d || d.length == 0) {
39827 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39828 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39834 this.setFlagClass(this.dialCodeMapping[d].iso2);
39835 this.setDialCode(d);
39836 this.inputEl().dom.value = v.replace('+'+d,'');
39837 this.hiddenEl().dom.value = this.getValue();
39842 getDialCode : function(v = '')
39844 if (v.length == 0) {
39845 return this.dialCodeHolder.dom.value;
39849 if (v.charAt(0) != "+") {
39852 var numericChars = "";
39853 for (var i = 1; i < v.length; i++) {
39854 var c = v.charAt(i);
39857 if (this.dialCodeMapping[numericChars]) {
39858 dialCode = v.substr(1, i);
39860 if (numericChars.length == 4) {
39870 this.setValue(this.defaultDialCode);
39874 hiddenEl : function()
39876 return this.el.select('input.hidden-tel-input',true).first();
39879 onKeyUp : function(e){
39881 var k = e.getKey();
39882 var c = e.getCharCode();
39885 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39886 this.allowed.indexOf(String.fromCharCode(c)) === -1
39891 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39894 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39898 this.setValue(this.getValue());
39903 * @class Roo.bootstrap.MoneyField
39904 * @extends Roo.bootstrap.ComboBox
39905 * Bootstrap MoneyField class
39908 * Create a new MoneyField.
39909 * @param {Object} config Configuration options
39912 Roo.bootstrap.MoneyField = function(config) {
39914 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39918 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39921 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39923 allowDecimals : true,
39925 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39927 decimalSeparator : ".",
39929 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39931 decimalPrecision : 2,
39933 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39935 allowNegative : true,
39937 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39939 minValue : Number.NEGATIVE_INFINITY,
39941 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39943 maxValue : Number.MAX_VALUE,
39945 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39947 minText : "The minimum value for this field is {0}",
39949 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39951 maxText : "The maximum value for this field is {0}",
39953 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39954 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39956 nanText : "{0} is not a valid number",
39958 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39969 getAutoCreate : function()
39971 var align = this.labelAlign || this.parentLabelAlign();
39983 cls : 'form-control roo-money-amount-input',
39984 autocomplete: 'new-password'
39988 input.name = this.name;
39991 if (this.disabled) {
39992 input.disabled = true;
39995 var clg = 12 - this.inputlg;
39996 var cmd = 12 - this.inputmd;
39997 var csm = 12 - this.inputsm;
39998 var cxs = 12 - this.inputxs;
40002 cls : 'row roo-money-field',
40006 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40010 cls: 'roo-select2-container input-group',
40014 cls : 'form-control roo-money-currency-input',
40015 autocomplete: 'new-password',
40017 name : this.currencyName
40021 cls : 'input-group-addon',
40035 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40039 cls: this.hasFeedback ? 'has-feedback' : '',
40050 if (this.fieldLabel.length) {
40053 tooltip: 'This field is required'
40059 cls: 'control-label',
40065 html: this.fieldLabel
40068 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40074 if(this.indicatorpos == 'right') {
40075 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40082 if(align == 'left') {
40090 if(this.labelWidth > 12){
40091 label.style = "width: " + this.labelWidth + 'px';
40093 if(this.labelWidth < 13 && this.labelmd == 0){
40094 this.labelmd = this.labelWidth;
40096 if(this.labellg > 0){
40097 label.cls += ' col-lg-' + this.labellg;
40098 input.cls += ' col-lg-' + (12 - this.labellg);
40100 if(this.labelmd > 0){
40101 label.cls += ' col-md-' + this.labelmd;
40102 container.cls += ' col-md-' + (12 - this.labelmd);
40104 if(this.labelsm > 0){
40105 label.cls += ' col-sm-' + this.labelsm;
40106 container.cls += ' col-sm-' + (12 - this.labelsm);
40108 if(this.labelxs > 0){
40109 label.cls += ' col-xs-' + this.labelxs;
40110 container.cls += ' col-xs-' + (12 - this.labelxs);
40120 var settings = this;
40122 ['xs','sm','md','lg'].map(function(size){
40123 if (settings[size]) {
40124 cfg.cls += ' col-' + size + '-' + settings[size];
40132 initEvents : function()
40134 this.indicator = this.indicatorEl();
40136 this.initCurrencyEvent();
40138 this.initNumberEvent();
40142 initCurrencyEvent : function()
40145 throw "can not find store for combo";
40148 this.store = Roo.factory(this.store, Roo.data);
40149 this.store.parent = this;
40153 this.triggerEl = this.el.select('.input-group-addon', true).first();
40155 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40160 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40161 _this.list.setWidth(lw);
40164 this.list.on('mouseover', this.onViewOver, this);
40165 this.list.on('mousemove', this.onViewMove, this);
40166 this.list.on('scroll', this.onViewScroll, this);
40169 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40172 this.view = new Roo.View(this.list, this.tpl, {
40173 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40176 this.view.on('click', this.onViewClick, this);
40178 this.store.on('beforeload', this.onBeforeLoad, this);
40179 this.store.on('load', this.onLoad, this);
40180 this.store.on('loadexception', this.onLoadException, this);
40182 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40183 "up" : function(e){
40184 this.inKeyMode = true;
40188 "down" : function(e){
40189 if(!this.isExpanded()){
40190 this.onTriggerClick();
40192 this.inKeyMode = true;
40197 "enter" : function(e){
40200 if(this.fireEvent("specialkey", this, e)){
40201 this.onViewClick(false);
40207 "esc" : function(e){
40211 "tab" : function(e){
40214 if(this.fireEvent("specialkey", this, e)){
40215 this.onViewClick(false);
40223 doRelay : function(foo, bar, hname){
40224 if(hname == 'down' || this.scope.isExpanded()){
40225 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40233 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40237 initNumberEvent : function(e)
40239 this.inputEl().on("keydown" , this.fireKey, this);
40240 this.inputEl().on("focus", this.onFocus, this);
40241 this.inputEl().on("blur", this.onBlur, this);
40243 this.inputEl().relayEvent('keyup', this);
40245 if(this.indicator){
40246 this.indicator.addClass('invisible');
40249 this.originalValue = this.getValue();
40251 if(this.validationEvent == 'keyup'){
40252 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40253 this.inputEl().on('keyup', this.filterValidation, this);
40255 else if(this.validationEvent !== false){
40256 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40259 if(this.selectOnFocus){
40260 this.on("focus", this.preFocus, this);
40263 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40264 this.inputEl().on("keypress", this.filterKeys, this);
40266 this.inputEl().relayEvent('keypress', this);
40269 var allowed = "0123456789";
40271 if(this.allowDecimals){
40272 allowed += this.decimalSeparator;
40275 if(this.allowNegative){
40279 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40281 var keyPress = function(e){
40283 var k = e.getKey();
40285 var c = e.getCharCode();
40288 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40289 allowed.indexOf(String.fromCharCode(c)) === -1
40295 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40299 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40304 this.inputEl().on("keypress", keyPress, this);
40308 onTriggerClick : function(e)
40315 this.loadNext = false;
40317 if(this.isExpanded()){
40322 this.hasFocus = true;
40324 if(this.triggerAction == 'all') {
40325 this.doQuery(this.allQuery, true);
40329 this.doQuery(this.getRawValue());
40332 getCurrency : function()
40334 var v = this.currencyEl().getValue();
40339 restrictHeight : function()
40341 this.list.alignTo(this.currencyEl(), this.listAlign);
40342 this.list.alignTo(this.currencyEl(), this.listAlign);
40345 onViewClick : function(view, doFocus, el, e)
40347 var index = this.view.getSelectedIndexes()[0];
40349 var r = this.store.getAt(index);
40352 this.onSelect(r, index);
40356 onSelect : function(record, index){
40358 if(this.fireEvent('beforeselect', this, record, index) !== false){
40360 this.setFromCurrencyData(index > -1 ? record.data : false);
40364 this.fireEvent('select', this, record, index);
40368 setFromCurrencyData : function(o)
40372 this.lastCurrency = o;
40374 if (this.currencyField) {
40375 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40377 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40380 this.lastSelectionText = currency;
40382 this.setCurrency(currency);
40385 setFromData : function(o)
40389 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40391 this.setFromCurrencyData(c);
40396 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40398 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40401 this.setValue(value);
40405 setCurrency : function(v)
40407 this.currencyValue = v;
40410 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40415 setValue : function(v)
40417 v = this.fixPrecision(v);
40419 v = String(v).replace(".", this.decimalSeparator);
40424 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40429 getRawValue : function()
40431 var v = this.inputEl().getValue();
40436 getValue : function()
40438 return this.fixPrecision(this.parseValue(this.getRawValue()));
40441 parseValue : function(value)
40443 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40444 return isNaN(value) ? '' : value;
40447 fixPrecision : function(value)
40449 var nan = isNaN(value);
40451 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40452 return nan ? '' : value;
40455 return parseFloat(value).toFixed(this.decimalPrecision);
40458 decimalPrecisionFcn : function(v)
40460 return Math.floor(v);
40463 validateValue : function(value)
40465 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40469 var num = this.parseValue(value);
40472 this.markInvalid(String.format(this.nanText, value));
40476 if(num < this.minValue){
40477 this.markInvalid(String.format(this.minText, this.minValue));
40481 if(num > this.maxValue){
40482 this.markInvalid(String.format(this.maxText, this.maxValue));
40489 validate : function()
40491 if(this.disabled || this.allowBlank){
40496 var currency = this.getCurrency();
40498 if(this.validateValue(this.getRawValue()) && currency.length){
40503 this.markInvalid();
40507 getName: function()
40512 beforeBlur : function()
40518 var v = this.parseValue(this.getRawValue());
40525 onBlur : function()
40529 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40530 //this.el.removeClass(this.focusClass);
40533 this.hasFocus = false;
40535 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40539 var v = this.getValue();
40541 if(String(v) !== String(this.startValue)){
40542 this.fireEvent('change', this, v, this.startValue);
40545 this.fireEvent("blur", this);
40548 inputEl : function()
40550 return this.el.select('.roo-money-amount-input', true).first();
40553 currencyEl : function()
40555 return this.el.select('.roo-money-currency-input', true).first();