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){
316 Roo.log(['skip', cn]);
321 cn.render && cn.render(this[cntr](true));
324 // then add the element..
332 if (typeof (tree.menu) != 'undefined') {
333 tree.menu.parentType = cn.xtype;
334 tree.menu.triggerEl = cn.el;
335 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
339 if (!tree.items || !tree.items.length) {
341 //Roo.log(["no children", this]);
346 var items = tree.items;
349 //Roo.log(items.length);
351 if (!skip_children) {
352 for(var i =0;i < items.length;i++) {
353 // Roo.log(['add child', items[i]]);
354 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
360 //Roo.log("fire childrenrendered");
362 cn.fireEvent('childrenrendered', this);
367 * Show a component - removes 'hidden' class
372 this.el.removeClass('hidden');
376 * Hide a component - adds 'hidden' class
380 if (this.el && !this.el.hasClass('hidden')) {
381 this.el.addClass('hidden');
394 * @class Roo.bootstrap.Body
395 * @extends Roo.bootstrap.Component
396 * Bootstrap Body class
400 * @param {Object} config The config object
403 Roo.bootstrap.Body = function(config){
405 config = config || {};
407 Roo.bootstrap.Body.superclass.constructor.call(this, config);
408 this.el = Roo.get(config.el ? config.el : document.body );
409 if (this.cls && this.cls.length) {
410 Roo.get(document.body).addClass(this.cls);
414 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
416 is_body : true,// just to make sure it's constructed?
421 onRender : function(ct, position)
423 /* Roo.log("Roo.bootstrap.Body - onRender");
424 if (this.cls && this.cls.length) {
425 Roo.get(document.body).addClass(this.cls);
444 * @class Roo.bootstrap.ButtonGroup
445 * @extends Roo.bootstrap.Component
446 * Bootstrap ButtonGroup class
447 * @cfg {String} size lg | sm | xs (default empty normal)
448 * @cfg {String} align vertical | justified (default none)
449 * @cfg {String} direction up | down (default down)
450 * @cfg {Boolean} toolbar false | true
451 * @cfg {Boolean} btn true | false
456 * @param {Object} config The config object
459 Roo.bootstrap.ButtonGroup = function(config){
460 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
463 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
471 getAutoCreate : function(){
477 cfg.html = this.html || cfg.html;
488 if (['vertical','justified'].indexOf(this.align)!==-1) {
489 cfg.cls = 'btn-group-' + this.align;
491 if (this.align == 'justified') {
492 console.log(this.items);
496 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
497 cfg.cls += ' btn-group-' + this.size;
500 if (this.direction == 'up') {
501 cfg.cls += ' dropup' ;
517 * @class Roo.bootstrap.Button
518 * @extends Roo.bootstrap.Component
519 * Bootstrap Button class
520 * @cfg {String} html The button content
521 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
522 * @cfg {String} size ( lg | sm | xs)
523 * @cfg {String} tag ( a | input | submit)
524 * @cfg {String} href empty or href
525 * @cfg {Boolean} disabled default false;
526 * @cfg {Boolean} isClose default false;
527 * @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)
528 * @cfg {String} badge text for badge
529 * @cfg {String} theme default
530 * @cfg {Boolean} inverse
531 * @cfg {Boolean} toggle
532 * @cfg {String} ontext text for on toggle state
533 * @cfg {String} offtext text for off toggle state
534 * @cfg {Boolean} defaulton
535 * @cfg {Boolean} preventDefault default true
536 * @cfg {Boolean} removeClass remove the standard class..
537 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
540 * Create a new button
541 * @param {Object} config The config object
545 Roo.bootstrap.Button = function(config){
546 Roo.bootstrap.Button.superclass.constructor.call(this, config);
547 this.weightClass = ["btn-default",
559 * When a butotn is pressed
560 * @param {Roo.bootstrap.Button} this
561 * @param {Roo.EventObject} e
566 * After the button has been toggles
567 * @param {Roo.EventObject} e
568 * @param {boolean} pressed (also available as button.pressed)
574 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
592 preventDefault: true,
601 getAutoCreate : function(){
609 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
610 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
615 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
617 if (this.toggle == true) {
620 cls: 'slider-frame roo-button',
625 'data-off-text':'OFF',
626 cls: 'slider-button',
632 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
633 cfg.cls += ' '+this.weight;
642 cfg["aria-hidden"] = true;
644 cfg.html = "×";
650 if (this.theme==='default') {
651 cfg.cls = 'btn roo-button';
653 //if (this.parentType != 'Navbar') {
654 this.weight = this.weight.length ? this.weight : 'default';
656 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
658 cfg.cls += ' btn-' + this.weight;
660 } else if (this.theme==='glow') {
663 cfg.cls = 'btn-glow roo-button';
665 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' ' + this.weight;
673 this.cls += ' inverse';
678 cfg.cls += ' active';
682 cfg.disabled = 'disabled';
686 Roo.log('changing to ul' );
688 this.glyphicon = 'caret';
691 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
693 //gsRoo.log(this.parentType);
694 if (this.parentType === 'Navbar' && !this.parent().bar) {
695 Roo.log('changing to li?');
704 href : this.href || '#'
707 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
708 cfg.cls += ' dropdown';
715 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
717 if (this.glyphicon) {
718 cfg.html = ' ' + cfg.html;
723 cls: 'glyphicon glyphicon-' + this.glyphicon
733 // cfg.cls='btn roo-button';
737 var value = cfg.html;
742 cls: 'glyphicon glyphicon-' + this.glyphicon,
761 cfg.cls += ' dropdown';
762 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
765 if (cfg.tag !== 'a' && this.href !== '') {
766 throw "Tag must be a to set href.";
767 } else if (this.href.length > 0) {
768 cfg.href = this.href;
771 if(this.removeClass){
776 cfg.target = this.target;
781 initEvents: function() {
782 // Roo.log('init events?');
783 // Roo.log(this.el.dom);
786 if (typeof (this.menu) != 'undefined') {
787 this.menu.parentType = this.xtype;
788 this.menu.triggerEl = this.el;
789 this.addxtype(Roo.apply({}, this.menu));
793 if (this.el.hasClass('roo-button')) {
794 this.el.on('click', this.onClick, this);
796 this.el.select('.roo-button').on('click', this.onClick, this);
799 if(this.removeClass){
800 this.el.on('click', this.onClick, this);
803 this.el.enableDisplayMode();
806 onClick : function(e)
813 Roo.log('button on click ');
814 if(this.preventDefault){
817 if (this.pressed === true || this.pressed === false) {
818 this.pressed = !this.pressed;
819 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
820 this.fireEvent('toggle', this, e, this.pressed);
824 this.fireEvent('click', this, e);
828 * Enables this button
832 this.disabled = false;
833 this.el.removeClass('disabled');
837 * Disable this button
841 this.disabled = true;
842 this.el.addClass('disabled');
845 * sets the active state on/off,
846 * @param {Boolean} state (optional) Force a particular state
848 setActive : function(v) {
850 this.el[v ? 'addClass' : 'removeClass']('active');
853 * toggles the current active state
855 toggleActive : function()
857 var active = this.el.hasClass('active');
858 this.setActive(!active);
862 setText : function(str)
864 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
868 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
879 setWeight : function(str)
881 this.el.removeClass(this.weightClass);
882 this.el.addClass('btn-' + str);
896 * @class Roo.bootstrap.Column
897 * @extends Roo.bootstrap.Component
898 * Bootstrap Column class
899 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
900 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
901 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
902 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
903 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
904 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
905 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
906 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
909 * @cfg {Boolean} hidden (true|false) hide the element
910 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
911 * @cfg {String} fa (ban|check|...) font awesome icon
912 * @cfg {Number} fasize (1|2|....) font awsome size
914 * @cfg {String} icon (info-sign|check|...) glyphicon name
916 * @cfg {String} html content of column.
919 * Create a new Column
920 * @param {Object} config The config object
923 Roo.bootstrap.Column = function(config){
924 Roo.bootstrap.Column.superclass.constructor.call(this, config);
927 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
945 getAutoCreate : function(){
946 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
954 ['xs','sm','md','lg'].map(function(size){
955 //Roo.log( size + ':' + settings[size]);
957 if (settings[size+'off'] !== false) {
958 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
961 if (settings[size] === false) {
965 if (!settings[size]) { // 0 = hidden
966 cfg.cls += ' hidden-' + size;
969 cfg.cls += ' col-' + size + '-' + settings[size];
974 cfg.cls += ' hidden';
977 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
978 cfg.cls +=' alert alert-' + this.alert;
982 if (this.html.length) {
983 cfg.html = this.html;
987 if (this.fasize > 1) {
988 fasize = ' fa-' + this.fasize + 'x';
990 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
995 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1014 * @class Roo.bootstrap.Container
1015 * @extends Roo.bootstrap.Component
1016 * Bootstrap Container class
1017 * @cfg {Boolean} jumbotron is it a jumbotron element
1018 * @cfg {String} html content of element
1019 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1020 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1021 * @cfg {String} header content of header (for panel)
1022 * @cfg {String} footer content of footer (for panel)
1023 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1024 * @cfg {String} tag (header|aside|section) type of HTML tag.
1025 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1026 * @cfg {String} fa font awesome icon
1027 * @cfg {String} icon (info-sign|check|...) glyphicon name
1028 * @cfg {Boolean} hidden (true|false) hide the element
1029 * @cfg {Boolean} expandable (true|false) default false
1030 * @cfg {Boolean} expanded (true|false) default true
1031 * @cfg {String} rheader contet on the right of header
1032 * @cfg {Boolean} clickable (true|false) default false
1036 * Create a new Container
1037 * @param {Object} config The config object
1040 Roo.bootstrap.Container = function(config){
1041 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1047 * After the panel has been expand
1049 * @param {Roo.bootstrap.Container} this
1054 * After the panel has been collapsed
1056 * @param {Roo.bootstrap.Container} this
1061 * When a element is chick
1062 * @param {Roo.bootstrap.Container} this
1063 * @param {Roo.EventObject} e
1069 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1087 getChildContainer : function() {
1093 if (this.panel.length) {
1094 return this.el.select('.panel-body',true).first();
1101 getAutoCreate : function(){
1104 tag : this.tag || 'div',
1108 if (this.jumbotron) {
1109 cfg.cls = 'jumbotron';
1114 // - this is applied by the parent..
1116 // cfg.cls = this.cls + '';
1119 if (this.sticky.length) {
1121 var bd = Roo.get(document.body);
1122 if (!bd.hasClass('bootstrap-sticky')) {
1123 bd.addClass('bootstrap-sticky');
1124 Roo.select('html',true).setStyle('height', '100%');
1127 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1131 if (this.well.length) {
1132 switch (this.well) {
1135 cfg.cls +=' well well-' +this.well;
1144 cfg.cls += ' hidden';
1148 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1149 cfg.cls +=' alert alert-' + this.alert;
1154 if (this.panel.length) {
1155 cfg.cls += ' panel panel-' + this.panel;
1157 if (this.header.length) {
1161 if(this.expandable){
1163 cfg.cls = cfg.cls + ' expandable';
1167 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1175 cls : 'panel-title',
1176 html : (this.expandable ? ' ' : '') + this.header
1180 cls: 'panel-header-right',
1186 cls : 'panel-heading',
1187 style : this.expandable ? 'cursor: pointer' : '',
1195 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1200 if (this.footer.length) {
1202 cls : 'panel-footer',
1211 body.html = this.html || cfg.html;
1212 // prefix with the icons..
1214 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1217 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1222 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1223 cfg.cls = 'container';
1229 initEvents: function()
1231 if(this.expandable){
1232 var headerEl = this.headerEl();
1235 headerEl.on('click', this.onToggleClick, this);
1240 this.el.on('click', this.onClick, this);
1245 onToggleClick : function()
1247 var headerEl = this.headerEl();
1263 if(this.fireEvent('expand', this)) {
1265 this.expanded = true;
1267 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1269 this.el.select('.panel-body',true).first().removeClass('hide');
1271 var toggleEl = this.toggleEl();
1277 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1282 collapse : function()
1284 if(this.fireEvent('collapse', this)) {
1286 this.expanded = false;
1288 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1289 this.el.select('.panel-body',true).first().addClass('hide');
1291 var toggleEl = this.toggleEl();
1297 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1301 toggleEl : function()
1303 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1307 return this.el.select('.panel-heading .fa',true).first();
1310 headerEl : function()
1312 if(!this.el || !this.panel.length || !this.header.length){
1316 return this.el.select('.panel-heading',true).first()
1321 if(!this.el || !this.panel.length){
1325 return this.el.select('.panel-body',true).first()
1328 titleEl : function()
1330 if(!this.el || !this.panel.length || !this.header.length){
1334 return this.el.select('.panel-title',true).first();
1337 setTitle : function(v)
1339 var titleEl = this.titleEl();
1345 titleEl.dom.innerHTML = v;
1348 getTitle : function()
1351 var titleEl = this.titleEl();
1357 return titleEl.dom.innerHTML;
1360 setRightTitle : function(v)
1362 var t = this.el.select('.panel-header-right',true).first();
1368 t.dom.innerHTML = v;
1371 onClick : function(e)
1375 this.fireEvent('click', this, e);
1389 * @class Roo.bootstrap.Img
1390 * @extends Roo.bootstrap.Component
1391 * Bootstrap Img class
1392 * @cfg {Boolean} imgResponsive false | true
1393 * @cfg {String} border rounded | circle | thumbnail
1394 * @cfg {String} src image source
1395 * @cfg {String} alt image alternative text
1396 * @cfg {String} href a tag href
1397 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1398 * @cfg {String} xsUrl xs image source
1399 * @cfg {String} smUrl sm image source
1400 * @cfg {String} mdUrl md image source
1401 * @cfg {String} lgUrl lg image source
1404 * Create a new Input
1405 * @param {Object} config The config object
1408 Roo.bootstrap.Img = function(config){
1409 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1415 * The img click event for the img.
1416 * @param {Roo.EventObject} e
1422 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1424 imgResponsive: true,
1434 getAutoCreate : function()
1436 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1437 return this.createSingleImg();
1442 cls: 'roo-image-responsive-group',
1447 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1449 if(!_this[size + 'Url']){
1455 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1456 html: _this.html || cfg.html,
1457 src: _this[size + 'Url']
1460 img.cls += ' roo-image-responsive-' + size;
1462 var s = ['xs', 'sm', 'md', 'lg'];
1464 s.splice(s.indexOf(size), 1);
1466 Roo.each(s, function(ss){
1467 img.cls += ' hidden-' + ss;
1470 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1471 cfg.cls += ' img-' + _this.border;
1475 cfg.alt = _this.alt;
1488 a.target = _this.target;
1492 cfg.cn.push((_this.href) ? a : img);
1499 createSingleImg : function()
1503 cls: (this.imgResponsive) ? 'img-responsive' : '',
1505 src : 'about:blank' // just incase src get's set to undefined?!?
1508 cfg.html = this.html || cfg.html;
1510 cfg.src = this.src || cfg.src;
1512 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1513 cfg.cls += ' img-' + this.border;
1530 a.target = this.target;
1535 return (this.href) ? a : cfg;
1538 initEvents: function()
1541 this.el.on('click', this.onClick, this);
1546 onClick : function(e)
1548 Roo.log('img onclick');
1549 this.fireEvent('click', this, e);
1552 * Sets the url of the image - used to update it
1553 * @param {String} url the url of the image
1556 setSrc : function(url)
1560 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1561 this.el.dom.src = url;
1565 this.el.select('img', true).first().dom.src = url;
1581 * @class Roo.bootstrap.Link
1582 * @extends Roo.bootstrap.Component
1583 * Bootstrap Link Class
1584 * @cfg {String} alt image alternative text
1585 * @cfg {String} href a tag href
1586 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1587 * @cfg {String} html the content of the link.
1588 * @cfg {String} anchor name for the anchor link
1589 * @cfg {String} fa - favicon
1591 * @cfg {Boolean} preventDefault (true | false) default false
1595 * Create a new Input
1596 * @param {Object} config The config object
1599 Roo.bootstrap.Link = function(config){
1600 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1606 * The img click event for the img.
1607 * @param {Roo.EventObject} e
1613 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1617 preventDefault: false,
1623 getAutoCreate : function()
1625 var html = this.html || '';
1627 if (this.fa !== false) {
1628 html = '<i class="fa fa-' + this.fa + '"></i>';
1633 // anchor's do not require html/href...
1634 if (this.anchor === false) {
1636 cfg.href = this.href || '#';
1638 cfg.name = this.anchor;
1639 if (this.html !== false || this.fa !== false) {
1642 if (this.href !== false) {
1643 cfg.href = this.href;
1647 if(this.alt !== false){
1652 if(this.target !== false) {
1653 cfg.target = this.target;
1659 initEvents: function() {
1661 if(!this.href || this.preventDefault){
1662 this.el.on('click', this.onClick, this);
1666 onClick : function(e)
1668 if(this.preventDefault){
1671 //Roo.log('img onclick');
1672 this.fireEvent('click', this, e);
1685 * @class Roo.bootstrap.Header
1686 * @extends Roo.bootstrap.Component
1687 * Bootstrap Header class
1688 * @cfg {String} html content of header
1689 * @cfg {Number} level (1|2|3|4|5|6) default 1
1692 * Create a new Header
1693 * @param {Object} config The config object
1697 Roo.bootstrap.Header = function(config){
1698 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1701 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1709 getAutoCreate : function(){
1714 tag: 'h' + (1 *this.level),
1715 html: this.html || ''
1727 * Ext JS Library 1.1.1
1728 * Copyright(c) 2006-2007, Ext JS, LLC.
1730 * Originally Released Under LGPL - original licence link has changed is not relivant.
1733 * <script type="text/javascript">
1737 * @class Roo.bootstrap.MenuMgr
1738 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1741 Roo.bootstrap.MenuMgr = function(){
1742 var menus, active, groups = {}, attached = false, lastShow = new Date();
1744 // private - called when first menu is created
1747 active = new Roo.util.MixedCollection();
1748 Roo.get(document).addKeyListener(27, function(){
1749 if(active.length > 0){
1757 if(active && active.length > 0){
1758 var c = active.clone();
1768 if(active.length < 1){
1769 Roo.get(document).un("mouseup", onMouseDown);
1777 var last = active.last();
1778 lastShow = new Date();
1781 Roo.get(document).on("mouseup", onMouseDown);
1786 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1787 m.parentMenu.activeChild = m;
1788 }else if(last && last.isVisible()){
1789 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1794 function onBeforeHide(m){
1796 m.activeChild.hide();
1798 if(m.autoHideTimer){
1799 clearTimeout(m.autoHideTimer);
1800 delete m.autoHideTimer;
1805 function onBeforeShow(m){
1806 var pm = m.parentMenu;
1807 if(!pm && !m.allowOtherMenus){
1809 }else if(pm && pm.activeChild && active != m){
1810 pm.activeChild.hide();
1814 // private this should really trigger on mouseup..
1815 function onMouseDown(e){
1816 Roo.log("on Mouse Up");
1818 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1819 Roo.log("MenuManager hideAll");
1828 function onBeforeCheck(mi, state){
1830 var g = groups[mi.group];
1831 for(var i = 0, l = g.length; i < l; i++){
1833 g[i].setChecked(false);
1842 * Hides all menus that are currently visible
1844 hideAll : function(){
1849 register : function(menu){
1853 menus[menu.id] = menu;
1854 menu.on("beforehide", onBeforeHide);
1855 menu.on("hide", onHide);
1856 menu.on("beforeshow", onBeforeShow);
1857 menu.on("show", onShow);
1859 if(g && menu.events["checkchange"]){
1863 groups[g].push(menu);
1864 menu.on("checkchange", onCheck);
1869 * Returns a {@link Roo.menu.Menu} object
1870 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1871 * be used to generate and return a new Menu instance.
1873 get : function(menu){
1874 if(typeof menu == "string"){ // menu id
1876 }else if(menu.events){ // menu instance
1879 /*else if(typeof menu.length == 'number'){ // array of menu items?
1880 return new Roo.bootstrap.Menu({items:menu});
1881 }else{ // otherwise, must be a config
1882 return new Roo.bootstrap.Menu(menu);
1889 unregister : function(menu){
1890 delete menus[menu.id];
1891 menu.un("beforehide", onBeforeHide);
1892 menu.un("hide", onHide);
1893 menu.un("beforeshow", onBeforeShow);
1894 menu.un("show", onShow);
1896 if(g && menu.events["checkchange"]){
1897 groups[g].remove(menu);
1898 menu.un("checkchange", onCheck);
1903 registerCheckable : function(menuItem){
1904 var g = menuItem.group;
1909 groups[g].push(menuItem);
1910 menuItem.on("beforecheckchange", onBeforeCheck);
1915 unregisterCheckable : function(menuItem){
1916 var g = menuItem.group;
1918 groups[g].remove(menuItem);
1919 menuItem.un("beforecheckchange", onBeforeCheck);
1931 * @class Roo.bootstrap.Menu
1932 * @extends Roo.bootstrap.Component
1933 * Bootstrap Menu class - container for MenuItems
1934 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1935 * @cfg {bool} hidden if the menu should be hidden when rendered.
1936 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1937 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1941 * @param {Object} config The config object
1945 Roo.bootstrap.Menu = function(config){
1946 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1947 if (this.registerMenu && this.type != 'treeview') {
1948 Roo.bootstrap.MenuMgr.register(this);
1953 * Fires before this menu is displayed
1954 * @param {Roo.menu.Menu} this
1959 * Fires before this menu is hidden
1960 * @param {Roo.menu.Menu} this
1965 * Fires after this menu is displayed
1966 * @param {Roo.menu.Menu} this
1971 * Fires after this menu is hidden
1972 * @param {Roo.menu.Menu} this
1977 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1978 * @param {Roo.menu.Menu} this
1979 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1980 * @param {Roo.EventObject} e
1985 * Fires when the mouse is hovering over this menu
1986 * @param {Roo.menu.Menu} this
1987 * @param {Roo.EventObject} e
1988 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1993 * Fires when the mouse exits this menu
1994 * @param {Roo.menu.Menu} this
1995 * @param {Roo.EventObject} e
1996 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2001 * Fires when a menu item contained in this menu is clicked
2002 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2003 * @param {Roo.EventObject} e
2007 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2010 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2014 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2017 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2019 registerMenu : true,
2021 menuItems :false, // stores the menu items..
2031 getChildContainer : function() {
2035 getAutoCreate : function(){
2037 //if (['right'].indexOf(this.align)!==-1) {
2038 // cfg.cn[1].cls += ' pull-right'
2044 cls : 'dropdown-menu' ,
2045 style : 'z-index:1000'
2049 if (this.type === 'submenu') {
2050 cfg.cls = 'submenu active';
2052 if (this.type === 'treeview') {
2053 cfg.cls = 'treeview-menu';
2058 initEvents : function() {
2060 // Roo.log("ADD event");
2061 // Roo.log(this.triggerEl.dom);
2063 this.triggerEl.on('click', this.onTriggerClick, this);
2065 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2067 this.triggerEl.addClass('dropdown-toggle');
2070 this.el.on('touchstart' , this.onTouch, this);
2072 this.el.on('click' , this.onClick, this);
2074 this.el.on("mouseover", this.onMouseOver, this);
2075 this.el.on("mouseout", this.onMouseOut, this);
2079 findTargetItem : function(e)
2081 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2085 //Roo.log(t); Roo.log(t.id);
2087 //Roo.log(this.menuitems);
2088 return this.menuitems.get(t.id);
2090 //return this.items.get(t.menuItemId);
2096 onTouch : function(e)
2098 Roo.log("menu.onTouch");
2099 //e.stopEvent(); this make the user popdown broken
2103 onClick : function(e)
2105 Roo.log("menu.onClick");
2107 var t = this.findTargetItem(e);
2108 if(!t || t.isContainer){
2113 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2114 if(t == this.activeItem && t.shouldDeactivate(e)){
2115 this.activeItem.deactivate();
2116 delete this.activeItem;
2120 this.setActiveItem(t, true);
2128 Roo.log('pass click event');
2132 this.fireEvent("click", this, t, e);
2136 if(!t.href.length || t.href == '#'){
2137 (function() { _this.hide(); }).defer(100);
2142 onMouseOver : function(e){
2143 var t = this.findTargetItem(e);
2146 // if(t.canActivate && !t.disabled){
2147 // this.setActiveItem(t, true);
2151 this.fireEvent("mouseover", this, e, t);
2153 isVisible : function(){
2154 return !this.hidden;
2156 onMouseOut : function(e){
2157 var t = this.findTargetItem(e);
2160 // if(t == this.activeItem && t.shouldDeactivate(e)){
2161 // this.activeItem.deactivate();
2162 // delete this.activeItem;
2165 this.fireEvent("mouseout", this, e, t);
2170 * Displays this menu relative to another element
2171 * @param {String/HTMLElement/Roo.Element} element The element to align to
2172 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2173 * the element (defaults to this.defaultAlign)
2174 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2176 show : function(el, pos, parentMenu){
2177 this.parentMenu = parentMenu;
2181 this.fireEvent("beforeshow", this);
2182 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2185 * Displays this menu at a specific xy position
2186 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2187 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2189 showAt : function(xy, parentMenu, /* private: */_e){
2190 this.parentMenu = parentMenu;
2195 this.fireEvent("beforeshow", this);
2196 //xy = this.el.adjustForConstraints(xy);
2200 this.hideMenuItems();
2201 this.hidden = false;
2202 this.triggerEl.addClass('open');
2204 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2205 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2208 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2213 this.fireEvent("show", this);
2219 this.doFocus.defer(50, this);
2223 doFocus : function(){
2225 this.focusEl.focus();
2230 * Hides this menu and optionally all parent menus
2231 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2233 hide : function(deep)
2236 this.hideMenuItems();
2237 if(this.el && this.isVisible()){
2238 this.fireEvent("beforehide", this);
2239 if(this.activeItem){
2240 this.activeItem.deactivate();
2241 this.activeItem = null;
2243 this.triggerEl.removeClass('open');;
2245 this.fireEvent("hide", this);
2247 if(deep === true && this.parentMenu){
2248 this.parentMenu.hide(true);
2252 onTriggerClick : function(e)
2254 Roo.log('trigger click');
2256 var target = e.getTarget();
2258 Roo.log(target.nodeName.toLowerCase());
2260 if(target.nodeName.toLowerCase() === 'i'){
2266 onTriggerPress : function(e)
2268 Roo.log('trigger press');
2269 //Roo.log(e.getTarget());
2270 // Roo.log(this.triggerEl.dom);
2272 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2273 var pel = Roo.get(e.getTarget());
2274 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2275 Roo.log('is treeview or dropdown?');
2279 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2283 if (this.isVisible()) {
2288 this.show(this.triggerEl, false, false);
2291 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2298 hideMenuItems : function()
2300 Roo.log("hide Menu Items");
2304 //$(backdrop).remove()
2305 this.el.select('.open',true).each(function(aa) {
2307 aa.removeClass('open');
2308 //var parent = getParent($(this))
2309 //var relatedTarget = { relatedTarget: this }
2311 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2312 //if (e.isDefaultPrevented()) return
2313 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2316 addxtypeChild : function (tree, cntr) {
2317 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2319 this.menuitems.add(comp);
2340 * @class Roo.bootstrap.MenuItem
2341 * @extends Roo.bootstrap.Component
2342 * Bootstrap MenuItem class
2343 * @cfg {String} html the menu label
2344 * @cfg {String} href the link
2345 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2346 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2347 * @cfg {Boolean} active used on sidebars to highlight active itesm
2348 * @cfg {String} fa favicon to show on left of menu item.
2349 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2353 * Create a new MenuItem
2354 * @param {Object} config The config object
2358 Roo.bootstrap.MenuItem = function(config){
2359 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2364 * The raw click event for the entire grid.
2365 * @param {Roo.bootstrap.MenuItem} this
2366 * @param {Roo.EventObject} e
2372 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2376 preventDefault: false,
2377 isContainer : false,
2381 getAutoCreate : function(){
2383 if(this.isContainer){
2386 cls: 'dropdown-menu-item'
2400 if (this.fa !== false) {
2403 cls : 'fa fa-' + this.fa
2412 cls: 'dropdown-menu-item',
2415 if (this.parent().type == 'treeview') {
2416 cfg.cls = 'treeview-menu';
2419 cfg.cls += ' active';
2424 anc.href = this.href || cfg.cn[0].href ;
2425 ctag.html = this.html || cfg.cn[0].html ;
2429 initEvents: function()
2431 if (this.parent().type == 'treeview') {
2432 this.el.select('a').on('click', this.onClick, this);
2436 this.menu.parentType = this.xtype;
2437 this.menu.triggerEl = this.el;
2438 this.menu = this.addxtype(Roo.apply({}, this.menu));
2442 onClick : function(e)
2444 Roo.log('item on click ');
2446 if(this.preventDefault){
2449 //this.parent().hideMenuItems();
2451 this.fireEvent('click', this, e);
2470 * @class Roo.bootstrap.MenuSeparator
2471 * @extends Roo.bootstrap.Component
2472 * Bootstrap MenuSeparator class
2475 * Create a new MenuItem
2476 * @param {Object} config The config object
2480 Roo.bootstrap.MenuSeparator = function(config){
2481 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2484 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2486 getAutoCreate : function(){
2505 * @class Roo.bootstrap.Modal
2506 * @extends Roo.bootstrap.Component
2507 * Bootstrap Modal class
2508 * @cfg {String} title Title of dialog
2509 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2510 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2511 * @cfg {Boolean} specificTitle default false
2512 * @cfg {Array} buttons Array of buttons or standard button set..
2513 * @cfg {String} buttonPosition (left|right|center) default right
2514 * @cfg {Boolean} animate default true
2515 * @cfg {Boolean} allow_close default true
2516 * @cfg {Boolean} fitwindow default false
2517 * @cfg {String} size (sm|lg) default empty
2521 * Create a new Modal Dialog
2522 * @param {Object} config The config object
2525 Roo.bootstrap.Modal = function(config){
2526 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2531 * The raw btnclick event for the button
2532 * @param {Roo.EventObject} e
2537 * Fire when dialog resize
2538 * @param {Roo.bootstrap.Modal} this
2539 * @param {Roo.EventObject} e
2543 this.buttons = this.buttons || [];
2546 this.tmpl = Roo.factory(this.tmpl);
2551 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2553 title : 'test dialog',
2563 specificTitle: false,
2565 buttonPosition: 'right',
2584 onRender : function(ct, position)
2586 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2589 var cfg = Roo.apply({}, this.getAutoCreate());
2592 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2594 //if (!cfg.name.length) {
2598 cfg.cls += ' ' + this.cls;
2601 cfg.style = this.style;
2603 this.el = Roo.get(document.body).createChild(cfg, position);
2605 //var type = this.el.dom.type;
2608 if(this.tabIndex !== undefined){
2609 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2612 this.dialogEl = this.el.select('.modal-dialog',true).first();
2613 this.bodyEl = this.el.select('.modal-body',true).first();
2614 this.closeEl = this.el.select('.modal-header .close', true).first();
2615 this.headerEl = this.el.select('.modal-header',true).first();
2616 this.titleEl = this.el.select('.modal-title',true).first();
2617 this.footerEl = this.el.select('.modal-footer',true).first();
2619 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2620 this.maskEl.enableDisplayMode("block");
2622 //this.el.addClass("x-dlg-modal");
2624 if (this.buttons.length) {
2625 Roo.each(this.buttons, function(bb) {
2626 var b = Roo.apply({}, bb);
2627 b.xns = b.xns || Roo.bootstrap;
2628 b.xtype = b.xtype || 'Button';
2629 if (typeof(b.listeners) == 'undefined') {
2630 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2633 var btn = Roo.factory(b);
2635 btn.render(this.el.select('.modal-footer div').first());
2639 // render the children.
2642 if(typeof(this.items) != 'undefined'){
2643 var items = this.items;
2646 for(var i =0;i < items.length;i++) {
2647 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2651 this.items = nitems;
2653 // where are these used - they used to be body/close/footer
2657 //this.el.addClass([this.fieldClass, this.cls]);
2661 getAutoCreate : function(){
2666 html : this.html || ''
2671 cls : 'modal-title',
2675 if(this.specificTitle){
2681 if (this.allow_close) {
2693 if(this.size.length){
2694 size = 'modal-' + this.size;
2699 style : 'display: none',
2702 cls: "modal-dialog " + size,
2705 cls : "modal-content",
2708 cls : 'modal-header',
2713 cls : 'modal-footer',
2717 cls: 'btn-' + this.buttonPosition
2734 modal.cls += ' fade';
2740 getChildContainer : function() {
2745 getButtonContainer : function() {
2746 return this.el.select('.modal-footer div',true).first();
2749 initEvents : function()
2751 if (this.allow_close) {
2752 this.closeEl.on('click', this.hide, this);
2754 Roo.EventManager.onWindowResize(this.resize, this, true);
2761 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2762 if (this.fitwindow) {
2763 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2764 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2769 setSize : function(w,h)
2779 if (!this.rendered) {
2783 this.el.setStyle('display', 'block');
2785 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2788 this.el.addClass('in');
2791 this.el.addClass('in');
2795 // not sure how we can show data in here..
2797 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2800 Roo.get(document.body).addClass("x-body-masked");
2802 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2803 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2808 this.fireEvent('show', this);
2810 // set zindex here - otherwise it appears to be ignored...
2811 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2814 this.items.forEach( function(e) {
2815 e.layout ? e.layout() : false;
2823 if(this.fireEvent("beforehide", this) !== false){
2825 Roo.get(document.body).removeClass("x-body-masked");
2826 this.el.removeClass('in');
2827 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2829 if(this.animate){ // why
2831 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2833 this.el.setStyle('display', 'none');
2835 this.fireEvent('hide', this);
2839 addButton : function(str, cb)
2843 var b = Roo.apply({}, { html : str } );
2844 b.xns = b.xns || Roo.bootstrap;
2845 b.xtype = b.xtype || 'Button';
2846 if (typeof(b.listeners) == 'undefined') {
2847 b.listeners = { click : cb.createDelegate(this) };
2850 var btn = Roo.factory(b);
2852 btn.render(this.el.select('.modal-footer div').first());
2858 setDefaultButton : function(btn)
2860 //this.el.select('.modal-footer').()
2864 resizeTo: function(w,h)
2868 this.dialogEl.setWidth(w);
2869 if (this.diff === false) {
2870 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2873 this.bodyEl.setHeight(h-this.diff);
2875 this.fireEvent('resize', this);
2878 setContentSize : function(w, h)
2882 onButtonClick: function(btn,e)
2885 this.fireEvent('btnclick', btn.name, e);
2888 * Set the title of the Dialog
2889 * @param {String} str new Title
2891 setTitle: function(str) {
2892 this.titleEl.dom.innerHTML = str;
2895 * Set the body of the Dialog
2896 * @param {String} str new Title
2898 setBody: function(str) {
2899 this.bodyEl.dom.innerHTML = str;
2902 * Set the body of the Dialog using the template
2903 * @param {Obj} data - apply this data to the template and replace the body contents.
2905 applyBody: function(obj)
2908 Roo.log("Error - using apply Body without a template");
2911 this.tmpl.overwrite(this.bodyEl, obj);
2917 Roo.apply(Roo.bootstrap.Modal, {
2919 * Button config that displays a single OK button
2928 * Button config that displays Yes and No buttons
2944 * Button config that displays OK and Cancel buttons
2959 * Button config that displays Yes, No and Cancel buttons
2983 * messagebox - can be used as a replace
2987 * @class Roo.MessageBox
2988 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2992 Roo.Msg.alert('Status', 'Changes saved successfully.');
2994 // Prompt for user data:
2995 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2997 // process text value...
3001 // Show a dialog using config options:
3003 title:'Save Changes?',
3004 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3005 buttons: Roo.Msg.YESNOCANCEL,
3012 Roo.bootstrap.MessageBox = function(){
3013 var dlg, opt, mask, waitTimer;
3014 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3015 var buttons, activeTextEl, bwidth;
3019 var handleButton = function(button){
3021 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3025 var handleHide = function(){
3027 dlg.el.removeClass(opt.cls);
3030 // Roo.TaskMgr.stop(waitTimer);
3031 // waitTimer = null;
3036 var updateButtons = function(b){
3039 buttons["ok"].hide();
3040 buttons["cancel"].hide();
3041 buttons["yes"].hide();
3042 buttons["no"].hide();
3043 //dlg.footer.dom.style.display = 'none';
3046 dlg.footerEl.dom.style.display = '';
3047 for(var k in buttons){
3048 if(typeof buttons[k] != "function"){
3051 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3052 width += buttons[k].el.getWidth()+15;
3062 var handleEsc = function(d, k, e){
3063 if(opt && opt.closable !== false){
3073 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3074 * @return {Roo.BasicDialog} The BasicDialog element
3076 getDialog : function(){
3078 dlg = new Roo.bootstrap.Modal( {
3081 //constraintoviewport:false,
3083 //collapsible : false,
3088 //buttonAlign:"center",
3089 closeClick : function(){
3090 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3093 handleButton("cancel");
3098 dlg.on("hide", handleHide);
3100 //dlg.addKeyListener(27, handleEsc);
3102 this.buttons = buttons;
3103 var bt = this.buttonText;
3104 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3105 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3106 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3107 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3109 bodyEl = dlg.bodyEl.createChild({
3111 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3112 '<textarea class="roo-mb-textarea"></textarea>' +
3113 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3115 msgEl = bodyEl.dom.firstChild;
3116 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3117 textboxEl.enableDisplayMode();
3118 textboxEl.addKeyListener([10,13], function(){
3119 if(dlg.isVisible() && opt && opt.buttons){
3122 }else if(opt.buttons.yes){
3123 handleButton("yes");
3127 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3128 textareaEl.enableDisplayMode();
3129 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3130 progressEl.enableDisplayMode();
3132 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3133 var pf = progressEl.dom.firstChild;
3135 pp = Roo.get(pf.firstChild);
3136 pp.setHeight(pf.offsetHeight);
3144 * Updates the message box body text
3145 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3146 * the XHTML-compliant non-breaking space character '&#160;')
3147 * @return {Roo.MessageBox} This message box
3149 updateText : function(text)
3151 if(!dlg.isVisible() && !opt.width){
3152 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3153 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3155 msgEl.innerHTML = text || ' ';
3157 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3158 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3160 Math.min(opt.width || cw , this.maxWidth),
3161 Math.max(opt.minWidth || this.minWidth, bwidth)
3164 activeTextEl.setWidth(w);
3166 if(dlg.isVisible()){
3167 dlg.fixedcenter = false;
3169 // to big, make it scroll. = But as usual stupid IE does not support
3172 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3173 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3174 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3176 bodyEl.dom.style.height = '';
3177 bodyEl.dom.style.overflowY = '';
3180 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3182 bodyEl.dom.style.overflowX = '';
3185 dlg.setContentSize(w, bodyEl.getHeight());
3186 if(dlg.isVisible()){
3187 dlg.fixedcenter = true;
3193 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3194 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3195 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3196 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3197 * @return {Roo.MessageBox} This message box
3199 updateProgress : function(value, text){
3201 this.updateText(text);
3204 if (pp) { // weird bug on my firefox - for some reason this is not defined
3205 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3206 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3212 * Returns true if the message box is currently displayed
3213 * @return {Boolean} True if the message box is visible, else false
3215 isVisible : function(){
3216 return dlg && dlg.isVisible();
3220 * Hides the message box if it is displayed
3223 if(this.isVisible()){
3229 * Displays a new message box, or reinitializes an existing message box, based on the config options
3230 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3231 * The following config object properties are supported:
3233 Property Type Description
3234 ---------- --------------- ------------------------------------------------------------------------------------
3235 animEl String/Element An id or Element from which the message box should animate as it opens and
3236 closes (defaults to undefined)
3237 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3238 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3239 closable Boolean False to hide the top-right close button (defaults to true). Note that
3240 progress and wait dialogs will ignore this property and always hide the
3241 close button as they can only be closed programmatically.
3242 cls String A custom CSS class to apply to the message box element
3243 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3244 displayed (defaults to 75)
3245 fn Function A callback function to execute after closing the dialog. The arguments to the
3246 function will be btn (the name of the button that was clicked, if applicable,
3247 e.g. "ok"), and text (the value of the active text field, if applicable).
3248 Progress and wait dialogs will ignore this option since they do not respond to
3249 user actions and can only be closed programmatically, so any required function
3250 should be called by the same code after it closes the dialog.
3251 icon String A CSS class that provides a background image to be used as an icon for
3252 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3253 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3254 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3255 modal Boolean False to allow user interaction with the page while the message box is
3256 displayed (defaults to true)
3257 msg String A string that will replace the existing message box body text (defaults
3258 to the XHTML-compliant non-breaking space character ' ')
3259 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3260 progress Boolean True to display a progress bar (defaults to false)
3261 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3262 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3263 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3264 title String The title text
3265 value String The string value to set into the active textbox element if displayed
3266 wait Boolean True to display a progress bar (defaults to false)
3267 width Number The width of the dialog in pixels
3274 msg: 'Please enter your address:',
3276 buttons: Roo.MessageBox.OKCANCEL,
3279 animEl: 'addAddressBtn'
3282 * @param {Object} config Configuration options
3283 * @return {Roo.MessageBox} This message box
3285 show : function(options)
3288 // this causes nightmares if you show one dialog after another
3289 // especially on callbacks..
3291 if(this.isVisible()){
3294 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3295 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3296 Roo.log("New Dialog Message:" + options.msg )
3297 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3298 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3301 var d = this.getDialog();
3303 d.setTitle(opt.title || " ");
3304 d.closeEl.setDisplayed(opt.closable !== false);
3305 activeTextEl = textboxEl;
3306 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3311 textareaEl.setHeight(typeof opt.multiline == "number" ?
3312 opt.multiline : this.defaultTextHeight);
3313 activeTextEl = textareaEl;
3322 progressEl.setDisplayed(opt.progress === true);
3323 this.updateProgress(0);
3324 activeTextEl.dom.value = opt.value || "";
3326 dlg.setDefaultButton(activeTextEl);
3328 var bs = opt.buttons;
3332 }else if(bs && bs.yes){
3333 db = buttons["yes"];
3335 dlg.setDefaultButton(db);
3337 bwidth = updateButtons(opt.buttons);
3338 this.updateText(opt.msg);
3340 d.el.addClass(opt.cls);
3342 d.proxyDrag = opt.proxyDrag === true;
3343 d.modal = opt.modal !== false;
3344 d.mask = opt.modal !== false ? mask : false;
3346 // force it to the end of the z-index stack so it gets a cursor in FF
3347 document.body.appendChild(dlg.el.dom);
3348 d.animateTarget = null;
3349 d.show(options.animEl);
3355 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3356 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3357 * and closing the message box when the process is complete.
3358 * @param {String} title The title bar text
3359 * @param {String} msg The message box body text
3360 * @return {Roo.MessageBox} This message box
3362 progress : function(title, msg){
3369 minWidth: this.minProgressWidth,
3376 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3377 * If a callback function is passed it will be called after the user clicks the button, and the
3378 * id of the button that was clicked will be passed as the only parameter to the callback
3379 * (could also be the top-right close button).
3380 * @param {String} title The title bar text
3381 * @param {String} msg The message box body text
3382 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3383 * @param {Object} scope (optional) The scope of the callback function
3384 * @return {Roo.MessageBox} This message box
3386 alert : function(title, msg, fn, scope)
3401 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3402 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3403 * You are responsible for closing the message box when the process is complete.
3404 * @param {String} msg The message box body text
3405 * @param {String} title (optional) The title bar text
3406 * @return {Roo.MessageBox} This message box
3408 wait : function(msg, title){
3419 waitTimer = Roo.TaskMgr.start({
3421 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3429 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3430 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3431 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3432 * @param {String} title The title bar text
3433 * @param {String} msg The message box body text
3434 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3435 * @param {Object} scope (optional) The scope of the callback function
3436 * @return {Roo.MessageBox} This message box
3438 confirm : function(title, msg, fn, scope){
3442 buttons: this.YESNO,
3451 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3452 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3453 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3454 * (could also be the top-right close button) and the text that was entered will be passed as the two
3455 * parameters to the callback.
3456 * @param {String} title The title bar text
3457 * @param {String} msg The message box body text
3458 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3459 * @param {Object} scope (optional) The scope of the callback function
3460 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3461 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3462 * @return {Roo.MessageBox} This message box
3464 prompt : function(title, msg, fn, scope, multiline){
3468 buttons: this.OKCANCEL,
3473 multiline: multiline,
3480 * Button config that displays a single OK button
3485 * Button config that displays Yes and No buttons
3488 YESNO : {yes:true, no:true},
3490 * Button config that displays OK and Cancel buttons
3493 OKCANCEL : {ok:true, cancel:true},
3495 * Button config that displays Yes, No and Cancel buttons
3498 YESNOCANCEL : {yes:true, no:true, cancel:true},
3501 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3504 defaultTextHeight : 75,
3506 * The maximum width in pixels of the message box (defaults to 600)
3511 * The minimum width in pixels of the message box (defaults to 100)
3516 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3517 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3520 minProgressWidth : 250,
3522 * An object containing the default button text strings that can be overriden for localized language support.
3523 * Supported properties are: ok, cancel, yes and no.
3524 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3537 * Shorthand for {@link Roo.MessageBox}
3539 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3540 Roo.Msg = Roo.Msg || Roo.MessageBox;
3549 * @class Roo.bootstrap.Navbar
3550 * @extends Roo.bootstrap.Component
3551 * Bootstrap Navbar class
3554 * Create a new Navbar
3555 * @param {Object} config The config object
3559 Roo.bootstrap.Navbar = function(config){
3560 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3564 * @event beforetoggle
3565 * Fire before toggle the menu
3566 * @param {Roo.EventObject} e
3568 "beforetoggle" : true
3572 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3581 getAutoCreate : function(){
3584 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3588 initEvents :function ()
3590 //Roo.log(this.el.select('.navbar-toggle',true));
3591 this.el.select('.navbar-toggle',true).on('click', function() {
3592 if(this.fireEvent('beforetoggle', this) !== false){
3593 this.el.select('.navbar-collapse',true).toggleClass('in');
3603 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3605 var size = this.el.getSize();
3606 this.maskEl.setSize(size.width, size.height);
3607 this.maskEl.enableDisplayMode("block");
3616 getChildContainer : function()
3618 if (this.el.select('.collapse').getCount()) {
3619 return this.el.select('.collapse',true).first();
3652 * @class Roo.bootstrap.NavSimplebar
3653 * @extends Roo.bootstrap.Navbar
3654 * Bootstrap Sidebar class
3656 * @cfg {Boolean} inverse is inverted color
3658 * @cfg {String} type (nav | pills | tabs)
3659 * @cfg {Boolean} arrangement stacked | justified
3660 * @cfg {String} align (left | right) alignment
3662 * @cfg {Boolean} main (true|false) main nav bar? default false
3663 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3665 * @cfg {String} tag (header|footer|nav|div) default is nav
3671 * Create a new Sidebar
3672 * @param {Object} config The config object
3676 Roo.bootstrap.NavSimplebar = function(config){
3677 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3680 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3696 getAutoCreate : function(){
3700 tag : this.tag || 'div',
3713 this.type = this.type || 'nav';
3714 if (['tabs','pills'].indexOf(this.type)!==-1) {
3715 cfg.cn[0].cls += ' nav-' + this.type
3719 if (this.type!=='nav') {
3720 Roo.log('nav type must be nav/tabs/pills')
3722 cfg.cn[0].cls += ' navbar-nav'
3728 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3729 cfg.cn[0].cls += ' nav-' + this.arrangement;
3733 if (this.align === 'right') {
3734 cfg.cn[0].cls += ' navbar-right';
3738 cfg.cls += ' navbar-inverse';
3765 * @class Roo.bootstrap.NavHeaderbar
3766 * @extends Roo.bootstrap.NavSimplebar
3767 * Bootstrap Sidebar class
3769 * @cfg {String} brand what is brand
3770 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3771 * @cfg {String} brand_href href of the brand
3772 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3773 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3774 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3775 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3778 * Create a new Sidebar
3779 * @param {Object} config The config object
3783 Roo.bootstrap.NavHeaderbar = function(config){
3784 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3788 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3795 desktopCenter : false,
3798 getAutoCreate : function(){
3801 tag: this.nav || 'nav',
3808 if (this.desktopCenter) {
3809 cn.push({cls : 'container', cn : []});
3816 cls: 'navbar-header',
3821 cls: 'navbar-toggle',
3822 'data-toggle': 'collapse',
3827 html: 'Toggle navigation'
3849 cls: 'collapse navbar-collapse',
3853 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3855 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3856 cfg.cls += ' navbar-' + this.position;
3858 // tag can override this..
3860 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3863 if (this.brand !== '') {
3866 href: this.brand_href ? this.brand_href : '#',
3867 cls: 'navbar-brand',
3875 cfg.cls += ' main-nav';
3883 getHeaderChildContainer : function()
3885 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3886 return this.el.select('.navbar-header',true).first();
3889 return this.getChildContainer();
3893 initEvents : function()
3895 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3897 if (this.autohide) {
3902 Roo.get(document).on('scroll',function(e) {
3903 var ns = Roo.get(document).getScroll().top;
3904 var os = prevScroll;
3908 ft.removeClass('slideDown');
3909 ft.addClass('slideUp');
3912 ft.removeClass('slideUp');
3913 ft.addClass('slideDown');
3934 * @class Roo.bootstrap.NavSidebar
3935 * @extends Roo.bootstrap.Navbar
3936 * Bootstrap Sidebar class
3939 * Create a new Sidebar
3940 * @param {Object} config The config object
3944 Roo.bootstrap.NavSidebar = function(config){
3945 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3948 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3950 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3952 getAutoCreate : function(){
3957 cls: 'sidebar sidebar-nav'
3979 * @class Roo.bootstrap.NavGroup
3980 * @extends Roo.bootstrap.Component
3981 * Bootstrap NavGroup class
3982 * @cfg {String} align (left|right)
3983 * @cfg {Boolean} inverse
3984 * @cfg {String} type (nav|pills|tab) default nav
3985 * @cfg {String} navId - reference Id for navbar.
3989 * Create a new nav group
3990 * @param {Object} config The config object
3993 Roo.bootstrap.NavGroup = function(config){
3994 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3997 Roo.bootstrap.NavGroup.register(this);
4001 * Fires when the active item changes
4002 * @param {Roo.bootstrap.NavGroup} this
4003 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4004 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4011 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4022 getAutoCreate : function()
4024 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4031 if (['tabs','pills'].indexOf(this.type)!==-1) {
4032 cfg.cls += ' nav-' + this.type
4034 if (this.type!=='nav') {
4035 Roo.log('nav type must be nav/tabs/pills')
4037 cfg.cls += ' navbar-nav'
4040 if (this.parent() && this.parent().sidebar) {
4043 cls: 'dashboard-menu sidebar-menu'
4049 if (this.form === true) {
4055 if (this.align === 'right') {
4056 cfg.cls += ' navbar-right';
4058 cfg.cls += ' navbar-left';
4062 if (this.align === 'right') {
4063 cfg.cls += ' navbar-right';
4067 cfg.cls += ' navbar-inverse';
4075 * sets the active Navigation item
4076 * @param {Roo.bootstrap.NavItem} the new current navitem
4078 setActiveItem : function(item)
4081 Roo.each(this.navItems, function(v){
4086 v.setActive(false, true);
4093 item.setActive(true, true);
4094 this.fireEvent('changed', this, item, prev);
4099 * gets the active Navigation item
4100 * @return {Roo.bootstrap.NavItem} the current navitem
4102 getActive : function()
4106 Roo.each(this.navItems, function(v){
4117 indexOfNav : function()
4121 Roo.each(this.navItems, function(v,i){
4132 * adds a Navigation item
4133 * @param {Roo.bootstrap.NavItem} the navitem to add
4135 addItem : function(cfg)
4137 var cn = new Roo.bootstrap.NavItem(cfg);
4139 cn.parentId = this.id;
4140 cn.onRender(this.el, null);
4144 * register a Navigation item
4145 * @param {Roo.bootstrap.NavItem} the navitem to add
4147 register : function(item)
4149 this.navItems.push( item);
4150 item.navId = this.navId;
4155 * clear all the Navigation item
4158 clearAll : function()
4161 this.el.dom.innerHTML = '';
4164 getNavItem: function(tabId)
4167 Roo.each(this.navItems, function(e) {
4168 if (e.tabId == tabId) {
4178 setActiveNext : function()
4180 var i = this.indexOfNav(this.getActive());
4181 if (i > this.navItems.length) {
4184 this.setActiveItem(this.navItems[i+1]);
4186 setActivePrev : function()
4188 var i = this.indexOfNav(this.getActive());
4192 this.setActiveItem(this.navItems[i-1]);
4194 clearWasActive : function(except) {
4195 Roo.each(this.navItems, function(e) {
4196 if (e.tabId != except.tabId && e.was_active) {
4197 e.was_active = false;
4204 getWasActive : function ()
4207 Roo.each(this.navItems, function(e) {
4222 Roo.apply(Roo.bootstrap.NavGroup, {
4226 * register a Navigation Group
4227 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4229 register : function(navgrp)
4231 this.groups[navgrp.navId] = navgrp;
4235 * fetch a Navigation Group based on the navigation ID
4236 * @param {string} the navgroup to add
4237 * @returns {Roo.bootstrap.NavGroup} the navgroup
4239 get: function(navId) {
4240 if (typeof(this.groups[navId]) == 'undefined') {
4242 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4244 return this.groups[navId] ;
4259 * @class Roo.bootstrap.NavItem
4260 * @extends Roo.bootstrap.Component
4261 * Bootstrap Navbar.NavItem class
4262 * @cfg {String} href link to
4263 * @cfg {String} html content of button
4264 * @cfg {String} badge text inside badge
4265 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4266 * @cfg {String} glyphicon name of glyphicon
4267 * @cfg {String} icon name of font awesome icon
4268 * @cfg {Boolean} active Is item active
4269 * @cfg {Boolean} disabled Is item disabled
4271 * @cfg {Boolean} preventDefault (true | false) default false
4272 * @cfg {String} tabId the tab that this item activates.
4273 * @cfg {String} tagtype (a|span) render as a href or span?
4274 * @cfg {Boolean} animateRef (true|false) link to element default false
4277 * Create a new Navbar Item
4278 * @param {Object} config The config object
4280 Roo.bootstrap.NavItem = function(config){
4281 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4286 * The raw click event for the entire grid.
4287 * @param {Roo.EventObject} e
4292 * Fires when the active item active state changes
4293 * @param {Roo.bootstrap.NavItem} this
4294 * @param {boolean} state the new state
4300 * Fires when scroll to element
4301 * @param {Roo.bootstrap.NavItem} this
4302 * @param {Object} options
4303 * @param {Roo.EventObject} e
4311 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4319 preventDefault : false,
4326 getAutoCreate : function(){
4335 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4337 if (this.disabled) {
4338 cfg.cls += ' disabled';
4341 if (this.href || this.html || this.glyphicon || this.icon) {
4345 href : this.href || "#",
4346 html: this.html || ''
4351 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4354 if(this.glyphicon) {
4355 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4360 cfg.cn[0].html += " <span class='caret'></span>";
4364 if (this.badge !== '') {
4366 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4374 initEvents: function()
4376 if (typeof (this.menu) != 'undefined') {
4377 this.menu.parentType = this.xtype;
4378 this.menu.triggerEl = this.el;
4379 this.menu = this.addxtype(Roo.apply({}, this.menu));
4382 this.el.select('a',true).on('click', this.onClick, this);
4384 if(this.tagtype == 'span'){
4385 this.el.select('span',true).on('click', this.onClick, this);
4388 // at this point parent should be available..
4389 this.parent().register(this);
4392 onClick : function(e)
4394 if (e.getTarget('.dropdown-menu-item')) {
4395 // did you click on a menu itemm.... - then don't trigger onclick..
4400 this.preventDefault ||
4403 Roo.log("NavItem - prevent Default?");
4407 if (this.disabled) {
4411 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4412 if (tg && tg.transition) {
4413 Roo.log("waiting for the transitionend");
4419 //Roo.log("fire event clicked");
4420 if(this.fireEvent('click', this, e) === false){
4424 if(this.tagtype == 'span'){
4428 //Roo.log(this.href);
4429 var ael = this.el.select('a',true).first();
4432 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4433 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4434 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4435 return; // ignore... - it's a 'hash' to another page.
4437 Roo.log("NavItem - prevent Default?");
4439 this.scrollToElement(e);
4443 var p = this.parent();
4445 if (['tabs','pills'].indexOf(p.type)!==-1) {
4446 if (typeof(p.setActiveItem) !== 'undefined') {
4447 p.setActiveItem(this);
4451 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4452 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4453 // remove the collapsed menu expand...
4454 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4458 isActive: function () {
4461 setActive : function(state, fire, is_was_active)
4463 if (this.active && !state && this.navId) {
4464 this.was_active = true;
4465 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4467 nv.clearWasActive(this);
4471 this.active = state;
4474 this.el.removeClass('active');
4475 } else if (!this.el.hasClass('active')) {
4476 this.el.addClass('active');
4479 this.fireEvent('changed', this, state);
4482 // show a panel if it's registered and related..
4484 if (!this.navId || !this.tabId || !state || is_was_active) {
4488 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4492 var pan = tg.getPanelByName(this.tabId);
4496 // if we can not flip to new panel - go back to old nav highlight..
4497 if (false == tg.showPanel(pan)) {
4498 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4500 var onav = nv.getWasActive();
4502 onav.setActive(true, false, true);
4511 // this should not be here...
4512 setDisabled : function(state)
4514 this.disabled = state;
4516 this.el.removeClass('disabled');
4517 } else if (!this.el.hasClass('disabled')) {
4518 this.el.addClass('disabled');
4524 * Fetch the element to display the tooltip on.
4525 * @return {Roo.Element} defaults to this.el
4527 tooltipEl : function()
4529 return this.el.select('' + this.tagtype + '', true).first();
4532 scrollToElement : function(e)
4534 var c = document.body;
4537 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4539 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4540 c = document.documentElement;
4543 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4549 var o = target.calcOffsetsTo(c);
4556 this.fireEvent('scrollto', this, options, e);
4558 Roo.get(c).scrollTo('top', options.value, true);
4571 * <span> icon </span>
4572 * <span> text </span>
4573 * <span>badge </span>
4577 * @class Roo.bootstrap.NavSidebarItem
4578 * @extends Roo.bootstrap.NavItem
4579 * Bootstrap Navbar.NavSidebarItem class
4580 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4581 * {Boolean} open is the menu open
4582 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4583 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4584 * {String} buttonSize (sm|md|lg)the extra classes for the button
4585 * {Boolean} showArrow show arrow next to the text (default true)
4587 * Create a new Navbar Button
4588 * @param {Object} config The config object
4590 Roo.bootstrap.NavSidebarItem = function(config){
4591 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4596 * The raw click event for the entire grid.
4597 * @param {Roo.EventObject} e
4602 * Fires when the active item active state changes
4603 * @param {Roo.bootstrap.NavSidebarItem} this
4604 * @param {boolean} state the new state
4612 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4614 badgeWeight : 'default',
4620 buttonWeight : 'default',
4626 getAutoCreate : function(){
4631 href : this.href || '#',
4637 if(this.buttonView){
4640 href : this.href || '#',
4641 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4654 cfg.cls += ' active';
4657 if (this.disabled) {
4658 cfg.cls += ' disabled';
4661 cfg.cls += ' open x-open';
4664 if (this.glyphicon || this.icon) {
4665 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4666 a.cn.push({ tag : 'i', cls : c }) ;
4669 if(!this.buttonView){
4672 html : this.html || ''
4679 if (this.badge !== '') {
4680 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4686 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4689 a.cls += ' dropdown-toggle treeview' ;
4695 initEvents : function()
4697 if (typeof (this.menu) != 'undefined') {
4698 this.menu.parentType = this.xtype;
4699 this.menu.triggerEl = this.el;
4700 this.menu = this.addxtype(Roo.apply({}, this.menu));
4703 this.el.on('click', this.onClick, this);
4705 if(this.badge !== ''){
4706 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4711 onClick : function(e)
4718 if(this.preventDefault){
4722 this.fireEvent('click', this);
4725 disable : function()
4727 this.setDisabled(true);
4732 this.setDisabled(false);
4735 setDisabled : function(state)
4737 if(this.disabled == state){
4741 this.disabled = state;
4744 this.el.addClass('disabled');
4748 this.el.removeClass('disabled');
4753 setActive : function(state)
4755 if(this.active == state){
4759 this.active = state;
4762 this.el.addClass('active');
4766 this.el.removeClass('active');
4771 isActive: function ()
4776 setBadge : function(str)
4782 this.badgeEl.dom.innerHTML = str;
4799 * @class Roo.bootstrap.Row
4800 * @extends Roo.bootstrap.Component
4801 * Bootstrap Row class (contains columns...)
4805 * @param {Object} config The config object
4808 Roo.bootstrap.Row = function(config){
4809 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4812 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4814 getAutoCreate : function(){
4833 * @class Roo.bootstrap.Element
4834 * @extends Roo.bootstrap.Component
4835 * Bootstrap Element class
4836 * @cfg {String} html contents of the element
4837 * @cfg {String} tag tag of the element
4838 * @cfg {String} cls class of the element
4839 * @cfg {Boolean} preventDefault (true|false) default false
4840 * @cfg {Boolean} clickable (true|false) default false
4843 * Create a new Element
4844 * @param {Object} config The config object
4847 Roo.bootstrap.Element = function(config){
4848 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4854 * When a element is chick
4855 * @param {Roo.bootstrap.Element} this
4856 * @param {Roo.EventObject} e
4862 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4867 preventDefault: false,
4870 getAutoCreate : function(){
4881 initEvents: function()
4883 Roo.bootstrap.Element.superclass.initEvents.call(this);
4886 this.el.on('click', this.onClick, this);
4891 onClick : function(e)
4893 if(this.preventDefault){
4897 this.fireEvent('click', this, e);
4900 getValue : function()
4902 return this.el.dom.innerHTML;
4905 setValue : function(value)
4907 this.el.dom.innerHTML = value;
4922 * @class Roo.bootstrap.Pagination
4923 * @extends Roo.bootstrap.Component
4924 * Bootstrap Pagination class
4925 * @cfg {String} size xs | sm | md | lg
4926 * @cfg {Boolean} inverse false | true
4929 * Create a new Pagination
4930 * @param {Object} config The config object
4933 Roo.bootstrap.Pagination = function(config){
4934 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4937 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4943 getAutoCreate : function(){
4949 cfg.cls += ' inverse';
4955 cfg.cls += " " + this.cls;
4973 * @class Roo.bootstrap.PaginationItem
4974 * @extends Roo.bootstrap.Component
4975 * Bootstrap PaginationItem class
4976 * @cfg {String} html text
4977 * @cfg {String} href the link
4978 * @cfg {Boolean} preventDefault (true | false) default true
4979 * @cfg {Boolean} active (true | false) default false
4980 * @cfg {Boolean} disabled default false
4984 * Create a new PaginationItem
4985 * @param {Object} config The config object
4989 Roo.bootstrap.PaginationItem = function(config){
4990 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4995 * The raw click event for the entire grid.
4996 * @param {Roo.EventObject} e
5002 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5006 preventDefault: true,
5011 getAutoCreate : function(){
5017 href : this.href ? this.href : '#',
5018 html : this.html ? this.html : ''
5028 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5032 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5038 initEvents: function() {
5040 this.el.on('click', this.onClick, this);
5043 onClick : function(e)
5045 Roo.log('PaginationItem on click ');
5046 if(this.preventDefault){
5054 this.fireEvent('click', this, e);
5070 * @class Roo.bootstrap.Slider
5071 * @extends Roo.bootstrap.Component
5072 * Bootstrap Slider class
5075 * Create a new Slider
5076 * @param {Object} config The config object
5079 Roo.bootstrap.Slider = function(config){
5080 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5083 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5085 getAutoCreate : function(){
5089 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5093 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5105 * Ext JS Library 1.1.1
5106 * Copyright(c) 2006-2007, Ext JS, LLC.
5108 * Originally Released Under LGPL - original licence link has changed is not relivant.
5111 * <script type="text/javascript">
5116 * @class Roo.grid.ColumnModel
5117 * @extends Roo.util.Observable
5118 * This is the default implementation of a ColumnModel used by the Grid. It defines
5119 * the columns in the grid.
5122 var colModel = new Roo.grid.ColumnModel([
5123 {header: "Ticker", width: 60, sortable: true, locked: true},
5124 {header: "Company Name", width: 150, sortable: true},
5125 {header: "Market Cap.", width: 100, sortable: true},
5126 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5127 {header: "Employees", width: 100, sortable: true, resizable: false}
5132 * The config options listed for this class are options which may appear in each
5133 * individual column definition.
5134 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5136 * @param {Object} config An Array of column config objects. See this class's
5137 * config objects for details.
5139 Roo.grid.ColumnModel = function(config){
5141 * The config passed into the constructor
5143 this.config = config;
5146 // if no id, create one
5147 // if the column does not have a dataIndex mapping,
5148 // map it to the order it is in the config
5149 for(var i = 0, len = config.length; i < len; i++){
5151 if(typeof c.dataIndex == "undefined"){
5154 if(typeof c.renderer == "string"){
5155 c.renderer = Roo.util.Format[c.renderer];
5157 if(typeof c.id == "undefined"){
5160 if(c.editor && c.editor.xtype){
5161 c.editor = Roo.factory(c.editor, Roo.grid);
5163 if(c.editor && c.editor.isFormField){
5164 c.editor = new Roo.grid.GridEditor(c.editor);
5166 this.lookup[c.id] = c;
5170 * The width of columns which have no width specified (defaults to 100)
5173 this.defaultWidth = 100;
5176 * Default sortable of columns which have no sortable specified (defaults to false)
5179 this.defaultSortable = false;
5183 * @event widthchange
5184 * Fires when the width of a column changes.
5185 * @param {ColumnModel} this
5186 * @param {Number} columnIndex The column index
5187 * @param {Number} newWidth The new width
5189 "widthchange": true,
5191 * @event headerchange
5192 * Fires when the text of a header changes.
5193 * @param {ColumnModel} this
5194 * @param {Number} columnIndex The column index
5195 * @param {Number} newText The new header text
5197 "headerchange": true,
5199 * @event hiddenchange
5200 * Fires when a column is hidden or "unhidden".
5201 * @param {ColumnModel} this
5202 * @param {Number} columnIndex The column index
5203 * @param {Boolean} hidden true if hidden, false otherwise
5205 "hiddenchange": true,
5207 * @event columnmoved
5208 * Fires when a column is moved.
5209 * @param {ColumnModel} this
5210 * @param {Number} oldIndex
5211 * @param {Number} newIndex
5213 "columnmoved" : true,
5215 * @event columlockchange
5216 * Fires when a column's locked state is changed
5217 * @param {ColumnModel} this
5218 * @param {Number} colIndex
5219 * @param {Boolean} locked true if locked
5221 "columnlockchange" : true
5223 Roo.grid.ColumnModel.superclass.constructor.call(this);
5225 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5227 * @cfg {String} header The header text to display in the Grid view.
5230 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5231 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5232 * specified, the column's index is used as an index into the Record's data Array.
5235 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5236 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5239 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5240 * Defaults to the value of the {@link #defaultSortable} property.
5241 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5244 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5247 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5250 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5253 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5256 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5257 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5258 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5259 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5262 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5265 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5268 * @cfg {String} cursor (Optional)
5271 * @cfg {String} tooltip (Optional)
5274 * @cfg {Number} xs (Optional)
5277 * @cfg {Number} sm (Optional)
5280 * @cfg {Number} md (Optional)
5283 * @cfg {Number} lg (Optional)
5286 * Returns the id of the column at the specified index.
5287 * @param {Number} index The column index
5288 * @return {String} the id
5290 getColumnId : function(index){
5291 return this.config[index].id;
5295 * Returns the column for a specified id.
5296 * @param {String} id The column id
5297 * @return {Object} the column
5299 getColumnById : function(id){
5300 return this.lookup[id];
5305 * Returns the column for a specified dataIndex.
5306 * @param {String} dataIndex The column dataIndex
5307 * @return {Object|Boolean} the column or false if not found
5309 getColumnByDataIndex: function(dataIndex){
5310 var index = this.findColumnIndex(dataIndex);
5311 return index > -1 ? this.config[index] : false;
5315 * Returns the index for a specified column id.
5316 * @param {String} id The column id
5317 * @return {Number} the index, or -1 if not found
5319 getIndexById : function(id){
5320 for(var i = 0, len = this.config.length; i < len; i++){
5321 if(this.config[i].id == id){
5329 * Returns the index for a specified column dataIndex.
5330 * @param {String} dataIndex The column dataIndex
5331 * @return {Number} the index, or -1 if not found
5334 findColumnIndex : function(dataIndex){
5335 for(var i = 0, len = this.config.length; i < len; i++){
5336 if(this.config[i].dataIndex == dataIndex){
5344 moveColumn : function(oldIndex, newIndex){
5345 var c = this.config[oldIndex];
5346 this.config.splice(oldIndex, 1);
5347 this.config.splice(newIndex, 0, c);
5348 this.dataMap = null;
5349 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5352 isLocked : function(colIndex){
5353 return this.config[colIndex].locked === true;
5356 setLocked : function(colIndex, value, suppressEvent){
5357 if(this.isLocked(colIndex) == value){
5360 this.config[colIndex].locked = value;
5362 this.fireEvent("columnlockchange", this, colIndex, value);
5366 getTotalLockedWidth : function(){
5368 for(var i = 0; i < this.config.length; i++){
5369 if(this.isLocked(i) && !this.isHidden(i)){
5370 this.totalWidth += this.getColumnWidth(i);
5376 getLockedCount : function(){
5377 for(var i = 0, len = this.config.length; i < len; i++){
5378 if(!this.isLocked(i)){
5383 return this.config.length;
5387 * Returns the number of columns.
5390 getColumnCount : function(visibleOnly){
5391 if(visibleOnly === true){
5393 for(var i = 0, len = this.config.length; i < len; i++){
5394 if(!this.isHidden(i)){
5400 return this.config.length;
5404 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5405 * @param {Function} fn
5406 * @param {Object} scope (optional)
5407 * @return {Array} result
5409 getColumnsBy : function(fn, scope){
5411 for(var i = 0, len = this.config.length; i < len; i++){
5412 var c = this.config[i];
5413 if(fn.call(scope||this, c, i) === true){
5421 * Returns true if the specified column is sortable.
5422 * @param {Number} col The column index
5425 isSortable : function(col){
5426 if(typeof this.config[col].sortable == "undefined"){
5427 return this.defaultSortable;
5429 return this.config[col].sortable;
5433 * Returns the rendering (formatting) function defined for the column.
5434 * @param {Number} col The column index.
5435 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5437 getRenderer : function(col){
5438 if(!this.config[col].renderer){
5439 return Roo.grid.ColumnModel.defaultRenderer;
5441 return this.config[col].renderer;
5445 * Sets the rendering (formatting) function for a column.
5446 * @param {Number} col The column index
5447 * @param {Function} fn The function to use to process the cell's raw data
5448 * to return HTML markup for the grid view. The render function is called with
5449 * the following parameters:<ul>
5450 * <li>Data value.</li>
5451 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5452 * <li>css A CSS style string to apply to the table cell.</li>
5453 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5454 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5455 * <li>Row index</li>
5456 * <li>Column index</li>
5457 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5459 setRenderer : function(col, fn){
5460 this.config[col].renderer = fn;
5464 * Returns the width for the specified column.
5465 * @param {Number} col The column index
5468 getColumnWidth : function(col){
5469 return this.config[col].width * 1 || this.defaultWidth;
5473 * Sets the width for a column.
5474 * @param {Number} col The column index
5475 * @param {Number} width The new width
5477 setColumnWidth : function(col, width, suppressEvent){
5478 this.config[col].width = width;
5479 this.totalWidth = null;
5481 this.fireEvent("widthchange", this, col, width);
5486 * Returns the total width of all columns.
5487 * @param {Boolean} includeHidden True to include hidden column widths
5490 getTotalWidth : function(includeHidden){
5491 if(!this.totalWidth){
5492 this.totalWidth = 0;
5493 for(var i = 0, len = this.config.length; i < len; i++){
5494 if(includeHidden || !this.isHidden(i)){
5495 this.totalWidth += this.getColumnWidth(i);
5499 return this.totalWidth;
5503 * Returns the header for the specified column.
5504 * @param {Number} col The column index
5507 getColumnHeader : function(col){
5508 return this.config[col].header;
5512 * Sets the header for a column.
5513 * @param {Number} col The column index
5514 * @param {String} header The new header
5516 setColumnHeader : function(col, header){
5517 this.config[col].header = header;
5518 this.fireEvent("headerchange", this, col, header);
5522 * Returns the tooltip for the specified column.
5523 * @param {Number} col The column index
5526 getColumnTooltip : function(col){
5527 return this.config[col].tooltip;
5530 * Sets the tooltip for a column.
5531 * @param {Number} col The column index
5532 * @param {String} tooltip The new tooltip
5534 setColumnTooltip : function(col, tooltip){
5535 this.config[col].tooltip = tooltip;
5539 * Returns the dataIndex for the specified column.
5540 * @param {Number} col The column index
5543 getDataIndex : function(col){
5544 return this.config[col].dataIndex;
5548 * Sets the dataIndex for a column.
5549 * @param {Number} col The column index
5550 * @param {Number} dataIndex The new dataIndex
5552 setDataIndex : function(col, dataIndex){
5553 this.config[col].dataIndex = dataIndex;
5559 * Returns true if the cell is editable.
5560 * @param {Number} colIndex The column index
5561 * @param {Number} rowIndex The row index - this is nto actually used..?
5564 isCellEditable : function(colIndex, rowIndex){
5565 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5569 * Returns the editor defined for the cell/column.
5570 * return false or null to disable editing.
5571 * @param {Number} colIndex The column index
5572 * @param {Number} rowIndex The row index
5575 getCellEditor : function(colIndex, rowIndex){
5576 return this.config[colIndex].editor;
5580 * Sets if a column is editable.
5581 * @param {Number} col The column index
5582 * @param {Boolean} editable True if the column is editable
5584 setEditable : function(col, editable){
5585 this.config[col].editable = editable;
5590 * Returns true if the column is hidden.
5591 * @param {Number} colIndex The column index
5594 isHidden : function(colIndex){
5595 return this.config[colIndex].hidden;
5600 * Returns true if the column width cannot be changed
5602 isFixed : function(colIndex){
5603 return this.config[colIndex].fixed;
5607 * Returns true if the column can be resized
5610 isResizable : function(colIndex){
5611 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5614 * Sets if a column is hidden.
5615 * @param {Number} colIndex The column index
5616 * @param {Boolean} hidden True if the column is hidden
5618 setHidden : function(colIndex, hidden){
5619 this.config[colIndex].hidden = hidden;
5620 this.totalWidth = null;
5621 this.fireEvent("hiddenchange", this, colIndex, hidden);
5625 * Sets the editor for a column.
5626 * @param {Number} col The column index
5627 * @param {Object} editor The editor object
5629 setEditor : function(col, editor){
5630 this.config[col].editor = editor;
5634 Roo.grid.ColumnModel.defaultRenderer = function(value)
5636 if(typeof value == "object") {
5639 if(typeof value == "string" && value.length < 1){
5643 return String.format("{0}", value);
5646 // Alias for backwards compatibility
5647 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5650 * Ext JS Library 1.1.1
5651 * Copyright(c) 2006-2007, Ext JS, LLC.
5653 * Originally Released Under LGPL - original licence link has changed is not relivant.
5656 * <script type="text/javascript">
5660 * @class Roo.LoadMask
5661 * A simple utility class for generically masking elements while loading data. If the element being masked has
5662 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5663 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5664 * element's UpdateManager load indicator and will be destroyed after the initial load.
5666 * Create a new LoadMask
5667 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5668 * @param {Object} config The config object
5670 Roo.LoadMask = function(el, config){
5671 this.el = Roo.get(el);
5672 Roo.apply(this, config);
5674 this.store.on('beforeload', this.onBeforeLoad, this);
5675 this.store.on('load', this.onLoad, this);
5676 this.store.on('loadexception', this.onLoadException, this);
5677 this.removeMask = false;
5679 var um = this.el.getUpdateManager();
5680 um.showLoadIndicator = false; // disable the default indicator
5681 um.on('beforeupdate', this.onBeforeLoad, this);
5682 um.on('update', this.onLoad, this);
5683 um.on('failure', this.onLoad, this);
5684 this.removeMask = true;
5688 Roo.LoadMask.prototype = {
5690 * @cfg {Boolean} removeMask
5691 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5692 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5696 * The text to display in a centered loading message box (defaults to 'Loading...')
5700 * @cfg {String} msgCls
5701 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5703 msgCls : 'x-mask-loading',
5706 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5712 * Disables the mask to prevent it from being displayed
5714 disable : function(){
5715 this.disabled = true;
5719 * Enables the mask so that it can be displayed
5721 enable : function(){
5722 this.disabled = false;
5725 onLoadException : function()
5729 if (typeof(arguments[3]) != 'undefined') {
5730 Roo.MessageBox.alert("Error loading",arguments[3]);
5734 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5735 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5742 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5747 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5751 onBeforeLoad : function(){
5753 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5758 destroy : function(){
5760 this.store.un('beforeload', this.onBeforeLoad, this);
5761 this.store.un('load', this.onLoad, this);
5762 this.store.un('loadexception', this.onLoadException, this);
5764 var um = this.el.getUpdateManager();
5765 um.un('beforeupdate', this.onBeforeLoad, this);
5766 um.un('update', this.onLoad, this);
5767 um.un('failure', this.onLoad, this);
5778 * @class Roo.bootstrap.Table
5779 * @extends Roo.bootstrap.Component
5780 * Bootstrap Table class
5781 * @cfg {String} cls table class
5782 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5783 * @cfg {String} bgcolor Specifies the background color for a table
5784 * @cfg {Number} border Specifies whether the table cells should have borders or not
5785 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5786 * @cfg {Number} cellspacing Specifies the space between cells
5787 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5788 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5789 * @cfg {String} sortable Specifies that the table should be sortable
5790 * @cfg {String} summary Specifies a summary of the content of a table
5791 * @cfg {Number} width Specifies the width of a table
5792 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5794 * @cfg {boolean} striped Should the rows be alternative striped
5795 * @cfg {boolean} bordered Add borders to the table
5796 * @cfg {boolean} hover Add hover highlighting
5797 * @cfg {boolean} condensed Format condensed
5798 * @cfg {boolean} responsive Format condensed
5799 * @cfg {Boolean} loadMask (true|false) default false
5800 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5801 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5802 * @cfg {Boolean} rowSelection (true|false) default false
5803 * @cfg {Boolean} cellSelection (true|false) default false
5804 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5805 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5806 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5810 * Create a new Table
5811 * @param {Object} config The config object
5814 Roo.bootstrap.Table = function(config){
5815 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5820 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5821 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5822 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5823 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5825 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5827 this.sm.grid = this;
5828 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5829 this.sm = this.selModel;
5830 this.sm.xmodule = this.xmodule || false;
5833 if (this.cm && typeof(this.cm.config) == 'undefined') {
5834 this.colModel = new Roo.grid.ColumnModel(this.cm);
5835 this.cm = this.colModel;
5836 this.cm.xmodule = this.xmodule || false;
5839 this.store= Roo.factory(this.store, Roo.data);
5840 this.ds = this.store;
5841 this.ds.xmodule = this.xmodule || false;
5844 if (this.footer && this.store) {
5845 this.footer.dataSource = this.ds;
5846 this.footer = Roo.factory(this.footer);
5853 * Fires when a cell is clicked
5854 * @param {Roo.bootstrap.Table} this
5855 * @param {Roo.Element} el
5856 * @param {Number} rowIndex
5857 * @param {Number} columnIndex
5858 * @param {Roo.EventObject} e
5862 * @event celldblclick
5863 * Fires when a cell is double clicked
5864 * @param {Roo.bootstrap.Table} this
5865 * @param {Roo.Element} el
5866 * @param {Number} rowIndex
5867 * @param {Number} columnIndex
5868 * @param {Roo.EventObject} e
5870 "celldblclick" : true,
5873 * Fires when a row is clicked
5874 * @param {Roo.bootstrap.Table} this
5875 * @param {Roo.Element} el
5876 * @param {Number} rowIndex
5877 * @param {Roo.EventObject} e
5881 * @event rowdblclick
5882 * Fires when a row is double clicked
5883 * @param {Roo.bootstrap.Table} this
5884 * @param {Roo.Element} el
5885 * @param {Number} rowIndex
5886 * @param {Roo.EventObject} e
5888 "rowdblclick" : true,
5891 * Fires when a mouseover occur
5892 * @param {Roo.bootstrap.Table} this
5893 * @param {Roo.Element} el
5894 * @param {Number} rowIndex
5895 * @param {Number} columnIndex
5896 * @param {Roo.EventObject} e
5901 * Fires when a mouseout occur
5902 * @param {Roo.bootstrap.Table} this
5903 * @param {Roo.Element} el
5904 * @param {Number} rowIndex
5905 * @param {Number} columnIndex
5906 * @param {Roo.EventObject} e
5911 * Fires when a row is rendered, so you can change add a style to it.
5912 * @param {Roo.bootstrap.Table} this
5913 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5917 * @event rowsrendered
5918 * Fires when all the rows have been rendered
5919 * @param {Roo.bootstrap.Table} this
5921 'rowsrendered' : true,
5923 * @event contextmenu
5924 * The raw contextmenu event for the entire grid.
5925 * @param {Roo.EventObject} e
5927 "contextmenu" : true,
5929 * @event rowcontextmenu
5930 * Fires when a row is right clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Number} rowIndex
5933 * @param {Roo.EventObject} e
5935 "rowcontextmenu" : true,
5937 * @event cellcontextmenu
5938 * Fires when a cell is right clicked
5939 * @param {Roo.bootstrap.Table} this
5940 * @param {Number} rowIndex
5941 * @param {Number} cellIndex
5942 * @param {Roo.EventObject} e
5944 "cellcontextmenu" : true,
5946 * @event headercontextmenu
5947 * Fires when a header is right clicked
5948 * @param {Roo.bootstrap.Table} this
5949 * @param {Number} columnIndex
5950 * @param {Roo.EventObject} e
5952 "headercontextmenu" : true
5956 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5982 rowSelection : false,
5983 cellSelection : false,
5986 // Roo.Element - the tbody
5988 // Roo.Element - thead element
5991 container: false, // used by gridpanel...
5995 getAutoCreate : function()
5997 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6004 if (this.scrollBody) {
6005 cfg.cls += ' table-body-fixed';
6008 cfg.cls += ' table-striped';
6012 cfg.cls += ' table-hover';
6014 if (this.bordered) {
6015 cfg.cls += ' table-bordered';
6017 if (this.condensed) {
6018 cfg.cls += ' table-condensed';
6020 if (this.responsive) {
6021 cfg.cls += ' table-responsive';
6025 cfg.cls+= ' ' +this.cls;
6028 // this lot should be simplifed...
6031 cfg.align=this.align;
6034 cfg.bgcolor=this.bgcolor;
6037 cfg.border=this.border;
6039 if (this.cellpadding) {
6040 cfg.cellpadding=this.cellpadding;
6042 if (this.cellspacing) {
6043 cfg.cellspacing=this.cellspacing;
6046 cfg.frame=this.frame;
6049 cfg.rules=this.rules;
6051 if (this.sortable) {
6052 cfg.sortable=this.sortable;
6055 cfg.summary=this.summary;
6058 cfg.width=this.width;
6061 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6064 if(this.store || this.cm){
6065 if(this.headerShow){
6066 cfg.cn.push(this.renderHeader());
6069 cfg.cn.push(this.renderBody());
6071 if(this.footerShow){
6072 cfg.cn.push(this.renderFooter());
6074 // where does this come from?
6075 //cfg.cls+= ' TableGrid';
6078 return { cn : [ cfg ] };
6081 initEvents : function()
6083 if(!this.store || !this.cm){
6086 if (this.selModel) {
6087 this.selModel.initEvents();
6091 //Roo.log('initEvents with ds!!!!');
6093 this.mainBody = this.el.select('tbody', true).first();
6094 this.mainHead = this.el.select('thead', true).first();
6101 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6102 e.on('click', _this.sort, _this);
6105 this.mainBody.on("click", this.onClick, this);
6106 this.mainBody.on("dblclick", this.onDblClick, this);
6108 // why is this done????? = it breaks dialogs??
6109 //this.parent().el.setStyle('position', 'relative');
6113 this.footer.parentId = this.id;
6114 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6117 this.el.select('tfoot tr td').first().addClass('hide');
6121 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6123 this.store.on('load', this.onLoad, this);
6124 this.store.on('beforeload', this.onBeforeLoad, this);
6125 this.store.on('update', this.onUpdate, this);
6126 this.store.on('add', this.onAdd, this);
6127 this.store.on("clear", this.clear, this);
6129 this.el.on("contextmenu", this.onContextMenu, this);
6131 this.mainBody.on('scroll', this.onBodyScroll, this);
6136 onContextMenu : function(e, t)
6138 this.processEvent("contextmenu", e);
6141 processEvent : function(name, e)
6143 if (name != 'touchstart' ) {
6144 this.fireEvent(name, e);
6147 var t = e.getTarget();
6149 var cell = Roo.get(t);
6155 if(cell.findParent('tfoot', false, true)){
6159 if(cell.findParent('thead', false, true)){
6161 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6162 cell = Roo.get(t).findParent('th', false, true);
6164 Roo.log("failed to find th in thead?");
6165 Roo.log(e.getTarget());
6170 var cellIndex = cell.dom.cellIndex;
6172 var ename = name == 'touchstart' ? 'click' : name;
6173 this.fireEvent("header" + ename, this, cellIndex, e);
6178 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6179 cell = Roo.get(t).findParent('td', false, true);
6181 Roo.log("failed to find th in tbody?");
6182 Roo.log(e.getTarget());
6187 var row = cell.findParent('tr', false, true);
6188 var cellIndex = cell.dom.cellIndex;
6189 var rowIndex = row.dom.rowIndex - 1;
6193 this.fireEvent("row" + name, this, rowIndex, e);
6197 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6203 onMouseover : function(e, el)
6205 var cell = Roo.get(el);
6211 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6212 cell = cell.findParent('td', false, true);
6215 var row = cell.findParent('tr', false, true);
6216 var cellIndex = cell.dom.cellIndex;
6217 var rowIndex = row.dom.rowIndex - 1; // start from 0
6219 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6223 onMouseout : function(e, el)
6225 var cell = Roo.get(el);
6231 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6232 cell = cell.findParent('td', false, true);
6235 var row = cell.findParent('tr', false, true);
6236 var cellIndex = cell.dom.cellIndex;
6237 var rowIndex = row.dom.rowIndex - 1; // start from 0
6239 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6243 onClick : function(e, el)
6245 var cell = Roo.get(el);
6247 if(!cell || (!this.cellSelection && !this.rowSelection)){
6251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6252 cell = cell.findParent('td', false, true);
6255 if(!cell || typeof(cell) == 'undefined'){
6259 var row = cell.findParent('tr', false, true);
6261 if(!row || typeof(row) == 'undefined'){
6265 var cellIndex = cell.dom.cellIndex;
6266 var rowIndex = this.getRowIndex(row);
6268 // why??? - should these not be based on SelectionModel?
6269 if(this.cellSelection){
6270 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6273 if(this.rowSelection){
6274 this.fireEvent('rowclick', this, row, rowIndex, e);
6280 onDblClick : function(e,el)
6282 var cell = Roo.get(el);
6284 if(!cell || (!this.cellSelection && !this.rowSelection)){
6288 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6289 cell = cell.findParent('td', false, true);
6292 if(!cell || typeof(cell) == 'undefined'){
6296 var row = cell.findParent('tr', false, true);
6298 if(!row || typeof(row) == 'undefined'){
6302 var cellIndex = cell.dom.cellIndex;
6303 var rowIndex = this.getRowIndex(row);
6305 if(this.cellSelection){
6306 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6309 if(this.rowSelection){
6310 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6314 sort : function(e,el)
6316 var col = Roo.get(el);
6318 if(!col.hasClass('sortable')){
6322 var sort = col.attr('sort');
6325 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6329 this.store.sortInfo = {field : sort, direction : dir};
6332 Roo.log("calling footer first");
6333 this.footer.onClick('first');
6336 this.store.load({ params : { start : 0 } });
6340 renderHeader : function()
6348 this.totalWidth = 0;
6350 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6352 var config = cm.config[i];
6357 html: cm.getColumnHeader(i)
6362 if(typeof(config.sortable) != 'undefined' && config.sortable){
6364 c.html = '<i class="glyphicon"></i>' + c.html;
6367 if(typeof(config.lgHeader) != 'undefined'){
6368 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6371 if(typeof(config.mdHeader) != 'undefined'){
6372 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6375 if(typeof(config.smHeader) != 'undefined'){
6376 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6379 if(typeof(config.xsHeader) != 'undefined'){
6380 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6387 if(typeof(config.tooltip) != 'undefined'){
6388 c.tooltip = config.tooltip;
6391 if(typeof(config.colspan) != 'undefined'){
6392 c.colspan = config.colspan;
6395 if(typeof(config.hidden) != 'undefined' && config.hidden){
6396 c.style += ' display:none;';
6399 if(typeof(config.dataIndex) != 'undefined'){
6400 c.sort = config.dataIndex;
6405 if(typeof(config.align) != 'undefined' && config.align.length){
6406 c.style += ' text-align:' + config.align + ';';
6409 if(typeof(config.width) != 'undefined'){
6410 c.style += ' width:' + config.width + 'px;';
6411 this.totalWidth += config.width;
6413 this.totalWidth += 100; // assume minimum of 100 per column?
6416 if(typeof(config.cls) != 'undefined'){
6417 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6420 ['xs','sm','md','lg'].map(function(size){
6422 if(typeof(config[size]) == 'undefined'){
6426 if (!config[size]) { // 0 = hidden
6427 c.cls += ' hidden-' + size;
6431 c.cls += ' col-' + size + '-' + config[size];
6441 renderBody : function()
6451 colspan : this.cm.getColumnCount()
6461 renderFooter : function()
6471 colspan : this.cm.getColumnCount()
6485 // Roo.log('ds onload');
6490 var ds = this.store;
6492 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6493 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6494 if (_this.store.sortInfo) {
6496 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6497 e.select('i', true).addClass(['glyphicon-arrow-up']);
6500 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6501 e.select('i', true).addClass(['glyphicon-arrow-down']);
6506 var tbody = this.mainBody;
6508 if(ds.getCount() > 0){
6509 ds.data.each(function(d,rowIndex){
6510 var row = this.renderRow(cm, ds, rowIndex);
6512 tbody.createChild(row);
6516 if(row.cellObjects.length){
6517 Roo.each(row.cellObjects, function(r){
6518 _this.renderCellObject(r);
6525 Roo.each(this.el.select('tbody td', true).elements, function(e){
6526 e.on('mouseover', _this.onMouseover, _this);
6529 Roo.each(this.el.select('tbody td', true).elements, function(e){
6530 e.on('mouseout', _this.onMouseout, _this);
6532 this.fireEvent('rowsrendered', this);
6533 //if(this.loadMask){
6534 // this.maskEl.hide();
6541 onUpdate : function(ds,record)
6543 this.refreshRow(record);
6547 onRemove : function(ds, record, index, isUpdate){
6548 if(isUpdate !== true){
6549 this.fireEvent("beforerowremoved", this, index, record);
6551 var bt = this.mainBody.dom;
6553 var rows = this.el.select('tbody > tr', true).elements;
6555 if(typeof(rows[index]) != 'undefined'){
6556 bt.removeChild(rows[index].dom);
6559 // if(bt.rows[index]){
6560 // bt.removeChild(bt.rows[index]);
6563 if(isUpdate !== true){
6564 //this.stripeRows(index);
6565 //this.syncRowHeights(index, index);
6567 this.fireEvent("rowremoved", this, index, record);
6571 onAdd : function(ds, records, rowIndex)
6573 //Roo.log('on Add called');
6574 // - note this does not handle multiple adding very well..
6575 var bt = this.mainBody.dom;
6576 for (var i =0 ; i < records.length;i++) {
6577 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6578 //Roo.log(records[i]);
6579 //Roo.log(this.store.getAt(rowIndex+i));
6580 this.insertRow(this.store, rowIndex + i, false);
6587 refreshRow : function(record){
6588 var ds = this.store, index;
6589 if(typeof record == 'number'){
6591 record = ds.getAt(index);
6593 index = ds.indexOf(record);
6595 this.insertRow(ds, index, true);
6597 this.onRemove(ds, record, index+1, true);
6599 //this.syncRowHeights(index, index);
6601 this.fireEvent("rowupdated", this, index, record);
6604 insertRow : function(dm, rowIndex, isUpdate){
6607 this.fireEvent("beforerowsinserted", this, rowIndex);
6609 //var s = this.getScrollState();
6610 var row = this.renderRow(this.cm, this.store, rowIndex);
6611 // insert before rowIndex..
6612 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6616 if(row.cellObjects.length){
6617 Roo.each(row.cellObjects, function(r){
6618 _this.renderCellObject(r);
6623 this.fireEvent("rowsinserted", this, rowIndex);
6624 //this.syncRowHeights(firstRow, lastRow);
6625 //this.stripeRows(firstRow);
6632 getRowDom : function(rowIndex)
6634 var rows = this.el.select('tbody > tr', true).elements;
6636 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6639 // returns the object tree for a tr..
6642 renderRow : function(cm, ds, rowIndex)
6645 var d = ds.getAt(rowIndex);
6652 var cellObjects = [];
6654 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6655 var config = cm.config[i];
6657 var renderer = cm.getRenderer(i);
6661 if(typeof(renderer) !== 'undefined'){
6662 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6664 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6665 // and are rendered into the cells after the row is rendered - using the id for the element.
6667 if(typeof(value) === 'object'){
6677 rowIndex : rowIndex,
6682 this.fireEvent('rowclass', this, rowcfg);
6686 cls : rowcfg.rowClass,
6688 html: (typeof(value) === 'object') ? '' : value
6695 if(typeof(config.colspan) != 'undefined'){
6696 td.colspan = config.colspan;
6699 if(typeof(config.hidden) != 'undefined' && config.hidden){
6700 td.style += ' display:none;';
6703 if(typeof(config.align) != 'undefined' && config.align.length){
6704 td.style += ' text-align:' + config.align + ';';
6707 if(typeof(config.width) != 'undefined'){
6708 td.style += ' width:' + config.width + 'px;';
6711 if(typeof(config.cursor) != 'undefined'){
6712 td.style += ' cursor:' + config.cursor + ';';
6715 if(typeof(config.cls) != 'undefined'){
6716 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6719 ['xs','sm','md','lg'].map(function(size){
6721 if(typeof(config[size]) == 'undefined'){
6725 if (!config[size]) { // 0 = hidden
6726 td.cls += ' hidden-' + size;
6730 td.cls += ' col-' + size + '-' + config[size];
6738 row.cellObjects = cellObjects;
6746 onBeforeLoad : function()
6748 //Roo.log('ds onBeforeLoad');
6752 //if(this.loadMask){
6753 // this.maskEl.show();
6761 this.el.select('tbody', true).first().dom.innerHTML = '';
6764 * Show or hide a row.
6765 * @param {Number} rowIndex to show or hide
6766 * @param {Boolean} state hide
6768 setRowVisibility : function(rowIndex, state)
6770 var bt = this.mainBody.dom;
6772 var rows = this.el.select('tbody > tr', true).elements;
6774 if(typeof(rows[rowIndex]) == 'undefined'){
6777 rows[rowIndex].dom.style.display = state ? '' : 'none';
6781 getSelectionModel : function(){
6783 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6785 return this.selModel;
6788 * Render the Roo.bootstrap object from renderder
6790 renderCellObject : function(r)
6794 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6796 var t = r.cfg.render(r.container);
6799 Roo.each(r.cfg.cn, function(c){
6801 container: t.getChildContainer(),
6804 _this.renderCellObject(child);
6809 getRowIndex : function(row)
6813 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6824 * Returns the grid's underlying element = used by panel.Grid
6825 * @return {Element} The element
6827 getGridEl : function(){
6831 * Forces a resize - used by panel.Grid
6832 * @return {Element} The element
6834 autoSize : function()
6836 //var ctr = Roo.get(this.container.dom.parentElement);
6837 var ctr = Roo.get(this.el.dom);
6839 var thd = this.getGridEl().select('thead',true).first();
6840 var tbd = this.getGridEl().select('tbody', true).first();
6841 var tfd = this.getGridEl().select('tfoot', true).first();
6843 var cw = ctr.getWidth();
6847 tbd.setSize(ctr.getWidth(),
6848 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6850 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6853 cw = Math.max(cw, this.totalWidth);
6854 this.getGridEl().select('tr',true).setWidth(cw);
6855 // resize 'expandable coloumn?
6857 return; // we doe not have a view in this design..
6860 onBodyScroll: function()
6862 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6863 this.mainHead.setStyle({
6864 'position' : 'relative',
6865 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6870 var scrollHeight = this.mainBody.dom.scrollHeight;
6872 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6874 var height = this.mainBody.getHeight();
6876 if(scrollHeight - height == scrollTop) {
6878 var total = this.ds.getTotalCount();
6880 if(this.footer.cursor + this.footer.pageSize < total){
6882 this.footer.ds.load({
6884 start : this.footer.cursor + this.footer.pageSize,
6885 limit : this.footer.pageSize
6906 * @class Roo.bootstrap.TableCell
6907 * @extends Roo.bootstrap.Component
6908 * Bootstrap TableCell class
6909 * @cfg {String} html cell contain text
6910 * @cfg {String} cls cell class
6911 * @cfg {String} tag cell tag (td|th) default td
6912 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6913 * @cfg {String} align Aligns the content in a cell
6914 * @cfg {String} axis Categorizes cells
6915 * @cfg {String} bgcolor Specifies the background color of a cell
6916 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6917 * @cfg {Number} colspan Specifies the number of columns a cell should span
6918 * @cfg {String} headers Specifies one or more header cells a cell is related to
6919 * @cfg {Number} height Sets the height of a cell
6920 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6921 * @cfg {Number} rowspan Sets the number of rows a cell should span
6922 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6923 * @cfg {String} valign Vertical aligns the content in a cell
6924 * @cfg {Number} width Specifies the width of a cell
6927 * Create a new TableCell
6928 * @param {Object} config The config object
6931 Roo.bootstrap.TableCell = function(config){
6932 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6935 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6955 getAutoCreate : function(){
6956 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6976 cfg.align=this.align
6982 cfg.bgcolor=this.bgcolor
6985 cfg.charoff=this.charoff
6988 cfg.colspan=this.colspan
6991 cfg.headers=this.headers
6994 cfg.height=this.height
6997 cfg.nowrap=this.nowrap
7000 cfg.rowspan=this.rowspan
7003 cfg.scope=this.scope
7006 cfg.valign=this.valign
7009 cfg.width=this.width
7028 * @class Roo.bootstrap.TableRow
7029 * @extends Roo.bootstrap.Component
7030 * Bootstrap TableRow class
7031 * @cfg {String} cls row class
7032 * @cfg {String} align Aligns the content in a table row
7033 * @cfg {String} bgcolor Specifies a background color for a table row
7034 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7035 * @cfg {String} valign Vertical aligns the content in a table row
7038 * Create a new TableRow
7039 * @param {Object} config The config object
7042 Roo.bootstrap.TableRow = function(config){
7043 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7046 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7054 getAutoCreate : function(){
7055 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7065 cfg.align = this.align;
7068 cfg.bgcolor = this.bgcolor;
7071 cfg.charoff = this.charoff;
7074 cfg.valign = this.valign;
7092 * @class Roo.bootstrap.TableBody
7093 * @extends Roo.bootstrap.Component
7094 * Bootstrap TableBody class
7095 * @cfg {String} cls element class
7096 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7097 * @cfg {String} align Aligns the content inside the element
7098 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7099 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7102 * Create a new TableBody
7103 * @param {Object} config The config object
7106 Roo.bootstrap.TableBody = function(config){
7107 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7110 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7118 getAutoCreate : function(){
7119 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7133 cfg.align = this.align;
7136 cfg.charoff = this.charoff;
7139 cfg.valign = this.valign;
7146 // initEvents : function()
7153 // this.store = Roo.factory(this.store, Roo.data);
7154 // this.store.on('load', this.onLoad, this);
7156 // this.store.load();
7160 // onLoad: function ()
7162 // this.fireEvent('load', this);
7172 * Ext JS Library 1.1.1
7173 * Copyright(c) 2006-2007, Ext JS, LLC.
7175 * Originally Released Under LGPL - original licence link has changed is not relivant.
7178 * <script type="text/javascript">
7181 // as we use this in bootstrap.
7182 Roo.namespace('Roo.form');
7184 * @class Roo.form.Action
7185 * Internal Class used to handle form actions
7187 * @param {Roo.form.BasicForm} el The form element or its id
7188 * @param {Object} config Configuration options
7193 // define the action interface
7194 Roo.form.Action = function(form, options){
7196 this.options = options || {};
7199 * Client Validation Failed
7202 Roo.form.Action.CLIENT_INVALID = 'client';
7204 * Server Validation Failed
7207 Roo.form.Action.SERVER_INVALID = 'server';
7209 * Connect to Server Failed
7212 Roo.form.Action.CONNECT_FAILURE = 'connect';
7214 * Reading Data from Server Failed
7217 Roo.form.Action.LOAD_FAILURE = 'load';
7219 Roo.form.Action.prototype = {
7221 failureType : undefined,
7222 response : undefined,
7226 run : function(options){
7231 success : function(response){
7236 handleResponse : function(response){
7240 // default connection failure
7241 failure : function(response){
7243 this.response = response;
7244 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7245 this.form.afterAction(this, false);
7248 processResponse : function(response){
7249 this.response = response;
7250 if(!response.responseText){
7253 this.result = this.handleResponse(response);
7257 // utility functions used internally
7258 getUrl : function(appendParams){
7259 var url = this.options.url || this.form.url || this.form.el.dom.action;
7261 var p = this.getParams();
7263 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7269 getMethod : function(){
7270 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7273 getParams : function(){
7274 var bp = this.form.baseParams;
7275 var p = this.options.params;
7277 if(typeof p == "object"){
7278 p = Roo.urlEncode(Roo.applyIf(p, bp));
7279 }else if(typeof p == 'string' && bp){
7280 p += '&' + Roo.urlEncode(bp);
7283 p = Roo.urlEncode(bp);
7288 createCallback : function(){
7290 success: this.success,
7291 failure: this.failure,
7293 timeout: (this.form.timeout*1000),
7294 upload: this.form.fileUpload ? this.success : undefined
7299 Roo.form.Action.Submit = function(form, options){
7300 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7303 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7306 haveProgress : false,
7307 uploadComplete : false,
7309 // uploadProgress indicator.
7310 uploadProgress : function()
7312 if (!this.form.progressUrl) {
7316 if (!this.haveProgress) {
7317 Roo.MessageBox.progress("Uploading", "Uploading");
7319 if (this.uploadComplete) {
7320 Roo.MessageBox.hide();
7324 this.haveProgress = true;
7326 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7328 var c = new Roo.data.Connection();
7330 url : this.form.progressUrl,
7335 success : function(req){
7336 //console.log(data);
7340 rdata = Roo.decode(req.responseText)
7342 Roo.log("Invalid data from server..");
7346 if (!rdata || !rdata.success) {
7348 Roo.MessageBox.alert(Roo.encode(rdata));
7351 var data = rdata.data;
7353 if (this.uploadComplete) {
7354 Roo.MessageBox.hide();
7359 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7360 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7363 this.uploadProgress.defer(2000,this);
7366 failure: function(data) {
7367 Roo.log('progress url failed ');
7378 // run get Values on the form, so it syncs any secondary forms.
7379 this.form.getValues();
7381 var o = this.options;
7382 var method = this.getMethod();
7383 var isPost = method == 'POST';
7384 if(o.clientValidation === false || this.form.isValid()){
7386 if (this.form.progressUrl) {
7387 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7388 (new Date() * 1) + '' + Math.random());
7393 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7394 form:this.form.el.dom,
7395 url:this.getUrl(!isPost),
7397 params:isPost ? this.getParams() : null,
7398 isUpload: this.form.fileUpload
7401 this.uploadProgress();
7403 }else if (o.clientValidation !== false){ // client validation failed
7404 this.failureType = Roo.form.Action.CLIENT_INVALID;
7405 this.form.afterAction(this, false);
7409 success : function(response)
7411 this.uploadComplete= true;
7412 if (this.haveProgress) {
7413 Roo.MessageBox.hide();
7417 var result = this.processResponse(response);
7418 if(result === true || result.success){
7419 this.form.afterAction(this, true);
7423 this.form.markInvalid(result.errors);
7424 this.failureType = Roo.form.Action.SERVER_INVALID;
7426 this.form.afterAction(this, false);
7428 failure : function(response)
7430 this.uploadComplete= true;
7431 if (this.haveProgress) {
7432 Roo.MessageBox.hide();
7435 this.response = response;
7436 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7437 this.form.afterAction(this, false);
7440 handleResponse : function(response){
7441 if(this.form.errorReader){
7442 var rs = this.form.errorReader.read(response);
7445 for(var i = 0, len = rs.records.length; i < len; i++) {
7446 var r = rs.records[i];
7450 if(errors.length < 1){
7454 success : rs.success,
7460 ret = Roo.decode(response.responseText);
7464 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7474 Roo.form.Action.Load = function(form, options){
7475 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7476 this.reader = this.form.reader;
7479 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7484 Roo.Ajax.request(Roo.apply(
7485 this.createCallback(), {
7486 method:this.getMethod(),
7487 url:this.getUrl(false),
7488 params:this.getParams()
7492 success : function(response){
7494 var result = this.processResponse(response);
7495 if(result === true || !result.success || !result.data){
7496 this.failureType = Roo.form.Action.LOAD_FAILURE;
7497 this.form.afterAction(this, false);
7500 this.form.clearInvalid();
7501 this.form.setValues(result.data);
7502 this.form.afterAction(this, true);
7505 handleResponse : function(response){
7506 if(this.form.reader){
7507 var rs = this.form.reader.read(response);
7508 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7510 success : rs.success,
7514 return Roo.decode(response.responseText);
7518 Roo.form.Action.ACTION_TYPES = {
7519 'load' : Roo.form.Action.Load,
7520 'submit' : Roo.form.Action.Submit
7529 * @class Roo.bootstrap.Form
7530 * @extends Roo.bootstrap.Component
7531 * Bootstrap Form class
7532 * @cfg {String} method GET | POST (default POST)
7533 * @cfg {String} labelAlign top | left (default top)
7534 * @cfg {String} align left | right - for navbars
7535 * @cfg {Boolean} loadMask load mask when submit (default true)
7540 * @param {Object} config The config object
7544 Roo.bootstrap.Form = function(config){
7545 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7547 Roo.bootstrap.Form.popover.apply();
7551 * @event clientvalidation
7552 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7553 * @param {Form} this
7554 * @param {Boolean} valid true if the form has passed client-side validation
7556 clientvalidation: true,
7558 * @event beforeaction
7559 * Fires before any action is performed. Return false to cancel the action.
7560 * @param {Form} this
7561 * @param {Action} action The action to be performed
7565 * @event actionfailed
7566 * Fires when an action fails.
7567 * @param {Form} this
7568 * @param {Action} action The action that failed
7570 actionfailed : true,
7572 * @event actioncomplete
7573 * Fires when an action is completed.
7574 * @param {Form} this
7575 * @param {Action} action The action that completed
7577 actioncomplete : true
7582 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7585 * @cfg {String} method
7586 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7591 * The URL to use for form actions if one isn't supplied in the action options.
7594 * @cfg {Boolean} fileUpload
7595 * Set to true if this form is a file upload.
7599 * @cfg {Object} baseParams
7600 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7604 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7608 * @cfg {Sting} align (left|right) for navbar forms
7613 activeAction : null,
7616 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7617 * element by passing it or its id or mask the form itself by passing in true.
7620 waitMsgTarget : false,
7625 * @cfg {Boolean} errorMask (true|false) default false
7630 * @cfg {Number} maskOffset Default 100
7635 * @cfg {Boolean} maskBody
7639 getAutoCreate : function(){
7643 method : this.method || 'POST',
7644 id : this.id || Roo.id(),
7647 if (this.parent().xtype.match(/^Nav/)) {
7648 cfg.cls = 'navbar-form navbar-' + this.align;
7652 if (this.labelAlign == 'left' ) {
7653 cfg.cls += ' form-horizontal';
7659 initEvents : function()
7661 this.el.on('submit', this.onSubmit, this);
7662 // this was added as random key presses on the form where triggering form submit.
7663 this.el.on('keypress', function(e) {
7664 if (e.getCharCode() != 13) {
7667 // we might need to allow it for textareas.. and some other items.
7668 // check e.getTarget().
7670 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7674 Roo.log("keypress blocked");
7682 onSubmit : function(e){
7687 * Returns true if client-side validation on the form is successful.
7690 isValid : function(){
7691 var items = this.getItems();
7695 items.each(function(f){
7701 if(!target && f.el.isVisible(true)){
7707 if(this.errorMask && !valid){
7708 Roo.bootstrap.Form.popover.mask(this, target);
7715 * Returns true if any fields in this form have changed since their original load.
7718 isDirty : function(){
7720 var items = this.getItems();
7721 items.each(function(f){
7731 * Performs a predefined action (submit or load) or custom actions you define on this form.
7732 * @param {String} actionName The name of the action type
7733 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7734 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7735 * accept other config options):
7737 Property Type Description
7738 ---------------- --------------- ----------------------------------------------------------------------------------
7739 url String The url for the action (defaults to the form's url)
7740 method String The form method to use (defaults to the form's method, or POST if not defined)
7741 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7742 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7743 validate the form on the client (defaults to false)
7745 * @return {BasicForm} this
7747 doAction : function(action, options){
7748 if(typeof action == 'string'){
7749 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7751 if(this.fireEvent('beforeaction', this, action) !== false){
7752 this.beforeAction(action);
7753 action.run.defer(100, action);
7759 beforeAction : function(action){
7760 var o = action.options;
7765 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7767 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7770 // not really supported yet.. ??
7772 //if(this.waitMsgTarget === true){
7773 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7774 //}else if(this.waitMsgTarget){
7775 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7776 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7778 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7784 afterAction : function(action, success){
7785 this.activeAction = null;
7786 var o = action.options;
7791 Roo.get(document.body).unmask();
7797 //if(this.waitMsgTarget === true){
7798 // this.el.unmask();
7799 //}else if(this.waitMsgTarget){
7800 // this.waitMsgTarget.unmask();
7802 // Roo.MessageBox.updateProgress(1);
7803 // Roo.MessageBox.hide();
7810 Roo.callback(o.success, o.scope, [this, action]);
7811 this.fireEvent('actioncomplete', this, action);
7815 // failure condition..
7816 // we have a scenario where updates need confirming.
7817 // eg. if a locking scenario exists..
7818 // we look for { errors : { needs_confirm : true }} in the response.
7820 (typeof(action.result) != 'undefined') &&
7821 (typeof(action.result.errors) != 'undefined') &&
7822 (typeof(action.result.errors.needs_confirm) != 'undefined')
7825 Roo.log("not supported yet");
7828 Roo.MessageBox.confirm(
7829 "Change requires confirmation",
7830 action.result.errorMsg,
7835 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7845 Roo.callback(o.failure, o.scope, [this, action]);
7846 // show an error message if no failed handler is set..
7847 if (!this.hasListener('actionfailed')) {
7848 Roo.log("need to add dialog support");
7850 Roo.MessageBox.alert("Error",
7851 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7852 action.result.errorMsg :
7853 "Saving Failed, please check your entries or try again"
7858 this.fireEvent('actionfailed', this, action);
7863 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7864 * @param {String} id The value to search for
7867 findField : function(id){
7868 var items = this.getItems();
7869 var field = items.get(id);
7871 items.each(function(f){
7872 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7879 return field || null;
7882 * Mark fields in this form invalid in bulk.
7883 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7884 * @return {BasicForm} this
7886 markInvalid : function(errors){
7887 if(errors instanceof Array){
7888 for(var i = 0, len = errors.length; i < len; i++){
7889 var fieldError = errors[i];
7890 var f = this.findField(fieldError.id);
7892 f.markInvalid(fieldError.msg);
7898 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7899 field.markInvalid(errors[id]);
7903 //Roo.each(this.childForms || [], function (f) {
7904 // f.markInvalid(errors);
7911 * Set values for fields in this form in bulk.
7912 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7913 * @return {BasicForm} this
7915 setValues : function(values){
7916 if(values instanceof Array){ // array of objects
7917 for(var i = 0, len = values.length; i < len; i++){
7919 var f = this.findField(v.id);
7921 f.setValue(v.value);
7922 if(this.trackResetOnLoad){
7923 f.originalValue = f.getValue();
7927 }else{ // object hash
7930 if(typeof values[id] != 'function' && (field = this.findField(id))){
7932 if (field.setFromData &&
7934 field.displayField &&
7935 // combos' with local stores can
7936 // be queried via setValue()
7937 // to set their value..
7938 (field.store && !field.store.isLocal)
7942 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7943 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7944 field.setFromData(sd);
7946 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7948 field.setFromData(values);
7951 field.setValue(values[id]);
7955 if(this.trackResetOnLoad){
7956 field.originalValue = field.getValue();
7962 //Roo.each(this.childForms || [], function (f) {
7963 // f.setValues(values);
7970 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7971 * they are returned as an array.
7972 * @param {Boolean} asString
7975 getValues : function(asString){
7976 //if (this.childForms) {
7977 // copy values from the child forms
7978 // Roo.each(this.childForms, function (f) {
7979 // this.setValues(f.getValues());
7985 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7986 if(asString === true){
7989 return Roo.urlDecode(fs);
7993 * Returns the fields in this form as an object with key/value pairs.
7994 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7997 getFieldValues : function(with_hidden)
7999 var items = this.getItems();
8001 items.each(function(f){
8007 var v = f.getValue();
8009 if (f.inputType =='radio') {
8010 if (typeof(ret[f.getName()]) == 'undefined') {
8011 ret[f.getName()] = ''; // empty..
8014 if (!f.el.dom.checked) {
8022 if(f.xtype == 'MoneyField'){
8023 ret[f.currencyName] = f.getCurrency();
8026 // not sure if this supported any more..
8027 if ((typeof(v) == 'object') && f.getRawValue) {
8028 v = f.getRawValue() ; // dates..
8030 // combo boxes where name != hiddenName...
8031 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8032 ret[f.name] = f.getRawValue();
8034 ret[f.getName()] = v;
8041 * Clears all invalid messages in this form.
8042 * @return {BasicForm} this
8044 clearInvalid : function(){
8045 var items = this.getItems();
8047 items.each(function(f){
8058 * @return {BasicForm} this
8061 var items = this.getItems();
8062 items.each(function(f){
8066 Roo.each(this.childForms || [], function (f) {
8074 getItems : function()
8076 var r=new Roo.util.MixedCollection(false, function(o){
8077 return o.id || (o.id = Roo.id());
8079 var iter = function(el) {
8086 Roo.each(el.items,function(e) {
8100 Roo.apply(Roo.bootstrap.Form, {
8127 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8128 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8129 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8130 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8133 this.maskEl.top.enableDisplayMode("block");
8134 this.maskEl.left.enableDisplayMode("block");
8135 this.maskEl.bottom.enableDisplayMode("block");
8136 this.maskEl.right.enableDisplayMode("block");
8138 this.toolTip = new Roo.bootstrap.Tooltip({
8139 cls : 'roo-form-error-popover',
8141 'left' : ['r-l', [-2,0], 'right'],
8142 'right' : ['l-r', [2,0], 'left'],
8143 'bottom' : ['tl-bl', [0,2], 'top'],
8144 'top' : [ 'bl-tl', [0,-2], 'bottom']
8148 this.toolTip.render(Roo.get(document.body));
8150 this.toolTip.el.enableDisplayMode("block");
8152 Roo.get(document.body).on('click', function(){
8156 Roo.get(document.body).on('touchstart', function(){
8160 this.isApplied = true
8163 mask : function(form, target)
8167 this.target = target;
8169 if(!this.form.errorMask || !target.el){
8173 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8175 Roo.log(scrollable);
8177 var ot = this.target.el.calcOffsetsTo(scrollable);
8179 var scrollTo = ot[1] - this.form.maskOffset;
8181 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8183 scrollable.scrollTo('top', scrollTo);
8185 var box = this.target.el.getBox();
8187 var zIndex = Roo.bootstrap.Modal.zIndex++;
8190 this.maskEl.top.setStyle('position', 'absolute');
8191 this.maskEl.top.setStyle('z-index', zIndex);
8192 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8193 this.maskEl.top.setLeft(0);
8194 this.maskEl.top.setTop(0);
8195 this.maskEl.top.show();
8197 this.maskEl.left.setStyle('position', 'absolute');
8198 this.maskEl.left.setStyle('z-index', zIndex);
8199 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8200 this.maskEl.left.setLeft(0);
8201 this.maskEl.left.setTop(box.y - this.padding);
8202 this.maskEl.left.show();
8204 this.maskEl.bottom.setStyle('position', 'absolute');
8205 this.maskEl.bottom.setStyle('z-index', zIndex);
8206 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8207 this.maskEl.bottom.setLeft(0);
8208 this.maskEl.bottom.setTop(box.bottom + this.padding);
8209 this.maskEl.bottom.show();
8211 this.maskEl.right.setStyle('position', 'absolute');
8212 this.maskEl.right.setStyle('z-index', zIndex);
8213 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8214 this.maskEl.right.setLeft(box.right + this.padding);
8215 this.maskEl.right.setTop(box.y - this.padding);
8216 this.maskEl.right.show();
8218 this.toolTip.bindEl = this.target.el;
8220 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8222 var tip = this.target.blankText;
8224 if(this.target.getValue() !== '' ) {
8226 if (this.target.invalidText.length) {
8227 tip = this.target.invalidText;
8228 } else if (this.target.regexText.length){
8229 tip = this.target.regexText;
8233 this.toolTip.show(tip);
8235 this.intervalID = window.setInterval(function() {
8236 Roo.bootstrap.Form.popover.unmask();
8239 window.onwheel = function(){ return false;};
8241 (function(){ this.isMasked = true; }).defer(500, this);
8247 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8251 this.maskEl.top.setStyle('position', 'absolute');
8252 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8253 this.maskEl.top.hide();
8255 this.maskEl.left.setStyle('position', 'absolute');
8256 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8257 this.maskEl.left.hide();
8259 this.maskEl.bottom.setStyle('position', 'absolute');
8260 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8261 this.maskEl.bottom.hide();
8263 this.maskEl.right.setStyle('position', 'absolute');
8264 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8265 this.maskEl.right.hide();
8267 this.toolTip.hide();
8269 this.toolTip.el.hide();
8271 window.onwheel = function(){ return true;};
8273 if(this.intervalID){
8274 window.clearInterval(this.intervalID);
8275 this.intervalID = false;
8278 this.isMasked = false;
8288 * Ext JS Library 1.1.1
8289 * Copyright(c) 2006-2007, Ext JS, LLC.
8291 * Originally Released Under LGPL - original licence link has changed is not relivant.
8294 * <script type="text/javascript">
8297 * @class Roo.form.VTypes
8298 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8301 Roo.form.VTypes = function(){
8302 // closure these in so they are only created once.
8303 var alpha = /^[a-zA-Z_]+$/;
8304 var alphanum = /^[a-zA-Z0-9_]+$/;
8305 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8306 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8308 // All these messages and functions are configurable
8311 * The function used to validate email addresses
8312 * @param {String} value The email address
8314 'email' : function(v){
8315 return email.test(v);
8318 * The error text to display when the email validation function returns false
8321 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8323 * The keystroke filter mask to be applied on email input
8326 'emailMask' : /[a-z0-9_\.\-@]/i,
8329 * The function used to validate URLs
8330 * @param {String} value The URL
8332 'url' : function(v){
8336 * The error text to display when the url validation function returns false
8339 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8342 * The function used to validate alpha values
8343 * @param {String} value The value
8345 'alpha' : function(v){
8346 return alpha.test(v);
8349 * The error text to display when the alpha validation function returns false
8352 'alphaText' : 'This field should only contain letters and _',
8354 * The keystroke filter mask to be applied on alpha input
8357 'alphaMask' : /[a-z_]/i,
8360 * The function used to validate alphanumeric values
8361 * @param {String} value The value
8363 'alphanum' : function(v){
8364 return alphanum.test(v);
8367 * The error text to display when the alphanumeric validation function returns false
8370 'alphanumText' : 'This field should only contain letters, numbers and _',
8372 * The keystroke filter mask to be applied on alphanumeric input
8375 'alphanumMask' : /[a-z0-9_]/i
8385 * @class Roo.bootstrap.Input
8386 * @extends Roo.bootstrap.Component
8387 * Bootstrap Input class
8388 * @cfg {Boolean} disabled is it disabled
8389 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8390 * @cfg {String} name name of the input
8391 * @cfg {string} fieldLabel - the label associated
8392 * @cfg {string} placeholder - placeholder to put in text.
8393 * @cfg {string} before - input group add on before
8394 * @cfg {string} after - input group add on after
8395 * @cfg {string} size - (lg|sm) or leave empty..
8396 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8397 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8398 * @cfg {Number} md colspan out of 12 for computer-sized screens
8399 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8400 * @cfg {string} value default value of the input
8401 * @cfg {Number} labelWidth set the width of label
8402 * @cfg {Number} labellg set the width of label (1-12)
8403 * @cfg {Number} labelmd set the width of label (1-12)
8404 * @cfg {Number} labelsm set the width of label (1-12)
8405 * @cfg {Number} labelxs set the width of label (1-12)
8406 * @cfg {String} labelAlign (top|left)
8407 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8408 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8409 * @cfg {String} indicatorpos (left|right) default left
8411 * @cfg {String} align (left|center|right) Default left
8412 * @cfg {Boolean} forceFeedback (true|false) Default false
8418 * Create a new Input
8419 * @param {Object} config The config object
8422 Roo.bootstrap.Input = function(config){
8424 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8429 * Fires when this field receives input focus.
8430 * @param {Roo.form.Field} this
8435 * Fires when this field loses input focus.
8436 * @param {Roo.form.Field} this
8441 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8442 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8443 * @param {Roo.form.Field} this
8444 * @param {Roo.EventObject} e The event object
8449 * Fires just before the field blurs if the field value has changed.
8450 * @param {Roo.form.Field} this
8451 * @param {Mixed} newValue The new value
8452 * @param {Mixed} oldValue The original value
8457 * Fires after the field has been marked as invalid.
8458 * @param {Roo.form.Field} this
8459 * @param {String} msg The validation message
8464 * Fires after the field has been validated with no errors.
8465 * @param {Roo.form.Field} this
8470 * Fires after the key up
8471 * @param {Roo.form.Field} this
8472 * @param {Roo.EventObject} e The event Object
8478 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8480 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8481 automatic validation (defaults to "keyup").
8483 validationEvent : "keyup",
8485 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8487 validateOnBlur : true,
8489 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8491 validationDelay : 250,
8493 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8495 focusClass : "x-form-focus", // not needed???
8499 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8501 invalidClass : "has-warning",
8504 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8506 validClass : "has-success",
8509 * @cfg {Boolean} hasFeedback (true|false) default true
8514 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8516 invalidFeedbackClass : "glyphicon-warning-sign",
8519 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8521 validFeedbackClass : "glyphicon-ok",
8524 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8526 selectOnFocus : false,
8529 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8533 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8538 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8540 disableKeyFilter : false,
8543 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8547 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8551 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8553 blankText : "Please complete this mandatory field",
8556 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8560 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8562 maxLength : Number.MAX_VALUE,
8564 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8566 minLengthText : "The minimum length for this field is {0}",
8568 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8570 maxLengthText : "The maximum length for this field is {0}",
8574 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8575 * If available, this function will be called only after the basic validators all return true, and will be passed the
8576 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8580 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8581 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8582 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8586 * @cfg {String} regexText -- Depricated - use Invalid Text
8591 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8597 autocomplete: false,
8616 formatedValue : false,
8617 forceFeedback : false,
8619 indicatorpos : 'left',
8626 parentLabelAlign : function()
8629 while (parent.parent()) {
8630 parent = parent.parent();
8631 if (typeof(parent.labelAlign) !='undefined') {
8632 return parent.labelAlign;
8639 getAutoCreate : function()
8641 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8647 if(this.inputType != 'hidden'){
8648 cfg.cls = 'form-group' //input-group
8654 type : this.inputType,
8656 cls : 'form-control',
8657 placeholder : this.placeholder || '',
8658 autocomplete : this.autocomplete || 'new-password'
8662 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8665 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8666 input.maxLength = this.maxLength;
8669 if (this.disabled) {
8670 input.disabled=true;
8673 if (this.readOnly) {
8674 input.readonly=true;
8678 input.name = this.name;
8682 input.cls += ' input-' + this.size;
8686 ['xs','sm','md','lg'].map(function(size){
8687 if (settings[size]) {
8688 cfg.cls += ' col-' + size + '-' + settings[size];
8692 var inputblock = input;
8696 cls: 'glyphicon form-control-feedback'
8699 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8702 cls : 'has-feedback',
8710 if (this.before || this.after) {
8713 cls : 'input-group',
8717 if (this.before && typeof(this.before) == 'string') {
8719 inputblock.cn.push({
8721 cls : 'roo-input-before input-group-addon',
8725 if (this.before && typeof(this.before) == 'object') {
8726 this.before = Roo.factory(this.before);
8728 inputblock.cn.push({
8730 cls : 'roo-input-before input-group-' +
8731 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8735 inputblock.cn.push(input);
8737 if (this.after && typeof(this.after) == 'string') {
8738 inputblock.cn.push({
8740 cls : 'roo-input-after input-group-addon',
8744 if (this.after && typeof(this.after) == 'object') {
8745 this.after = Roo.factory(this.after);
8747 inputblock.cn.push({
8749 cls : 'roo-input-after input-group-' +
8750 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8754 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8755 inputblock.cls += ' has-feedback';
8756 inputblock.cn.push(feedback);
8760 if (align ==='left' && this.fieldLabel.length) {
8762 cfg.cls += ' roo-form-group-label-left';
8767 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8768 tooltip : 'This field is required'
8773 cls : 'control-label',
8774 html : this.fieldLabel
8785 var labelCfg = cfg.cn[1];
8786 var contentCfg = cfg.cn[2];
8788 if(this.indicatorpos == 'right'){
8793 cls : 'control-label',
8797 html : this.fieldLabel
8801 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8802 tooltip : 'This field is required'
8815 labelCfg = cfg.cn[0];
8816 contentCfg = cfg.cn[1];
8820 if(this.labelWidth > 12){
8821 labelCfg.style = "width: " + this.labelWidth + 'px';
8824 if(this.labelWidth < 13 && this.labelmd == 0){
8825 this.labelmd = this.labelWidth;
8828 if(this.labellg > 0){
8829 labelCfg.cls += ' col-lg-' + this.labellg;
8830 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8833 if(this.labelmd > 0){
8834 labelCfg.cls += ' col-md-' + this.labelmd;
8835 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8838 if(this.labelsm > 0){
8839 labelCfg.cls += ' col-sm-' + this.labelsm;
8840 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8843 if(this.labelxs > 0){
8844 labelCfg.cls += ' col-xs-' + this.labelxs;
8845 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8849 } else if ( this.fieldLabel.length) {
8854 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8855 tooltip : 'This field is required'
8859 //cls : 'input-group-addon',
8860 html : this.fieldLabel
8868 if(this.indicatorpos == 'right'){
8873 //cls : 'input-group-addon',
8874 html : this.fieldLabel
8879 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8880 tooltip : 'This field is required'
8900 if (this.parentType === 'Navbar' && this.parent().bar) {
8901 cfg.cls += ' navbar-form';
8904 if (this.parentType === 'NavGroup') {
8905 cfg.cls += ' navbar-form';
8913 * return the real input element.
8915 inputEl: function ()
8917 return this.el.select('input.form-control',true).first();
8920 tooltipEl : function()
8922 return this.inputEl();
8925 indicatorEl : function()
8927 var indicator = this.el.select('i.roo-required-indicator',true).first();
8937 setDisabled : function(v)
8939 var i = this.inputEl().dom;
8941 i.removeAttribute('disabled');
8945 i.setAttribute('disabled','true');
8947 initEvents : function()
8950 this.inputEl().on("keydown" , this.fireKey, this);
8951 this.inputEl().on("focus", this.onFocus, this);
8952 this.inputEl().on("blur", this.onBlur, this);
8954 this.inputEl().relayEvent('keyup', this);
8956 this.indicator = this.indicatorEl();
8959 this.indicator.addClass('invisible');
8963 // reference to original value for reset
8964 this.originalValue = this.getValue();
8965 //Roo.form.TextField.superclass.initEvents.call(this);
8966 if(this.validationEvent == 'keyup'){
8967 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8968 this.inputEl().on('keyup', this.filterValidation, this);
8970 else if(this.validationEvent !== false){
8971 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8974 if(this.selectOnFocus){
8975 this.on("focus", this.preFocus, this);
8978 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8979 this.inputEl().on("keypress", this.filterKeys, this);
8981 this.inputEl().relayEvent('keypress', this);
8984 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8985 this.el.on("click", this.autoSize, this);
8988 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8989 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8992 if (typeof(this.before) == 'object') {
8993 this.before.render(this.el.select('.roo-input-before',true).first());
8995 if (typeof(this.after) == 'object') {
8996 this.after.render(this.el.select('.roo-input-after',true).first());
9001 filterValidation : function(e){
9002 if(!e.isNavKeyPress()){
9003 this.validationTask.delay(this.validationDelay);
9007 * Validates the field value
9008 * @return {Boolean} True if the value is valid, else false
9010 validate : function(){
9011 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9012 if(this.disabled || this.validateValue(this.getRawValue())){
9023 * Validates a value according to the field's validation rules and marks the field as invalid
9024 * if the validation fails
9025 * @param {Mixed} value The value to validate
9026 * @return {Boolean} True if the value is valid, else false
9028 validateValue : function(value){
9029 if(value.length < 1) { // if it's blank
9030 if(this.allowBlank){
9033 return this.inputEl().hasClass('hide') ? true : false;
9036 if(value.length < this.minLength){
9039 if(value.length > this.maxLength){
9043 var vt = Roo.form.VTypes;
9044 if(!vt[this.vtype](value, this)){
9048 if(typeof this.validator == "function"){
9049 var msg = this.validator(value);
9053 if (typeof(msg) == 'string') {
9054 this.invalidText = msg;
9058 if(this.regex && !this.regex.test(value)){
9068 fireKey : function(e){
9069 //Roo.log('field ' + e.getKey());
9070 if(e.isNavKeyPress()){
9071 this.fireEvent("specialkey", this, e);
9074 focus : function (selectText){
9076 this.inputEl().focus();
9077 if(selectText === true){
9078 this.inputEl().dom.select();
9084 onFocus : function(){
9085 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9086 // this.el.addClass(this.focusClass);
9089 this.hasFocus = true;
9090 this.startValue = this.getValue();
9091 this.fireEvent("focus", this);
9095 beforeBlur : Roo.emptyFn,
9099 onBlur : function(){
9101 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9102 //this.el.removeClass(this.focusClass);
9104 this.hasFocus = false;
9105 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9108 var v = this.getValue();
9109 if(String(v) !== String(this.startValue)){
9110 this.fireEvent('change', this, v, this.startValue);
9112 this.fireEvent("blur", this);
9116 * Resets the current field value to the originally loaded value and clears any validation messages
9119 this.setValue(this.originalValue);
9123 * Returns the name of the field
9124 * @return {Mixed} name The name field
9126 getName: function(){
9130 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9131 * @return {Mixed} value The field value
9133 getValue : function(){
9135 var v = this.inputEl().getValue();
9140 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9141 * @return {Mixed} value The field value
9143 getRawValue : function(){
9144 var v = this.inputEl().getValue();
9150 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9151 * @param {Mixed} value The value to set
9153 setRawValue : function(v){
9154 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9157 selectText : function(start, end){
9158 var v = this.getRawValue();
9160 start = start === undefined ? 0 : start;
9161 end = end === undefined ? v.length : end;
9162 var d = this.inputEl().dom;
9163 if(d.setSelectionRange){
9164 d.setSelectionRange(start, end);
9165 }else if(d.createTextRange){
9166 var range = d.createTextRange();
9167 range.moveStart("character", start);
9168 range.moveEnd("character", v.length-end);
9175 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9176 * @param {Mixed} value The value to set
9178 setValue : function(v){
9181 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9187 processValue : function(value){
9188 if(this.stripCharsRe){
9189 var newValue = value.replace(this.stripCharsRe, '');
9190 if(newValue !== value){
9191 this.setRawValue(newValue);
9198 preFocus : function(){
9200 if(this.selectOnFocus){
9201 this.inputEl().dom.select();
9204 filterKeys : function(e){
9206 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9209 var c = e.getCharCode(), cc = String.fromCharCode(c);
9210 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9213 if(!this.maskRe.test(cc)){
9218 * Clear any invalid styles/messages for this field
9220 clearInvalid : function(){
9222 if(!this.el || this.preventMark){ // not rendered
9227 this.el.removeClass(this.invalidClass);
9229 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9231 var feedback = this.el.select('.form-control-feedback', true).first();
9234 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9239 this.fireEvent('valid', this);
9243 * Mark this field as valid
9245 markValid : function()
9247 if(!this.el || this.preventMark){ // not rendered...
9251 this.el.removeClass([this.invalidClass, this.validClass]);
9253 var feedback = this.el.select('.form-control-feedback', true).first();
9256 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9263 if(this.allowBlank && !this.getRawValue().length){
9268 this.indicator.removeClass('visible');
9269 this.indicator.addClass('invisible');
9272 this.el.addClass(this.validClass);
9274 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9276 var feedback = this.el.select('.form-control-feedback', true).first();
9279 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9280 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9285 this.fireEvent('valid', this);
9289 * Mark this field as invalid
9290 * @param {String} msg The validation message
9292 markInvalid : function(msg)
9294 if(!this.el || this.preventMark){ // not rendered
9298 this.el.removeClass([this.invalidClass, this.validClass]);
9300 var feedback = this.el.select('.form-control-feedback', true).first();
9303 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9310 if(this.allowBlank && !this.getRawValue().length){
9315 this.indicator.removeClass('invisible');
9316 this.indicator.addClass('visible');
9319 this.el.addClass(this.invalidClass);
9321 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9323 var feedback = this.el.select('.form-control-feedback', true).first();
9326 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9328 if(this.getValue().length || this.forceFeedback){
9329 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9336 this.fireEvent('invalid', this, msg);
9339 SafariOnKeyDown : function(event)
9341 // this is a workaround for a password hang bug on chrome/ webkit.
9342 if (this.inputEl().dom.type != 'password') {
9346 var isSelectAll = false;
9348 if(this.inputEl().dom.selectionEnd > 0){
9349 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9351 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9352 event.preventDefault();
9357 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9359 event.preventDefault();
9360 // this is very hacky as keydown always get's upper case.
9362 var cc = String.fromCharCode(event.getCharCode());
9363 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9367 adjustWidth : function(tag, w){
9368 tag = tag.toLowerCase();
9369 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9370 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9374 if(tag == 'textarea'){
9377 }else if(Roo.isOpera){
9381 if(tag == 'textarea'){
9389 setFieldLabel : function(v)
9395 this.fieldLabel = v;
9398 var ar = this.el.select('label > span',true);
9399 if (!ar.elements.length) {
9400 Roo.log("could not find label > span on element");
9404 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9408 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9421 * @class Roo.bootstrap.TextArea
9422 * @extends Roo.bootstrap.Input
9423 * Bootstrap TextArea class
9424 * @cfg {Number} cols Specifies the visible width of a text area
9425 * @cfg {Number} rows Specifies the visible number of lines in a text area
9426 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9427 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9428 * @cfg {string} html text
9431 * Create a new TextArea
9432 * @param {Object} config The config object
9435 Roo.bootstrap.TextArea = function(config){
9436 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9440 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9450 getAutoCreate : function(){
9452 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9458 if(this.inputType != 'hidden'){
9459 cfg.cls = 'form-group' //input-group
9467 value : this.value || '',
9468 html: this.html || '',
9469 cls : 'form-control',
9470 placeholder : this.placeholder || ''
9474 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9475 input.maxLength = this.maxLength;
9479 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9483 input.cols = this.cols;
9486 if (this.readOnly) {
9487 input.readonly = true;
9491 input.name = this.name;
9495 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9499 ['xs','sm','md','lg'].map(function(size){
9500 if (settings[size]) {
9501 cfg.cls += ' col-' + size + '-' + settings[size];
9505 var inputblock = input;
9507 if(this.hasFeedback && !this.allowBlank){
9511 cls: 'glyphicon form-control-feedback'
9515 cls : 'has-feedback',
9524 if (this.before || this.after) {
9527 cls : 'input-group',
9531 inputblock.cn.push({
9533 cls : 'input-group-addon',
9538 inputblock.cn.push(input);
9540 if(this.hasFeedback && !this.allowBlank){
9541 inputblock.cls += ' has-feedback';
9542 inputblock.cn.push(feedback);
9546 inputblock.cn.push({
9548 cls : 'input-group-addon',
9555 if (align ==='left' && this.fieldLabel.length) {
9560 cls : 'control-label',
9561 html : this.fieldLabel
9572 if(this.labelWidth > 12){
9573 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9576 if(this.labelWidth < 13 && this.labelmd == 0){
9577 this.labelmd = this.labelWidth;
9580 if(this.labellg > 0){
9581 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9582 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9585 if(this.labelmd > 0){
9586 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9587 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9590 if(this.labelsm > 0){
9591 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9592 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9595 if(this.labelxs > 0){
9596 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9597 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9600 } else if ( this.fieldLabel.length) {
9605 //cls : 'input-group-addon',
9606 html : this.fieldLabel
9624 if (this.disabled) {
9625 input.disabled=true;
9632 * return the real textarea element.
9634 inputEl: function ()
9636 return this.el.select('textarea.form-control',true).first();
9640 * Clear any invalid styles/messages for this field
9642 clearInvalid : function()
9645 if(!this.el || this.preventMark){ // not rendered
9649 var label = this.el.select('label', true).first();
9650 var icon = this.el.select('i.fa-star', true).first();
9656 this.el.removeClass(this.invalidClass);
9658 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9660 var feedback = this.el.select('.form-control-feedback', true).first();
9663 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9668 this.fireEvent('valid', this);
9672 * Mark this field as valid
9674 markValid : function()
9676 if(!this.el || this.preventMark){ // not rendered
9680 this.el.removeClass([this.invalidClass, this.validClass]);
9682 var feedback = this.el.select('.form-control-feedback', true).first();
9685 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9688 if(this.disabled || this.allowBlank){
9692 var label = this.el.select('label', true).first();
9693 var icon = this.el.select('i.fa-star', true).first();
9699 this.el.addClass(this.validClass);
9701 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9703 var feedback = this.el.select('.form-control-feedback', true).first();
9706 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9707 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9712 this.fireEvent('valid', this);
9716 * Mark this field as invalid
9717 * @param {String} msg The validation message
9719 markInvalid : function(msg)
9721 if(!this.el || this.preventMark){ // not rendered
9725 this.el.removeClass([this.invalidClass, this.validClass]);
9727 var feedback = this.el.select('.form-control-feedback', true).first();
9730 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9733 if(this.disabled || this.allowBlank){
9737 var label = this.el.select('label', true).first();
9738 var icon = this.el.select('i.fa-star', true).first();
9740 if(!this.getValue().length && label && !icon){
9741 this.el.createChild({
9743 cls : 'text-danger fa fa-lg fa-star',
9744 tooltip : 'This field is required',
9745 style : 'margin-right:5px;'
9749 this.el.addClass(this.invalidClass);
9751 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9753 var feedback = this.el.select('.form-control-feedback', true).first();
9756 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9758 if(this.getValue().length || this.forceFeedback){
9759 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9766 this.fireEvent('invalid', this, msg);
9774 * trigger field - base class for combo..
9779 * @class Roo.bootstrap.TriggerField
9780 * @extends Roo.bootstrap.Input
9781 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9782 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9783 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9784 * for which you can provide a custom implementation. For example:
9786 var trigger = new Roo.bootstrap.TriggerField();
9787 trigger.onTriggerClick = myTriggerFn;
9788 trigger.applyTo('my-field');
9791 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9792 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9793 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9794 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9795 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9798 * Create a new TriggerField.
9799 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9800 * to the base TextField)
9802 Roo.bootstrap.TriggerField = function(config){
9803 this.mimicing = false;
9804 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9807 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9809 * @cfg {String} triggerClass A CSS class to apply to the trigger
9812 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9817 * @cfg {Boolean} removable (true|false) special filter default false
9821 /** @cfg {Boolean} grow @hide */
9822 /** @cfg {Number} growMin @hide */
9823 /** @cfg {Number} growMax @hide */
9829 autoSize: Roo.emptyFn,
9836 actionMode : 'wrap',
9841 getAutoCreate : function(){
9843 var align = this.labelAlign || this.parentLabelAlign();
9848 cls: 'form-group' //input-group
9855 type : this.inputType,
9856 cls : 'form-control',
9857 autocomplete: 'new-password',
9858 placeholder : this.placeholder || ''
9862 input.name = this.name;
9865 input.cls += ' input-' + this.size;
9868 if (this.disabled) {
9869 input.disabled=true;
9872 var inputblock = input;
9874 if(this.hasFeedback && !this.allowBlank){
9878 cls: 'glyphicon form-control-feedback'
9881 if(this.removable && !this.editable && !this.tickable){
9883 cls : 'has-feedback',
9889 cls : 'roo-combo-removable-btn close'
9896 cls : 'has-feedback',
9905 if(this.removable && !this.editable && !this.tickable){
9907 cls : 'roo-removable',
9913 cls : 'roo-combo-removable-btn close'
9920 if (this.before || this.after) {
9923 cls : 'input-group',
9927 inputblock.cn.push({
9929 cls : 'input-group-addon',
9934 inputblock.cn.push(input);
9936 if(this.hasFeedback && !this.allowBlank){
9937 inputblock.cls += ' has-feedback';
9938 inputblock.cn.push(feedback);
9942 inputblock.cn.push({
9944 cls : 'input-group-addon',
9957 cls: 'form-hidden-field'
9971 cls: 'form-hidden-field'
9975 cls: 'roo-select2-choices',
9979 cls: 'roo-select2-search-field',
9992 cls: 'roo-select2-container input-group',
9997 // cls: 'typeahead typeahead-long dropdown-menu',
9998 // style: 'display:none'
10003 if(!this.multiple && this.showToggleBtn){
10009 if (this.caret != false) {
10012 cls: 'fa fa-' + this.caret
10019 cls : 'input-group-addon btn dropdown-toggle',
10024 cls: 'combobox-clear',
10038 combobox.cls += ' roo-select2-container-multi';
10041 if (align ==='left' && this.fieldLabel.length) {
10043 cfg.cls += ' roo-form-group-label-left';
10048 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10049 tooltip : 'This field is required'
10054 cls : 'control-label',
10055 html : this.fieldLabel
10067 var labelCfg = cfg.cn[1];
10068 var contentCfg = cfg.cn[2];
10070 if(this.indicatorpos == 'right'){
10075 cls : 'control-label',
10079 html : this.fieldLabel
10083 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10084 tooltip : 'This field is required'
10097 labelCfg = cfg.cn[0];
10098 contentCfg = cfg.cn[1];
10101 if(this.labelWidth > 12){
10102 labelCfg.style = "width: " + this.labelWidth + 'px';
10105 if(this.labelWidth < 13 && this.labelmd == 0){
10106 this.labelmd = this.labelWidth;
10109 if(this.labellg > 0){
10110 labelCfg.cls += ' col-lg-' + this.labellg;
10111 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10114 if(this.labelmd > 0){
10115 labelCfg.cls += ' col-md-' + this.labelmd;
10116 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10119 if(this.labelsm > 0){
10120 labelCfg.cls += ' col-sm-' + this.labelsm;
10121 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10124 if(this.labelxs > 0){
10125 labelCfg.cls += ' col-xs-' + this.labelxs;
10126 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10129 } else if ( this.fieldLabel.length) {
10130 // Roo.log(" label");
10134 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10135 tooltip : 'This field is required'
10139 //cls : 'input-group-addon',
10140 html : this.fieldLabel
10148 if(this.indicatorpos == 'right'){
10156 html : this.fieldLabel
10160 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10161 tooltip : 'This field is required'
10174 // Roo.log(" no label && no align");
10181 ['xs','sm','md','lg'].map(function(size){
10182 if (settings[size]) {
10183 cfg.cls += ' col-' + size + '-' + settings[size];
10194 onResize : function(w, h){
10195 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10196 // if(typeof w == 'number'){
10197 // var x = w - this.trigger.getWidth();
10198 // this.inputEl().setWidth(this.adjustWidth('input', x));
10199 // this.trigger.setStyle('left', x+'px');
10204 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10207 getResizeEl : function(){
10208 return this.inputEl();
10212 getPositionEl : function(){
10213 return this.inputEl();
10217 alignErrorIcon : function(){
10218 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10222 initEvents : function(){
10226 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10227 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10228 if(!this.multiple && this.showToggleBtn){
10229 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10230 if(this.hideTrigger){
10231 this.trigger.setDisplayed(false);
10233 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10237 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10240 if(this.removable && !this.editable && !this.tickable){
10241 var close = this.closeTriggerEl();
10244 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10245 close.on('click', this.removeBtnClick, this, close);
10249 //this.trigger.addClassOnOver('x-form-trigger-over');
10250 //this.trigger.addClassOnClick('x-form-trigger-click');
10253 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10257 closeTriggerEl : function()
10259 var close = this.el.select('.roo-combo-removable-btn', true).first();
10260 return close ? close : false;
10263 removeBtnClick : function(e, h, el)
10265 e.preventDefault();
10267 if(this.fireEvent("remove", this) !== false){
10269 this.fireEvent("afterremove", this)
10273 createList : function()
10275 this.list = Roo.get(document.body).createChild({
10277 cls: 'typeahead typeahead-long dropdown-menu',
10278 style: 'display:none'
10281 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10286 initTrigger : function(){
10291 onDestroy : function(){
10293 this.trigger.removeAllListeners();
10294 // this.trigger.remove();
10297 // this.wrap.remove();
10299 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10303 onFocus : function(){
10304 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10306 if(!this.mimicing){
10307 this.wrap.addClass('x-trigger-wrap-focus');
10308 this.mimicing = true;
10309 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10310 if(this.monitorTab){
10311 this.el.on("keydown", this.checkTab, this);
10318 checkTab : function(e){
10319 if(e.getKey() == e.TAB){
10320 this.triggerBlur();
10325 onBlur : function(){
10330 mimicBlur : function(e, t){
10332 if(!this.wrap.contains(t) && this.validateBlur()){
10333 this.triggerBlur();
10339 triggerBlur : function(){
10340 this.mimicing = false;
10341 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10342 if(this.monitorTab){
10343 this.el.un("keydown", this.checkTab, this);
10345 //this.wrap.removeClass('x-trigger-wrap-focus');
10346 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10350 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10351 validateBlur : function(e, t){
10356 onDisable : function(){
10357 this.inputEl().dom.disabled = true;
10358 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10360 // this.wrap.addClass('x-item-disabled');
10365 onEnable : function(){
10366 this.inputEl().dom.disabled = false;
10367 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10369 // this.el.removeClass('x-item-disabled');
10374 onShow : function(){
10375 var ae = this.getActionEl();
10378 ae.dom.style.display = '';
10379 ae.dom.style.visibility = 'visible';
10385 onHide : function(){
10386 var ae = this.getActionEl();
10387 ae.dom.style.display = 'none';
10391 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10392 * by an implementing function.
10394 * @param {EventObject} e
10396 onTriggerClick : Roo.emptyFn
10400 * Ext JS Library 1.1.1
10401 * Copyright(c) 2006-2007, Ext JS, LLC.
10403 * Originally Released Under LGPL - original licence link has changed is not relivant.
10406 * <script type="text/javascript">
10411 * @class Roo.data.SortTypes
10413 * Defines the default sorting (casting?) comparison functions used when sorting data.
10415 Roo.data.SortTypes = {
10417 * Default sort that does nothing
10418 * @param {Mixed} s The value being converted
10419 * @return {Mixed} The comparison value
10421 none : function(s){
10426 * The regular expression used to strip tags
10430 stripTagsRE : /<\/?[^>]+>/gi,
10433 * Strips all HTML tags to sort on text only
10434 * @param {Mixed} s The value being converted
10435 * @return {String} The comparison value
10437 asText : function(s){
10438 return String(s).replace(this.stripTagsRE, "");
10442 * Strips all HTML tags to sort on text only - Case insensitive
10443 * @param {Mixed} s The value being converted
10444 * @return {String} The comparison value
10446 asUCText : function(s){
10447 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10451 * Case insensitive string
10452 * @param {Mixed} s The value being converted
10453 * @return {String} The comparison value
10455 asUCString : function(s) {
10456 return String(s).toUpperCase();
10461 * @param {Mixed} s The value being converted
10462 * @return {Number} The comparison value
10464 asDate : function(s) {
10468 if(s instanceof Date){
10469 return s.getTime();
10471 return Date.parse(String(s));
10476 * @param {Mixed} s The value being converted
10477 * @return {Float} The comparison value
10479 asFloat : function(s) {
10480 var val = parseFloat(String(s).replace(/,/g, ""));
10489 * @param {Mixed} s The value being converted
10490 * @return {Number} The comparison value
10492 asInt : function(s) {
10493 var val = parseInt(String(s).replace(/,/g, ""));
10501 * Ext JS Library 1.1.1
10502 * Copyright(c) 2006-2007, Ext JS, LLC.
10504 * Originally Released Under LGPL - original licence link has changed is not relivant.
10507 * <script type="text/javascript">
10511 * @class Roo.data.Record
10512 * Instances of this class encapsulate both record <em>definition</em> information, and record
10513 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10514 * to access Records cached in an {@link Roo.data.Store} object.<br>
10516 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10517 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10520 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10522 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10523 * {@link #create}. The parameters are the same.
10524 * @param {Array} data An associative Array of data values keyed by the field name.
10525 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10526 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10527 * not specified an integer id is generated.
10529 Roo.data.Record = function(data, id){
10530 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10535 * Generate a constructor for a specific record layout.
10536 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10537 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10538 * Each field definition object may contain the following properties: <ul>
10539 * <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,
10540 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10541 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10542 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10543 * is being used, then this is a string containing the javascript expression to reference the data relative to
10544 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10545 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10546 * this may be omitted.</p></li>
10547 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10548 * <ul><li>auto (Default, implies no conversion)</li>
10553 * <li>date</li></ul></p></li>
10554 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10555 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10556 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10557 * by the Reader into an object that will be stored in the Record. It is passed the
10558 * following parameters:<ul>
10559 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10561 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10563 * <br>usage:<br><pre><code>
10564 var TopicRecord = Roo.data.Record.create(
10565 {name: 'title', mapping: 'topic_title'},
10566 {name: 'author', mapping: 'username'},
10567 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10568 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10569 {name: 'lastPoster', mapping: 'user2'},
10570 {name: 'excerpt', mapping: 'post_text'}
10573 var myNewRecord = new TopicRecord({
10574 title: 'Do my job please',
10577 lastPost: new Date(),
10578 lastPoster: 'Animal',
10579 excerpt: 'No way dude!'
10581 myStore.add(myNewRecord);
10586 Roo.data.Record.create = function(o){
10587 var f = function(){
10588 f.superclass.constructor.apply(this, arguments);
10590 Roo.extend(f, Roo.data.Record);
10591 var p = f.prototype;
10592 p.fields = new Roo.util.MixedCollection(false, function(field){
10595 for(var i = 0, len = o.length; i < len; i++){
10596 p.fields.add(new Roo.data.Field(o[i]));
10598 f.getField = function(name){
10599 return p.fields.get(name);
10604 Roo.data.Record.AUTO_ID = 1000;
10605 Roo.data.Record.EDIT = 'edit';
10606 Roo.data.Record.REJECT = 'reject';
10607 Roo.data.Record.COMMIT = 'commit';
10609 Roo.data.Record.prototype = {
10611 * Readonly flag - true if this record has been modified.
10620 join : function(store){
10621 this.store = store;
10625 * Set the named field to the specified value.
10626 * @param {String} name The name of the field to set.
10627 * @param {Object} value The value to set the field to.
10629 set : function(name, value){
10630 if(this.data[name] == value){
10634 if(!this.modified){
10635 this.modified = {};
10637 if(typeof this.modified[name] == 'undefined'){
10638 this.modified[name] = this.data[name];
10640 this.data[name] = value;
10641 if(!this.editing && this.store){
10642 this.store.afterEdit(this);
10647 * Get the value of the named field.
10648 * @param {String} name The name of the field to get the value of.
10649 * @return {Object} The value of the field.
10651 get : function(name){
10652 return this.data[name];
10656 beginEdit : function(){
10657 this.editing = true;
10658 this.modified = {};
10662 cancelEdit : function(){
10663 this.editing = false;
10664 delete this.modified;
10668 endEdit : function(){
10669 this.editing = false;
10670 if(this.dirty && this.store){
10671 this.store.afterEdit(this);
10676 * Usually called by the {@link Roo.data.Store} which owns the Record.
10677 * Rejects all changes made to the Record since either creation, or the last commit operation.
10678 * Modified fields are reverted to their original values.
10680 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10681 * of reject operations.
10683 reject : function(){
10684 var m = this.modified;
10686 if(typeof m[n] != "function"){
10687 this.data[n] = m[n];
10690 this.dirty = false;
10691 delete this.modified;
10692 this.editing = false;
10694 this.store.afterReject(this);
10699 * Usually called by the {@link Roo.data.Store} which owns the Record.
10700 * Commits all changes made to the Record since either creation, or the last commit operation.
10702 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10703 * of commit operations.
10705 commit : function(){
10706 this.dirty = false;
10707 delete this.modified;
10708 this.editing = false;
10710 this.store.afterCommit(this);
10715 hasError : function(){
10716 return this.error != null;
10720 clearError : function(){
10725 * Creates a copy of this record.
10726 * @param {String} id (optional) A new record id if you don't want to use this record's id
10729 copy : function(newId) {
10730 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10734 * Ext JS Library 1.1.1
10735 * Copyright(c) 2006-2007, Ext JS, LLC.
10737 * Originally Released Under LGPL - original licence link has changed is not relivant.
10740 * <script type="text/javascript">
10746 * @class Roo.data.Store
10747 * @extends Roo.util.Observable
10748 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10749 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10751 * 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
10752 * has no knowledge of the format of the data returned by the Proxy.<br>
10754 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10755 * instances from the data object. These records are cached and made available through accessor functions.
10757 * Creates a new Store.
10758 * @param {Object} config A config object containing the objects needed for the Store to access data,
10759 * and read the data into Records.
10761 Roo.data.Store = function(config){
10762 this.data = new Roo.util.MixedCollection(false);
10763 this.data.getKey = function(o){
10766 this.baseParams = {};
10768 this.paramNames = {
10773 "multisort" : "_multisort"
10776 if(config && config.data){
10777 this.inlineData = config.data;
10778 delete config.data;
10781 Roo.apply(this, config);
10783 if(this.reader){ // reader passed
10784 this.reader = Roo.factory(this.reader, Roo.data);
10785 this.reader.xmodule = this.xmodule || false;
10786 if(!this.recordType){
10787 this.recordType = this.reader.recordType;
10789 if(this.reader.onMetaChange){
10790 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10794 if(this.recordType){
10795 this.fields = this.recordType.prototype.fields;
10797 this.modified = [];
10801 * @event datachanged
10802 * Fires when the data cache has changed, and a widget which is using this Store
10803 * as a Record cache should refresh its view.
10804 * @param {Store} this
10806 datachanged : true,
10808 * @event metachange
10809 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10810 * @param {Store} this
10811 * @param {Object} meta The JSON metadata
10816 * Fires when Records have been added to the Store
10817 * @param {Store} this
10818 * @param {Roo.data.Record[]} records The array of Records added
10819 * @param {Number} index The index at which the record(s) were added
10824 * Fires when a Record has been removed from the Store
10825 * @param {Store} this
10826 * @param {Roo.data.Record} record The Record that was removed
10827 * @param {Number} index The index at which the record was removed
10832 * Fires when a Record has been updated
10833 * @param {Store} this
10834 * @param {Roo.data.Record} record The Record that was updated
10835 * @param {String} operation The update operation being performed. Value may be one of:
10837 Roo.data.Record.EDIT
10838 Roo.data.Record.REJECT
10839 Roo.data.Record.COMMIT
10845 * Fires when the data cache has been cleared.
10846 * @param {Store} this
10850 * @event beforeload
10851 * Fires before a request is made for a new data object. If the beforeload handler returns false
10852 * the load action will be canceled.
10853 * @param {Store} this
10854 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10858 * @event beforeloadadd
10859 * Fires after a new set of Records has been loaded.
10860 * @param {Store} this
10861 * @param {Roo.data.Record[]} records The Records that were loaded
10862 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10864 beforeloadadd : true,
10867 * Fires after a new set of Records has been loaded, before they are added to the store.
10868 * @param {Store} this
10869 * @param {Roo.data.Record[]} records The Records that were loaded
10870 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10871 * @params {Object} return from reader
10875 * @event loadexception
10876 * Fires if an exception occurs in the Proxy during loading.
10877 * Called with the signature of the Proxy's "loadexception" event.
10878 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10881 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10882 * @param {Object} load options
10883 * @param {Object} jsonData from your request (normally this contains the Exception)
10885 loadexception : true
10889 this.proxy = Roo.factory(this.proxy, Roo.data);
10890 this.proxy.xmodule = this.xmodule || false;
10891 this.relayEvents(this.proxy, ["loadexception"]);
10893 this.sortToggle = {};
10894 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10896 Roo.data.Store.superclass.constructor.call(this);
10898 if(this.inlineData){
10899 this.loadData(this.inlineData);
10900 delete this.inlineData;
10904 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10906 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10907 * without a remote query - used by combo/forms at present.
10911 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10914 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10917 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10918 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10921 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10922 * on any HTTP request
10925 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10928 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10932 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10933 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10935 remoteSort : false,
10938 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10939 * loaded or when a record is removed. (defaults to false).
10941 pruneModifiedRecords : false,
10944 lastOptions : null,
10947 * Add Records to the Store and fires the add event.
10948 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10950 add : function(records){
10951 records = [].concat(records);
10952 for(var i = 0, len = records.length; i < len; i++){
10953 records[i].join(this);
10955 var index = this.data.length;
10956 this.data.addAll(records);
10957 this.fireEvent("add", this, records, index);
10961 * Remove a Record from the Store and fires the remove event.
10962 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10964 remove : function(record){
10965 var index = this.data.indexOf(record);
10966 this.data.removeAt(index);
10967 if(this.pruneModifiedRecords){
10968 this.modified.remove(record);
10970 this.fireEvent("remove", this, record, index);
10974 * Remove all Records from the Store and fires the clear event.
10976 removeAll : function(){
10978 if(this.pruneModifiedRecords){
10979 this.modified = [];
10981 this.fireEvent("clear", this);
10985 * Inserts Records to the Store at the given index and fires the add event.
10986 * @param {Number} index The start index at which to insert the passed Records.
10987 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10989 insert : function(index, records){
10990 records = [].concat(records);
10991 for(var i = 0, len = records.length; i < len; i++){
10992 this.data.insert(index, records[i]);
10993 records[i].join(this);
10995 this.fireEvent("add", this, records, index);
10999 * Get the index within the cache of the passed Record.
11000 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11001 * @return {Number} The index of the passed Record. Returns -1 if not found.
11003 indexOf : function(record){
11004 return this.data.indexOf(record);
11008 * Get the index within the cache of the Record with the passed id.
11009 * @param {String} id The id of the Record to find.
11010 * @return {Number} The index of the Record. Returns -1 if not found.
11012 indexOfId : function(id){
11013 return this.data.indexOfKey(id);
11017 * Get the Record with the specified id.
11018 * @param {String} id The id of the Record to find.
11019 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11021 getById : function(id){
11022 return this.data.key(id);
11026 * Get the Record at the specified index.
11027 * @param {Number} index The index of the Record to find.
11028 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11030 getAt : function(index){
11031 return this.data.itemAt(index);
11035 * Returns a range of Records between specified indices.
11036 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11037 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11038 * @return {Roo.data.Record[]} An array of Records
11040 getRange : function(start, end){
11041 return this.data.getRange(start, end);
11045 storeOptions : function(o){
11046 o = Roo.apply({}, o);
11049 this.lastOptions = o;
11053 * Loads the Record cache from the configured Proxy using the configured Reader.
11055 * If using remote paging, then the first load call must specify the <em>start</em>
11056 * and <em>limit</em> properties in the options.params property to establish the initial
11057 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11059 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11060 * and this call will return before the new data has been loaded. Perform any post-processing
11061 * in a callback function, or in a "load" event handler.</strong>
11063 * @param {Object} options An object containing properties which control loading options:<ul>
11064 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11065 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11066 * passed the following arguments:<ul>
11067 * <li>r : Roo.data.Record[]</li>
11068 * <li>options: Options object from the load call</li>
11069 * <li>success: Boolean success indicator</li></ul></li>
11070 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11071 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11074 load : function(options){
11075 options = options || {};
11076 if(this.fireEvent("beforeload", this, options) !== false){
11077 this.storeOptions(options);
11078 var p = Roo.apply(options.params || {}, this.baseParams);
11079 // if meta was not loaded from remote source.. try requesting it.
11080 if (!this.reader.metaFromRemote) {
11081 p._requestMeta = 1;
11083 if(this.sortInfo && this.remoteSort){
11084 var pn = this.paramNames;
11085 p[pn["sort"]] = this.sortInfo.field;
11086 p[pn["dir"]] = this.sortInfo.direction;
11088 if (this.multiSort) {
11089 var pn = this.paramNames;
11090 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11093 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11098 * Reloads the Record cache from the configured Proxy using the configured Reader and
11099 * the options from the last load operation performed.
11100 * @param {Object} options (optional) An object containing properties which may override the options
11101 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11102 * the most recently used options are reused).
11104 reload : function(options){
11105 this.load(Roo.applyIf(options||{}, this.lastOptions));
11109 // Called as a callback by the Reader during a load operation.
11110 loadRecords : function(o, options, success){
11111 if(!o || success === false){
11112 if(success !== false){
11113 this.fireEvent("load", this, [], options, o);
11115 if(options.callback){
11116 options.callback.call(options.scope || this, [], options, false);
11120 // if data returned failure - throw an exception.
11121 if (o.success === false) {
11122 // show a message if no listener is registered.
11123 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11124 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11126 // loadmask wil be hooked into this..
11127 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11130 var r = o.records, t = o.totalRecords || r.length;
11132 this.fireEvent("beforeloadadd", this, r, options, o);
11134 if(!options || options.add !== true){
11135 if(this.pruneModifiedRecords){
11136 this.modified = [];
11138 for(var i = 0, len = r.length; i < len; i++){
11142 this.data = this.snapshot;
11143 delete this.snapshot;
11146 this.data.addAll(r);
11147 this.totalLength = t;
11149 this.fireEvent("datachanged", this);
11151 this.totalLength = Math.max(t, this.data.length+r.length);
11155 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11157 var e = new Roo.data.Record({});
11159 e.set(this.parent.displayField, this.parent.emptyTitle);
11160 e.set(this.parent.valueField, '');
11165 this.fireEvent("load", this, r, options, o);
11166 if(options.callback){
11167 options.callback.call(options.scope || this, r, options, true);
11173 * Loads data from a passed data block. A Reader which understands the format of the data
11174 * must have been configured in the constructor.
11175 * @param {Object} data The data block from which to read the Records. The format of the data expected
11176 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11177 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11179 loadData : function(o, append){
11180 var r = this.reader.readRecords(o);
11181 this.loadRecords(r, {add: append}, true);
11185 * Gets the number of cached records.
11187 * <em>If using paging, this may not be the total size of the dataset. If the data object
11188 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11189 * the data set size</em>
11191 getCount : function(){
11192 return this.data.length || 0;
11196 * Gets the total number of records in the dataset as returned by the server.
11198 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11199 * the dataset size</em>
11201 getTotalCount : function(){
11202 return this.totalLength || 0;
11206 * Returns the sort state of the Store as an object with two properties:
11208 field {String} The name of the field by which the Records are sorted
11209 direction {String} The sort order, "ASC" or "DESC"
11212 getSortState : function(){
11213 return this.sortInfo;
11217 applySort : function(){
11218 if(this.sortInfo && !this.remoteSort){
11219 var s = this.sortInfo, f = s.field;
11220 var st = this.fields.get(f).sortType;
11221 var fn = function(r1, r2){
11222 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11223 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11225 this.data.sort(s.direction, fn);
11226 if(this.snapshot && this.snapshot != this.data){
11227 this.snapshot.sort(s.direction, fn);
11233 * Sets the default sort column and order to be used by the next load operation.
11234 * @param {String} fieldName The name of the field to sort by.
11235 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11237 setDefaultSort : function(field, dir){
11238 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11242 * Sort the Records.
11243 * If remote sorting is used, the sort is performed on the server, and the cache is
11244 * reloaded. If local sorting is used, the cache is sorted internally.
11245 * @param {String} fieldName The name of the field to sort by.
11246 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11248 sort : function(fieldName, dir){
11249 var f = this.fields.get(fieldName);
11251 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11253 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11254 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11259 this.sortToggle[f.name] = dir;
11260 this.sortInfo = {field: f.name, direction: dir};
11261 if(!this.remoteSort){
11263 this.fireEvent("datachanged", this);
11265 this.load(this.lastOptions);
11270 * Calls the specified function for each of the Records in the cache.
11271 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11272 * Returning <em>false</em> aborts and exits the iteration.
11273 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11275 each : function(fn, scope){
11276 this.data.each(fn, scope);
11280 * Gets all records modified since the last commit. Modified records are persisted across load operations
11281 * (e.g., during paging).
11282 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11284 getModifiedRecords : function(){
11285 return this.modified;
11289 createFilterFn : function(property, value, anyMatch){
11290 if(!value.exec){ // not a regex
11291 value = String(value);
11292 if(value.length == 0){
11295 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11297 return function(r){
11298 return value.test(r.data[property]);
11303 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11304 * @param {String} property A field on your records
11305 * @param {Number} start The record index to start at (defaults to 0)
11306 * @param {Number} end The last record index to include (defaults to length - 1)
11307 * @return {Number} The sum
11309 sum : function(property, start, end){
11310 var rs = this.data.items, v = 0;
11311 start = start || 0;
11312 end = (end || end === 0) ? end : rs.length-1;
11314 for(var i = start; i <= end; i++){
11315 v += (rs[i].data[property] || 0);
11321 * Filter the records by a specified property.
11322 * @param {String} field A field on your records
11323 * @param {String/RegExp} value Either a string that the field
11324 * should start with or a RegExp to test against the field
11325 * @param {Boolean} anyMatch True to match any part not just the beginning
11327 filter : function(property, value, anyMatch){
11328 var fn = this.createFilterFn(property, value, anyMatch);
11329 return fn ? this.filterBy(fn) : this.clearFilter();
11333 * Filter by a function. The specified function will be called with each
11334 * record in this data source. If the function returns true the record is included,
11335 * otherwise it is filtered.
11336 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11337 * @param {Object} scope (optional) The scope of the function (defaults to this)
11339 filterBy : function(fn, scope){
11340 this.snapshot = this.snapshot || this.data;
11341 this.data = this.queryBy(fn, scope||this);
11342 this.fireEvent("datachanged", this);
11346 * Query the records by a specified property.
11347 * @param {String} field A field on your records
11348 * @param {String/RegExp} value Either a string that the field
11349 * should start with or a RegExp to test against the field
11350 * @param {Boolean} anyMatch True to match any part not just the beginning
11351 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11353 query : function(property, value, anyMatch){
11354 var fn = this.createFilterFn(property, value, anyMatch);
11355 return fn ? this.queryBy(fn) : this.data.clone();
11359 * Query by a function. The specified function will be called with each
11360 * record in this data source. If the function returns true the record is included
11362 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11363 * @param {Object} scope (optional) The scope of the function (defaults to this)
11364 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11366 queryBy : function(fn, scope){
11367 var data = this.snapshot || this.data;
11368 return data.filterBy(fn, scope||this);
11372 * Collects unique values for a particular dataIndex from this store.
11373 * @param {String} dataIndex The property to collect
11374 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11375 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11376 * @return {Array} An array of the unique values
11378 collect : function(dataIndex, allowNull, bypassFilter){
11379 var d = (bypassFilter === true && this.snapshot) ?
11380 this.snapshot.items : this.data.items;
11381 var v, sv, r = [], l = {};
11382 for(var i = 0, len = d.length; i < len; i++){
11383 v = d[i].data[dataIndex];
11385 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11394 * Revert to a view of the Record cache with no filtering applied.
11395 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11397 clearFilter : function(suppressEvent){
11398 if(this.snapshot && this.snapshot != this.data){
11399 this.data = this.snapshot;
11400 delete this.snapshot;
11401 if(suppressEvent !== true){
11402 this.fireEvent("datachanged", this);
11408 afterEdit : function(record){
11409 if(this.modified.indexOf(record) == -1){
11410 this.modified.push(record);
11412 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11416 afterReject : function(record){
11417 this.modified.remove(record);
11418 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11422 afterCommit : function(record){
11423 this.modified.remove(record);
11424 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11428 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11429 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11431 commitChanges : function(){
11432 var m = this.modified.slice(0);
11433 this.modified = [];
11434 for(var i = 0, len = m.length; i < len; i++){
11440 * Cancel outstanding changes on all changed records.
11442 rejectChanges : function(){
11443 var m = this.modified.slice(0);
11444 this.modified = [];
11445 for(var i = 0, len = m.length; i < len; i++){
11450 onMetaChange : function(meta, rtype, o){
11451 this.recordType = rtype;
11452 this.fields = rtype.prototype.fields;
11453 delete this.snapshot;
11454 this.sortInfo = meta.sortInfo || this.sortInfo;
11455 this.modified = [];
11456 this.fireEvent('metachange', this, this.reader.meta);
11459 moveIndex : function(data, type)
11461 var index = this.indexOf(data);
11463 var newIndex = index + type;
11467 this.insert(newIndex, data);
11472 * Ext JS Library 1.1.1
11473 * Copyright(c) 2006-2007, Ext JS, LLC.
11475 * Originally Released Under LGPL - original licence link has changed is not relivant.
11478 * <script type="text/javascript">
11482 * @class Roo.data.SimpleStore
11483 * @extends Roo.data.Store
11484 * Small helper class to make creating Stores from Array data easier.
11485 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11486 * @cfg {Array} fields An array of field definition objects, or field name strings.
11487 * @cfg {Array} data The multi-dimensional array of data
11489 * @param {Object} config
11491 Roo.data.SimpleStore = function(config){
11492 Roo.data.SimpleStore.superclass.constructor.call(this, {
11494 reader: new Roo.data.ArrayReader({
11497 Roo.data.Record.create(config.fields)
11499 proxy : new Roo.data.MemoryProxy(config.data)
11503 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11505 * Ext JS Library 1.1.1
11506 * Copyright(c) 2006-2007, Ext JS, LLC.
11508 * Originally Released Under LGPL - original licence link has changed is not relivant.
11511 * <script type="text/javascript">
11516 * @extends Roo.data.Store
11517 * @class Roo.data.JsonStore
11518 * Small helper class to make creating Stores for JSON data easier. <br/>
11520 var store = new Roo.data.JsonStore({
11521 url: 'get-images.php',
11523 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11526 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11527 * JsonReader and HttpProxy (unless inline data is provided).</b>
11528 * @cfg {Array} fields An array of field definition objects, or field name strings.
11530 * @param {Object} config
11532 Roo.data.JsonStore = function(c){
11533 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11534 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11535 reader: new Roo.data.JsonReader(c, c.fields)
11538 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11540 * Ext JS Library 1.1.1
11541 * Copyright(c) 2006-2007, Ext JS, LLC.
11543 * Originally Released Under LGPL - original licence link has changed is not relivant.
11546 * <script type="text/javascript">
11550 Roo.data.Field = function(config){
11551 if(typeof config == "string"){
11552 config = {name: config};
11554 Roo.apply(this, config);
11557 this.type = "auto";
11560 var st = Roo.data.SortTypes;
11561 // named sortTypes are supported, here we look them up
11562 if(typeof this.sortType == "string"){
11563 this.sortType = st[this.sortType];
11566 // set default sortType for strings and dates
11567 if(!this.sortType){
11570 this.sortType = st.asUCString;
11573 this.sortType = st.asDate;
11576 this.sortType = st.none;
11581 var stripRe = /[\$,%]/g;
11583 // prebuilt conversion function for this field, instead of
11584 // switching every time we're reading a value
11586 var cv, dateFormat = this.dateFormat;
11591 cv = function(v){ return v; };
11594 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11598 return v !== undefined && v !== null && v !== '' ?
11599 parseInt(String(v).replace(stripRe, ""), 10) : '';
11604 return v !== undefined && v !== null && v !== '' ?
11605 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11610 cv = function(v){ return v === true || v === "true" || v == 1; };
11617 if(v instanceof Date){
11621 if(dateFormat == "timestamp"){
11622 return new Date(v*1000);
11624 return Date.parseDate(v, dateFormat);
11626 var parsed = Date.parse(v);
11627 return parsed ? new Date(parsed) : null;
11636 Roo.data.Field.prototype = {
11644 * Ext JS Library 1.1.1
11645 * Copyright(c) 2006-2007, Ext JS, LLC.
11647 * Originally Released Under LGPL - original licence link has changed is not relivant.
11650 * <script type="text/javascript">
11653 // Base class for reading structured data from a data source. This class is intended to be
11654 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11657 * @class Roo.data.DataReader
11658 * Base class for reading structured data from a data source. This class is intended to be
11659 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11662 Roo.data.DataReader = function(meta, recordType){
11666 this.recordType = recordType instanceof Array ?
11667 Roo.data.Record.create(recordType) : recordType;
11670 Roo.data.DataReader.prototype = {
11672 * Create an empty record
11673 * @param {Object} data (optional) - overlay some values
11674 * @return {Roo.data.Record} record created.
11676 newRow : function(d) {
11678 this.recordType.prototype.fields.each(function(c) {
11680 case 'int' : da[c.name] = 0; break;
11681 case 'date' : da[c.name] = new Date(); break;
11682 case 'float' : da[c.name] = 0.0; break;
11683 case 'boolean' : da[c.name] = false; break;
11684 default : da[c.name] = ""; break;
11688 return new this.recordType(Roo.apply(da, d));
11693 * Ext JS Library 1.1.1
11694 * Copyright(c) 2006-2007, Ext JS, LLC.
11696 * Originally Released Under LGPL - original licence link has changed is not relivant.
11699 * <script type="text/javascript">
11703 * @class Roo.data.DataProxy
11704 * @extends Roo.data.Observable
11705 * This class is an abstract base class for implementations which provide retrieval of
11706 * unformatted data objects.<br>
11708 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11709 * (of the appropriate type which knows how to parse the data object) to provide a block of
11710 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11712 * Custom implementations must implement the load method as described in
11713 * {@link Roo.data.HttpProxy#load}.
11715 Roo.data.DataProxy = function(){
11718 * @event beforeload
11719 * Fires before a network request is made to retrieve a data object.
11720 * @param {Object} This DataProxy object.
11721 * @param {Object} params The params parameter to the load function.
11726 * Fires before the load method's callback is called.
11727 * @param {Object} This DataProxy object.
11728 * @param {Object} o The data object.
11729 * @param {Object} arg The callback argument object passed to the load function.
11733 * @event loadexception
11734 * Fires if an Exception occurs during data retrieval.
11735 * @param {Object} This DataProxy object.
11736 * @param {Object} o The data object.
11737 * @param {Object} arg The callback argument object passed to the load function.
11738 * @param {Object} e The Exception.
11740 loadexception : true
11742 Roo.data.DataProxy.superclass.constructor.call(this);
11745 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11748 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11752 * Ext JS Library 1.1.1
11753 * Copyright(c) 2006-2007, Ext JS, LLC.
11755 * Originally Released Under LGPL - original licence link has changed is not relivant.
11758 * <script type="text/javascript">
11761 * @class Roo.data.MemoryProxy
11762 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11763 * to the Reader when its load method is called.
11765 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11767 Roo.data.MemoryProxy = function(data){
11771 Roo.data.MemoryProxy.superclass.constructor.call(this);
11775 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11778 * Load data from the requested source (in this case an in-memory
11779 * data object passed to the constructor), read the data object into
11780 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11781 * process that block using the passed callback.
11782 * @param {Object} params This parameter is not used by the MemoryProxy class.
11783 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11784 * object into a block of Roo.data.Records.
11785 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11786 * The function must be passed <ul>
11787 * <li>The Record block object</li>
11788 * <li>The "arg" argument from the load function</li>
11789 * <li>A boolean success indicator</li>
11791 * @param {Object} scope The scope in which to call the callback
11792 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11794 load : function(params, reader, callback, scope, arg){
11795 params = params || {};
11798 result = reader.readRecords(this.data);
11800 this.fireEvent("loadexception", this, arg, null, e);
11801 callback.call(scope, null, arg, false);
11804 callback.call(scope, result, arg, true);
11808 update : function(params, records){
11813 * Ext JS Library 1.1.1
11814 * Copyright(c) 2006-2007, Ext JS, LLC.
11816 * Originally Released Under LGPL - original licence link has changed is not relivant.
11819 * <script type="text/javascript">
11822 * @class Roo.data.HttpProxy
11823 * @extends Roo.data.DataProxy
11824 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11825 * configured to reference a certain URL.<br><br>
11827 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11828 * from which the running page was served.<br><br>
11830 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11832 * Be aware that to enable the browser to parse an XML document, the server must set
11833 * the Content-Type header in the HTTP response to "text/xml".
11835 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11836 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11837 * will be used to make the request.
11839 Roo.data.HttpProxy = function(conn){
11840 Roo.data.HttpProxy.superclass.constructor.call(this);
11841 // is conn a conn config or a real conn?
11843 this.useAjax = !conn || !conn.events;
11847 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11848 // thse are take from connection...
11851 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11854 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11855 * extra parameters to each request made by this object. (defaults to undefined)
11858 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11859 * to each request made by this object. (defaults to undefined)
11862 * @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)
11865 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11868 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11874 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11878 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11879 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11880 * a finer-grained basis than the DataProxy events.
11882 getConnection : function(){
11883 return this.useAjax ? Roo.Ajax : this.conn;
11887 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11888 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11889 * process that block using the passed callback.
11890 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11891 * for the request to the remote server.
11892 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11893 * object into a block of Roo.data.Records.
11894 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11895 * The function must be passed <ul>
11896 * <li>The Record block object</li>
11897 * <li>The "arg" argument from the load function</li>
11898 * <li>A boolean success indicator</li>
11900 * @param {Object} scope The scope in which to call the callback
11901 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11903 load : function(params, reader, callback, scope, arg){
11904 if(this.fireEvent("beforeload", this, params) !== false){
11906 params : params || {},
11908 callback : callback,
11913 callback : this.loadResponse,
11917 Roo.applyIf(o, this.conn);
11918 if(this.activeRequest){
11919 Roo.Ajax.abort(this.activeRequest);
11921 this.activeRequest = Roo.Ajax.request(o);
11923 this.conn.request(o);
11926 callback.call(scope||this, null, arg, false);
11931 loadResponse : function(o, success, response){
11932 delete this.activeRequest;
11934 this.fireEvent("loadexception", this, o, response);
11935 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11940 result = o.reader.read(response);
11942 this.fireEvent("loadexception", this, o, response, e);
11943 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11947 this.fireEvent("load", this, o, o.request.arg);
11948 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11952 update : function(dataSet){
11957 updateResponse : function(dataSet){
11962 * Ext JS Library 1.1.1
11963 * Copyright(c) 2006-2007, Ext JS, LLC.
11965 * Originally Released Under LGPL - original licence link has changed is not relivant.
11968 * <script type="text/javascript">
11972 * @class Roo.data.ScriptTagProxy
11973 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11974 * other than the originating domain of the running page.<br><br>
11976 * <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
11977 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11979 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11980 * source code that is used as the source inside a <script> tag.<br><br>
11982 * In order for the browser to process the returned data, the server must wrap the data object
11983 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11984 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11985 * depending on whether the callback name was passed:
11988 boolean scriptTag = false;
11989 String cb = request.getParameter("callback");
11992 response.setContentType("text/javascript");
11994 response.setContentType("application/x-json");
11996 Writer out = response.getWriter();
11998 out.write(cb + "(");
12000 out.print(dataBlock.toJsonString());
12007 * @param {Object} config A configuration object.
12009 Roo.data.ScriptTagProxy = function(config){
12010 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12011 Roo.apply(this, config);
12012 this.head = document.getElementsByTagName("head")[0];
12015 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12017 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12019 * @cfg {String} url The URL from which to request the data object.
12022 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12026 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12027 * the server the name of the callback function set up by the load call to process the returned data object.
12028 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12029 * javascript output which calls this named function passing the data object as its only parameter.
12031 callbackParam : "callback",
12033 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12034 * name to the request.
12039 * Load data from the configured URL, read the data object into
12040 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12041 * process that block using the passed callback.
12042 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12043 * for the request to the remote server.
12044 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12045 * object into a block of Roo.data.Records.
12046 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12047 * The function must be passed <ul>
12048 * <li>The Record block object</li>
12049 * <li>The "arg" argument from the load function</li>
12050 * <li>A boolean success indicator</li>
12052 * @param {Object} scope The scope in which to call the callback
12053 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12055 load : function(params, reader, callback, scope, arg){
12056 if(this.fireEvent("beforeload", this, params) !== false){
12058 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12060 var url = this.url;
12061 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12063 url += "&_dc=" + (new Date().getTime());
12065 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12068 cb : "stcCallback"+transId,
12069 scriptId : "stcScript"+transId,
12073 callback : callback,
12079 window[trans.cb] = function(o){
12080 conn.handleResponse(o, trans);
12083 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12085 if(this.autoAbort !== false){
12089 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12091 var script = document.createElement("script");
12092 script.setAttribute("src", url);
12093 script.setAttribute("type", "text/javascript");
12094 script.setAttribute("id", trans.scriptId);
12095 this.head.appendChild(script);
12097 this.trans = trans;
12099 callback.call(scope||this, null, arg, false);
12104 isLoading : function(){
12105 return this.trans ? true : false;
12109 * Abort the current server request.
12111 abort : function(){
12112 if(this.isLoading()){
12113 this.destroyTrans(this.trans);
12118 destroyTrans : function(trans, isLoaded){
12119 this.head.removeChild(document.getElementById(trans.scriptId));
12120 clearTimeout(trans.timeoutId);
12122 window[trans.cb] = undefined;
12124 delete window[trans.cb];
12127 // if hasn't been loaded, wait for load to remove it to prevent script error
12128 window[trans.cb] = function(){
12129 window[trans.cb] = undefined;
12131 delete window[trans.cb];
12138 handleResponse : function(o, trans){
12139 this.trans = false;
12140 this.destroyTrans(trans, true);
12143 result = trans.reader.readRecords(o);
12145 this.fireEvent("loadexception", this, o, trans.arg, e);
12146 trans.callback.call(trans.scope||window, null, trans.arg, false);
12149 this.fireEvent("load", this, o, trans.arg);
12150 trans.callback.call(trans.scope||window, result, trans.arg, true);
12154 handleFailure : function(trans){
12155 this.trans = false;
12156 this.destroyTrans(trans, false);
12157 this.fireEvent("loadexception", this, null, trans.arg);
12158 trans.callback.call(trans.scope||window, null, trans.arg, false);
12162 * Ext JS Library 1.1.1
12163 * Copyright(c) 2006-2007, Ext JS, LLC.
12165 * Originally Released Under LGPL - original licence link has changed is not relivant.
12168 * <script type="text/javascript">
12172 * @class Roo.data.JsonReader
12173 * @extends Roo.data.DataReader
12174 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12175 * based on mappings in a provided Roo.data.Record constructor.
12177 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12178 * in the reply previously.
12183 var RecordDef = Roo.data.Record.create([
12184 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12185 {name: 'occupation'} // This field will use "occupation" as the mapping.
12187 var myReader = new Roo.data.JsonReader({
12188 totalProperty: "results", // The property which contains the total dataset size (optional)
12189 root: "rows", // The property which contains an Array of row objects
12190 id: "id" // The property within each row object that provides an ID for the record (optional)
12194 * This would consume a JSON file like this:
12196 { 'results': 2, 'rows': [
12197 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12198 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12201 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12202 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12203 * paged from the remote server.
12204 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12205 * @cfg {String} root name of the property which contains the Array of row objects.
12206 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12207 * @cfg {Array} fields Array of field definition objects
12209 * Create a new JsonReader
12210 * @param {Object} meta Metadata configuration options
12211 * @param {Object} recordType Either an Array of field definition objects,
12212 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12214 Roo.data.JsonReader = function(meta, recordType){
12217 // set some defaults:
12218 Roo.applyIf(meta, {
12219 totalProperty: 'total',
12220 successProperty : 'success',
12225 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12227 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12230 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12231 * Used by Store query builder to append _requestMeta to params.
12234 metaFromRemote : false,
12236 * This method is only used by a DataProxy which has retrieved data from a remote server.
12237 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12238 * @return {Object} data A data block which is used by an Roo.data.Store object as
12239 * a cache of Roo.data.Records.
12241 read : function(response){
12242 var json = response.responseText;
12244 var o = /* eval:var:o */ eval("("+json+")");
12246 throw {message: "JsonReader.read: Json object not found"};
12252 this.metaFromRemote = true;
12253 this.meta = o.metaData;
12254 this.recordType = Roo.data.Record.create(o.metaData.fields);
12255 this.onMetaChange(this.meta, this.recordType, o);
12257 return this.readRecords(o);
12260 // private function a store will implement
12261 onMetaChange : function(meta, recordType, o){
12268 simpleAccess: function(obj, subsc) {
12275 getJsonAccessor: function(){
12277 return function(expr) {
12279 return(re.test(expr))
12280 ? new Function("obj", "return obj." + expr)
12285 return Roo.emptyFn;
12290 * Create a data block containing Roo.data.Records from an XML document.
12291 * @param {Object} o An object which contains an Array of row objects in the property specified
12292 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12293 * which contains the total size of the dataset.
12294 * @return {Object} data A data block which is used by an Roo.data.Store object as
12295 * a cache of Roo.data.Records.
12297 readRecords : function(o){
12299 * After any data loads, the raw JSON data is available for further custom processing.
12303 var s = this.meta, Record = this.recordType,
12304 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12306 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12308 if(s.totalProperty) {
12309 this.getTotal = this.getJsonAccessor(s.totalProperty);
12311 if(s.successProperty) {
12312 this.getSuccess = this.getJsonAccessor(s.successProperty);
12314 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12316 var g = this.getJsonAccessor(s.id);
12317 this.getId = function(rec) {
12319 return (r === undefined || r === "") ? null : r;
12322 this.getId = function(){return null;};
12325 for(var jj = 0; jj < fl; jj++){
12327 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12328 this.ef[jj] = this.getJsonAccessor(map);
12332 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12333 if(s.totalProperty){
12334 var vt = parseInt(this.getTotal(o), 10);
12339 if(s.successProperty){
12340 var vs = this.getSuccess(o);
12341 if(vs === false || vs === 'false'){
12346 for(var i = 0; i < c; i++){
12349 var id = this.getId(n);
12350 for(var j = 0; j < fl; j++){
12352 var v = this.ef[j](n);
12354 Roo.log('missing convert for ' + f.name);
12358 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12360 var record = new Record(values, id);
12362 records[i] = record;
12368 totalRecords : totalRecords
12373 * Ext JS Library 1.1.1
12374 * Copyright(c) 2006-2007, Ext JS, LLC.
12376 * Originally Released Under LGPL - original licence link has changed is not relivant.
12379 * <script type="text/javascript">
12383 * @class Roo.data.ArrayReader
12384 * @extends Roo.data.DataReader
12385 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12386 * Each element of that Array represents a row of data fields. The
12387 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12388 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12392 var RecordDef = Roo.data.Record.create([
12393 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12394 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12396 var myReader = new Roo.data.ArrayReader({
12397 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12401 * This would consume an Array like this:
12403 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12405 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12407 * Create a new JsonReader
12408 * @param {Object} meta Metadata configuration options.
12409 * @param {Object} recordType Either an Array of field definition objects
12410 * as specified to {@link Roo.data.Record#create},
12411 * or an {@link Roo.data.Record} object
12412 * created using {@link Roo.data.Record#create}.
12414 Roo.data.ArrayReader = function(meta, recordType){
12415 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12418 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12420 * Create a data block containing Roo.data.Records from an XML document.
12421 * @param {Object} o An Array of row objects which represents the dataset.
12422 * @return {Object} data A data block which is used by an Roo.data.Store object as
12423 * a cache of Roo.data.Records.
12425 readRecords : function(o){
12426 var sid = this.meta ? this.meta.id : null;
12427 var recordType = this.recordType, fields = recordType.prototype.fields;
12430 for(var i = 0; i < root.length; i++){
12433 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12434 for(var j = 0, jlen = fields.length; j < jlen; j++){
12435 var f = fields.items[j];
12436 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12437 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12439 values[f.name] = v;
12441 var record = new recordType(values, id);
12443 records[records.length] = record;
12447 totalRecords : records.length
12456 * @class Roo.bootstrap.ComboBox
12457 * @extends Roo.bootstrap.TriggerField
12458 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12459 * @cfg {Boolean} append (true|false) default false
12460 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12461 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12462 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12463 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12464 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12465 * @cfg {Boolean} animate default true
12466 * @cfg {Boolean} emptyResultText only for touch device
12467 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12468 * @cfg {String} emptyTitle default ''
12470 * Create a new ComboBox.
12471 * @param {Object} config Configuration options
12473 Roo.bootstrap.ComboBox = function(config){
12474 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12478 * Fires when the dropdown list is expanded
12479 * @param {Roo.bootstrap.ComboBox} combo This combo box
12484 * Fires when the dropdown list is collapsed
12485 * @param {Roo.bootstrap.ComboBox} combo This combo box
12489 * @event beforeselect
12490 * Fires before a list item is selected. Return false to cancel the selection.
12491 * @param {Roo.bootstrap.ComboBox} combo This combo box
12492 * @param {Roo.data.Record} record The data record returned from the underlying store
12493 * @param {Number} index The index of the selected item in the dropdown list
12495 'beforeselect' : true,
12498 * Fires when a list item is selected
12499 * @param {Roo.bootstrap.ComboBox} combo This combo box
12500 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12501 * @param {Number} index The index of the selected item in the dropdown list
12505 * @event beforequery
12506 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12507 * The event object passed has these properties:
12508 * @param {Roo.bootstrap.ComboBox} combo This combo box
12509 * @param {String} query The query
12510 * @param {Boolean} forceAll true to force "all" query
12511 * @param {Boolean} cancel true to cancel the query
12512 * @param {Object} e The query event object
12514 'beforequery': true,
12517 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12518 * @param {Roo.bootstrap.ComboBox} combo This combo box
12523 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12524 * @param {Roo.bootstrap.ComboBox} combo This combo box
12525 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12530 * Fires when the remove value from the combobox array
12531 * @param {Roo.bootstrap.ComboBox} combo This combo box
12535 * @event afterremove
12536 * Fires when the remove value from the combobox array
12537 * @param {Roo.bootstrap.ComboBox} combo This combo box
12539 'afterremove' : true,
12541 * @event specialfilter
12542 * Fires when specialfilter
12543 * @param {Roo.bootstrap.ComboBox} combo This combo box
12545 'specialfilter' : true,
12548 * Fires when tick the element
12549 * @param {Roo.bootstrap.ComboBox} combo This combo box
12553 * @event touchviewdisplay
12554 * Fires when touch view require special display (default is using displayField)
12555 * @param {Roo.bootstrap.ComboBox} combo This combo box
12556 * @param {Object} cfg set html .
12558 'touchviewdisplay' : true
12563 this.tickItems = [];
12565 this.selectedIndex = -1;
12566 if(this.mode == 'local'){
12567 if(config.queryDelay === undefined){
12568 this.queryDelay = 10;
12570 if(config.minChars === undefined){
12576 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12579 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12580 * rendering into an Roo.Editor, defaults to false)
12583 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12584 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12587 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12590 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12591 * the dropdown list (defaults to undefined, with no header element)
12595 * @cfg {String/Roo.Template} tpl The template to use to render the output
12599 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12601 listWidth: undefined,
12603 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12604 * mode = 'remote' or 'text' if mode = 'local')
12606 displayField: undefined,
12609 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12610 * mode = 'remote' or 'value' if mode = 'local').
12611 * Note: use of a valueField requires the user make a selection
12612 * in order for a value to be mapped.
12614 valueField: undefined,
12616 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12621 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12622 * field's data value (defaults to the underlying DOM element's name)
12624 hiddenName: undefined,
12626 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12630 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12632 selectedClass: 'active',
12635 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12639 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12640 * anchor positions (defaults to 'tl-bl')
12642 listAlign: 'tl-bl?',
12644 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12648 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12649 * query specified by the allQuery config option (defaults to 'query')
12651 triggerAction: 'query',
12653 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12654 * (defaults to 4, does not apply if editable = false)
12658 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12659 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12663 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12664 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12668 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12669 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12673 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12674 * when editable = true (defaults to false)
12676 selectOnFocus:false,
12678 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12680 queryParam: 'query',
12682 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12683 * when mode = 'remote' (defaults to 'Loading...')
12685 loadingText: 'Loading...',
12687 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12691 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12695 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12696 * traditional select (defaults to true)
12700 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12704 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12708 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12709 * listWidth has a higher value)
12713 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12714 * allow the user to set arbitrary text into the field (defaults to false)
12716 forceSelection:false,
12718 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12719 * if typeAhead = true (defaults to 250)
12721 typeAheadDelay : 250,
12723 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12724 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12726 valueNotFoundText : undefined,
12728 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12730 blockFocus : false,
12733 * @cfg {Boolean} disableClear Disable showing of clear button.
12735 disableClear : false,
12737 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12739 alwaysQuery : false,
12742 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12747 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12749 invalidClass : "has-warning",
12752 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12754 validClass : "has-success",
12757 * @cfg {Boolean} specialFilter (true|false) special filter default false
12759 specialFilter : false,
12762 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12764 mobileTouchView : true,
12767 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12769 useNativeIOS : false,
12771 ios_options : false,
12783 btnPosition : 'right',
12784 triggerList : true,
12785 showToggleBtn : true,
12787 emptyResultText: 'Empty',
12788 triggerText : 'Select',
12791 // element that contains real text value.. (when hidden is used..)
12793 getAutoCreate : function()
12798 * Render classic select for iso
12801 if(Roo.isIOS && this.useNativeIOS){
12802 cfg = this.getAutoCreateNativeIOS();
12810 if(Roo.isTouch && this.mobileTouchView){
12811 cfg = this.getAutoCreateTouchView();
12818 if(!this.tickable){
12819 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12824 * ComboBox with tickable selections
12827 var align = this.labelAlign || this.parentLabelAlign();
12830 cls : 'form-group roo-combobox-tickable' //input-group
12833 var btn_text_select = '';
12834 var btn_text_done = '';
12835 var btn_text_cancel = '';
12837 if (this.btn_text_show) {
12838 btn_text_select = 'Select';
12839 btn_text_done = 'Done';
12840 btn_text_cancel = 'Cancel';
12845 cls : 'tickable-buttons',
12850 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12851 //html : this.triggerText
12852 html: btn_text_select
12858 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12860 html: btn_text_done
12866 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12868 html: btn_text_cancel
12874 buttons.cn.unshift({
12876 cls: 'roo-select2-search-field-input'
12882 Roo.each(buttons.cn, function(c){
12884 c.cls += ' btn-' + _this.size;
12887 if (_this.disabled) {
12898 cls: 'form-hidden-field'
12902 cls: 'roo-select2-choices',
12906 cls: 'roo-select2-search-field',
12917 cls: 'roo-select2-container input-group roo-select2-container-multi',
12922 // cls: 'typeahead typeahead-long dropdown-menu',
12923 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12928 if(this.hasFeedback && !this.allowBlank){
12932 cls: 'glyphicon form-control-feedback'
12935 combobox.cn.push(feedback);
12939 if (align ==='left' && this.fieldLabel.length) {
12941 cfg.cls += ' roo-form-group-label-left';
12946 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12947 tooltip : 'This field is required'
12952 cls : 'control-label',
12953 html : this.fieldLabel
12965 var labelCfg = cfg.cn[1];
12966 var contentCfg = cfg.cn[2];
12969 if(this.indicatorpos == 'right'){
12975 cls : 'control-label',
12979 html : this.fieldLabel
12983 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12984 tooltip : 'This field is required'
12999 labelCfg = cfg.cn[0];
13000 contentCfg = cfg.cn[1];
13004 if(this.labelWidth > 12){
13005 labelCfg.style = "width: " + this.labelWidth + 'px';
13008 if(this.labelWidth < 13 && this.labelmd == 0){
13009 this.labelmd = this.labelWidth;
13012 if(this.labellg > 0){
13013 labelCfg.cls += ' col-lg-' + this.labellg;
13014 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13017 if(this.labelmd > 0){
13018 labelCfg.cls += ' col-md-' + this.labelmd;
13019 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13022 if(this.labelsm > 0){
13023 labelCfg.cls += ' col-sm-' + this.labelsm;
13024 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13027 if(this.labelxs > 0){
13028 labelCfg.cls += ' col-xs-' + this.labelxs;
13029 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13033 } else if ( this.fieldLabel.length) {
13034 // Roo.log(" label");
13038 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13039 tooltip : 'This field is required'
13043 //cls : 'input-group-addon',
13044 html : this.fieldLabel
13049 if(this.indicatorpos == 'right'){
13053 //cls : 'input-group-addon',
13054 html : this.fieldLabel
13058 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13059 tooltip : 'This field is required'
13068 // Roo.log(" no label && no align");
13075 ['xs','sm','md','lg'].map(function(size){
13076 if (settings[size]) {
13077 cfg.cls += ' col-' + size + '-' + settings[size];
13085 _initEventsCalled : false,
13088 initEvents: function()
13090 if (this._initEventsCalled) { // as we call render... prevent looping...
13093 this._initEventsCalled = true;
13096 throw "can not find store for combo";
13099 this.indicator = this.indicatorEl();
13101 this.store = Roo.factory(this.store, Roo.data);
13102 this.store.parent = this;
13104 // if we are building from html. then this element is so complex, that we can not really
13105 // use the rendered HTML.
13106 // so we have to trash and replace the previous code.
13107 if (Roo.XComponent.build_from_html) {
13108 // remove this element....
13109 var e = this.el.dom, k=0;
13110 while (e ) { e = e.previousSibling; ++k;}
13115 this.rendered = false;
13117 this.render(this.parent().getChildContainer(true), k);
13120 if(Roo.isIOS && this.useNativeIOS){
13121 this.initIOSView();
13129 if(Roo.isTouch && this.mobileTouchView){
13130 this.initTouchView();
13135 this.initTickableEvents();
13139 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13141 if(this.hiddenName){
13143 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13145 this.hiddenField.dom.value =
13146 this.hiddenValue !== undefined ? this.hiddenValue :
13147 this.value !== undefined ? this.value : '';
13149 // prevent input submission
13150 this.el.dom.removeAttribute('name');
13151 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13156 // this.el.dom.setAttribute('autocomplete', 'off');
13159 var cls = 'x-combo-list';
13161 //this.list = new Roo.Layer({
13162 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13168 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13169 _this.list.setWidth(lw);
13172 this.list.on('mouseover', this.onViewOver, this);
13173 this.list.on('mousemove', this.onViewMove, this);
13174 this.list.on('scroll', this.onViewScroll, this);
13177 this.list.swallowEvent('mousewheel');
13178 this.assetHeight = 0;
13181 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13182 this.assetHeight += this.header.getHeight();
13185 this.innerList = this.list.createChild({cls:cls+'-inner'});
13186 this.innerList.on('mouseover', this.onViewOver, this);
13187 this.innerList.on('mousemove', this.onViewMove, this);
13188 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13190 if(this.allowBlank && !this.pageSize && !this.disableClear){
13191 this.footer = this.list.createChild({cls:cls+'-ft'});
13192 this.pageTb = new Roo.Toolbar(this.footer);
13196 this.footer = this.list.createChild({cls:cls+'-ft'});
13197 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13198 {pageSize: this.pageSize});
13202 if (this.pageTb && this.allowBlank && !this.disableClear) {
13204 this.pageTb.add(new Roo.Toolbar.Fill(), {
13205 cls: 'x-btn-icon x-btn-clear',
13207 handler: function()
13210 _this.clearValue();
13211 _this.onSelect(false, -1);
13216 this.assetHeight += this.footer.getHeight();
13221 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13224 this.view = new Roo.View(this.list, this.tpl, {
13225 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13227 //this.view.wrapEl.setDisplayed(false);
13228 this.view.on('click', this.onViewClick, this);
13231 this.store.on('beforeload', this.onBeforeLoad, this);
13232 this.store.on('load', this.onLoad, this);
13233 this.store.on('loadexception', this.onLoadException, this);
13235 if(this.resizable){
13236 this.resizer = new Roo.Resizable(this.list, {
13237 pinned:true, handles:'se'
13239 this.resizer.on('resize', function(r, w, h){
13240 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13241 this.listWidth = w;
13242 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13243 this.restrictHeight();
13245 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13248 if(!this.editable){
13249 this.editable = true;
13250 this.setEditable(false);
13255 if (typeof(this.events.add.listeners) != 'undefined') {
13257 this.addicon = this.wrap.createChild(
13258 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13260 this.addicon.on('click', function(e) {
13261 this.fireEvent('add', this);
13264 if (typeof(this.events.edit.listeners) != 'undefined') {
13266 this.editicon = this.wrap.createChild(
13267 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13268 if (this.addicon) {
13269 this.editicon.setStyle('margin-left', '40px');
13271 this.editicon.on('click', function(e) {
13273 // we fire even if inothing is selected..
13274 this.fireEvent('edit', this, this.lastData );
13280 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13281 "up" : function(e){
13282 this.inKeyMode = true;
13286 "down" : function(e){
13287 if(!this.isExpanded()){
13288 this.onTriggerClick();
13290 this.inKeyMode = true;
13295 "enter" : function(e){
13296 // this.onViewClick();
13300 if(this.fireEvent("specialkey", this, e)){
13301 this.onViewClick(false);
13307 "esc" : function(e){
13311 "tab" : function(e){
13314 if(this.fireEvent("specialkey", this, e)){
13315 this.onViewClick(false);
13323 doRelay : function(foo, bar, hname){
13324 if(hname == 'down' || this.scope.isExpanded()){
13325 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13334 this.queryDelay = Math.max(this.queryDelay || 10,
13335 this.mode == 'local' ? 10 : 250);
13338 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13340 if(this.typeAhead){
13341 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13343 if(this.editable !== false){
13344 this.inputEl().on("keyup", this.onKeyUp, this);
13346 if(this.forceSelection){
13347 this.inputEl().on('blur', this.doForce, this);
13351 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13352 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13356 initTickableEvents: function()
13360 if(this.hiddenName){
13362 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13364 this.hiddenField.dom.value =
13365 this.hiddenValue !== undefined ? this.hiddenValue :
13366 this.value !== undefined ? this.value : '';
13368 // prevent input submission
13369 this.el.dom.removeAttribute('name');
13370 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13375 // this.list = this.el.select('ul.dropdown-menu',true).first();
13377 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13378 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13379 if(this.triggerList){
13380 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13383 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13384 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13386 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13387 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13389 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13390 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13392 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13393 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13394 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13397 this.cancelBtn.hide();
13402 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13403 _this.list.setWidth(lw);
13406 this.list.on('mouseover', this.onViewOver, this);
13407 this.list.on('mousemove', this.onViewMove, this);
13409 this.list.on('scroll', this.onViewScroll, this);
13412 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>';
13415 this.view = new Roo.View(this.list, this.tpl, {
13416 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13419 //this.view.wrapEl.setDisplayed(false);
13420 this.view.on('click', this.onViewClick, this);
13424 this.store.on('beforeload', this.onBeforeLoad, this);
13425 this.store.on('load', this.onLoad, this);
13426 this.store.on('loadexception', this.onLoadException, this);
13429 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13430 "up" : function(e){
13431 this.inKeyMode = true;
13435 "down" : function(e){
13436 this.inKeyMode = true;
13440 "enter" : function(e){
13441 if(this.fireEvent("specialkey", this, e)){
13442 this.onViewClick(false);
13448 "esc" : function(e){
13449 this.onTickableFooterButtonClick(e, false, false);
13452 "tab" : function(e){
13453 this.fireEvent("specialkey", this, e);
13455 this.onTickableFooterButtonClick(e, false, false);
13462 doRelay : function(e, fn, key){
13463 if(this.scope.isExpanded()){
13464 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13473 this.queryDelay = Math.max(this.queryDelay || 10,
13474 this.mode == 'local' ? 10 : 250);
13477 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13479 if(this.typeAhead){
13480 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13483 if(this.editable !== false){
13484 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13487 this.indicator = this.indicatorEl();
13489 if(this.indicator){
13490 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13491 this.indicator.hide();
13496 onDestroy : function(){
13498 this.view.setStore(null);
13499 this.view.el.removeAllListeners();
13500 this.view.el.remove();
13501 this.view.purgeListeners();
13504 this.list.dom.innerHTML = '';
13508 this.store.un('beforeload', this.onBeforeLoad, this);
13509 this.store.un('load', this.onLoad, this);
13510 this.store.un('loadexception', this.onLoadException, this);
13512 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13516 fireKey : function(e){
13517 if(e.isNavKeyPress() && !this.list.isVisible()){
13518 this.fireEvent("specialkey", this, e);
13523 onResize: function(w, h){
13524 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13526 // if(typeof w != 'number'){
13527 // // we do not handle it!?!?
13530 // var tw = this.trigger.getWidth();
13531 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13532 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13534 // this.inputEl().setWidth( this.adjustWidth('input', x));
13536 // //this.trigger.setStyle('left', x+'px');
13538 // if(this.list && this.listWidth === undefined){
13539 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13540 // this.list.setWidth(lw);
13541 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13549 * Allow or prevent the user from directly editing the field text. If false is passed,
13550 * the user will only be able to select from the items defined in the dropdown list. This method
13551 * is the runtime equivalent of setting the 'editable' config option at config time.
13552 * @param {Boolean} value True to allow the user to directly edit the field text
13554 setEditable : function(value){
13555 if(value == this.editable){
13558 this.editable = value;
13560 this.inputEl().dom.setAttribute('readOnly', true);
13561 this.inputEl().on('mousedown', this.onTriggerClick, this);
13562 this.inputEl().addClass('x-combo-noedit');
13564 this.inputEl().dom.setAttribute('readOnly', false);
13565 this.inputEl().un('mousedown', this.onTriggerClick, this);
13566 this.inputEl().removeClass('x-combo-noedit');
13572 onBeforeLoad : function(combo,opts){
13573 if(!this.hasFocus){
13577 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13579 this.restrictHeight();
13580 this.selectedIndex = -1;
13584 onLoad : function(){
13586 this.hasQuery = false;
13588 if(!this.hasFocus){
13592 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13593 this.loading.hide();
13596 if(this.store.getCount() > 0){
13599 this.restrictHeight();
13600 if(this.lastQuery == this.allQuery){
13601 if(this.editable && !this.tickable){
13602 this.inputEl().dom.select();
13606 !this.selectByValue(this.value, true) &&
13609 !this.store.lastOptions ||
13610 typeof(this.store.lastOptions.add) == 'undefined' ||
13611 this.store.lastOptions.add != true
13614 this.select(0, true);
13617 if(this.autoFocus){
13620 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13621 this.taTask.delay(this.typeAheadDelay);
13625 this.onEmptyResults();
13631 onLoadException : function()
13633 this.hasQuery = false;
13635 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13636 this.loading.hide();
13639 if(this.tickable && this.editable){
13644 // only causes errors at present
13645 //Roo.log(this.store.reader.jsonData);
13646 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13648 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13654 onTypeAhead : function(){
13655 if(this.store.getCount() > 0){
13656 var r = this.store.getAt(0);
13657 var newValue = r.data[this.displayField];
13658 var len = newValue.length;
13659 var selStart = this.getRawValue().length;
13661 if(selStart != len){
13662 this.setRawValue(newValue);
13663 this.selectText(selStart, newValue.length);
13669 onSelect : function(record, index){
13671 if(this.fireEvent('beforeselect', this, record, index) !== false){
13673 this.setFromData(index > -1 ? record.data : false);
13676 this.fireEvent('select', this, record, index);
13681 * Returns the currently selected field value or empty string if no value is set.
13682 * @return {String} value The selected value
13684 getValue : function()
13686 if(Roo.isIOS && this.useNativeIOS){
13687 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13691 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13694 if(this.valueField){
13695 return typeof this.value != 'undefined' ? this.value : '';
13697 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13701 getRawValue : function()
13703 if(Roo.isIOS && this.useNativeIOS){
13704 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13707 var v = this.inputEl().getValue();
13713 * Clears any text/value currently set in the field
13715 clearValue : function(){
13717 if(this.hiddenField){
13718 this.hiddenField.dom.value = '';
13721 this.setRawValue('');
13722 this.lastSelectionText = '';
13723 this.lastData = false;
13725 var close = this.closeTriggerEl();
13736 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13737 * will be displayed in the field. If the value does not match the data value of an existing item,
13738 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13739 * Otherwise the field will be blank (although the value will still be set).
13740 * @param {String} value The value to match
13742 setValue : function(v)
13744 if(Roo.isIOS && this.useNativeIOS){
13745 this.setIOSValue(v);
13755 if(this.valueField){
13756 var r = this.findRecord(this.valueField, v);
13758 text = r.data[this.displayField];
13759 }else if(this.valueNotFoundText !== undefined){
13760 text = this.valueNotFoundText;
13763 this.lastSelectionText = text;
13764 if(this.hiddenField){
13765 this.hiddenField.dom.value = v;
13767 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13770 var close = this.closeTriggerEl();
13773 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13779 * @property {Object} the last set data for the element
13784 * Sets the value of the field based on a object which is related to the record format for the store.
13785 * @param {Object} value the value to set as. or false on reset?
13787 setFromData : function(o){
13794 var dv = ''; // display value
13795 var vv = ''; // value value..
13797 if (this.displayField) {
13798 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13800 // this is an error condition!!!
13801 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13804 if(this.valueField){
13805 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13808 var close = this.closeTriggerEl();
13811 if(dv.length || vv * 1 > 0){
13813 this.blockFocus=true;
13819 if(this.hiddenField){
13820 this.hiddenField.dom.value = vv;
13822 this.lastSelectionText = dv;
13823 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13827 // no hidden field.. - we store the value in 'value', but still display
13828 // display field!!!!
13829 this.lastSelectionText = dv;
13830 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13837 reset : function(){
13838 // overridden so that last data is reset..
13845 this.setValue(this.originalValue);
13846 //this.clearInvalid();
13847 this.lastData = false;
13849 this.view.clearSelections();
13855 findRecord : function(prop, value){
13857 if(this.store.getCount() > 0){
13858 this.store.each(function(r){
13859 if(r.data[prop] == value){
13869 getName: function()
13871 // returns hidden if it's set..
13872 if (!this.rendered) {return ''};
13873 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13877 onViewMove : function(e, t){
13878 this.inKeyMode = false;
13882 onViewOver : function(e, t){
13883 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13886 var item = this.view.findItemFromChild(t);
13889 var index = this.view.indexOf(item);
13890 this.select(index, false);
13895 onViewClick : function(view, doFocus, el, e)
13897 var index = this.view.getSelectedIndexes()[0];
13899 var r = this.store.getAt(index);
13903 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13910 Roo.each(this.tickItems, function(v,k){
13912 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13914 _this.tickItems.splice(k, 1);
13916 if(typeof(e) == 'undefined' && view == false){
13917 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13929 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13930 this.tickItems.push(r.data);
13933 if(typeof(e) == 'undefined' && view == false){
13934 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13941 this.onSelect(r, index);
13943 if(doFocus !== false && !this.blockFocus){
13944 this.inputEl().focus();
13949 restrictHeight : function(){
13950 //this.innerList.dom.style.height = '';
13951 //var inner = this.innerList.dom;
13952 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13953 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13954 //this.list.beginUpdate();
13955 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13956 this.list.alignTo(this.inputEl(), this.listAlign);
13957 this.list.alignTo(this.inputEl(), this.listAlign);
13958 //this.list.endUpdate();
13962 onEmptyResults : function(){
13964 if(this.tickable && this.editable){
13965 this.restrictHeight();
13973 * Returns true if the dropdown list is expanded, else false.
13975 isExpanded : function(){
13976 return this.list.isVisible();
13980 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13981 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13982 * @param {String} value The data value of the item to select
13983 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13984 * selected item if it is not currently in view (defaults to true)
13985 * @return {Boolean} True if the value matched an item in the list, else false
13987 selectByValue : function(v, scrollIntoView){
13988 if(v !== undefined && v !== null){
13989 var r = this.findRecord(this.valueField || this.displayField, v);
13991 this.select(this.store.indexOf(r), scrollIntoView);
13999 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14000 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14001 * @param {Number} index The zero-based index of the list item to select
14002 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14003 * selected item if it is not currently in view (defaults to true)
14005 select : function(index, scrollIntoView){
14006 this.selectedIndex = index;
14007 this.view.select(index);
14008 if(scrollIntoView !== false){
14009 var el = this.view.getNode(index);
14011 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14014 this.list.scrollChildIntoView(el, false);
14020 selectNext : function(){
14021 var ct = this.store.getCount();
14023 if(this.selectedIndex == -1){
14025 }else if(this.selectedIndex < ct-1){
14026 this.select(this.selectedIndex+1);
14032 selectPrev : function(){
14033 var ct = this.store.getCount();
14035 if(this.selectedIndex == -1){
14037 }else if(this.selectedIndex != 0){
14038 this.select(this.selectedIndex-1);
14044 onKeyUp : function(e){
14045 if(this.editable !== false && !e.isSpecialKey()){
14046 this.lastKey = e.getKey();
14047 this.dqTask.delay(this.queryDelay);
14052 validateBlur : function(){
14053 return !this.list || !this.list.isVisible();
14057 initQuery : function(){
14059 var v = this.getRawValue();
14061 if(this.tickable && this.editable){
14062 v = this.tickableInputEl().getValue();
14069 doForce : function(){
14070 if(this.inputEl().dom.value.length > 0){
14071 this.inputEl().dom.value =
14072 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14078 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14079 * query allowing the query action to be canceled if needed.
14080 * @param {String} query The SQL query to execute
14081 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14082 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14083 * saved in the current store (defaults to false)
14085 doQuery : function(q, forceAll){
14087 if(q === undefined || q === null){
14092 forceAll: forceAll,
14096 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14101 forceAll = qe.forceAll;
14102 if(forceAll === true || (q.length >= this.minChars)){
14104 this.hasQuery = true;
14106 if(this.lastQuery != q || this.alwaysQuery){
14107 this.lastQuery = q;
14108 if(this.mode == 'local'){
14109 this.selectedIndex = -1;
14111 this.store.clearFilter();
14114 if(this.specialFilter){
14115 this.fireEvent('specialfilter', this);
14120 this.store.filter(this.displayField, q);
14123 this.store.fireEvent("datachanged", this.store);
14130 this.store.baseParams[this.queryParam] = q;
14132 var options = {params : this.getParams(q)};
14135 options.add = true;
14136 options.params.start = this.page * this.pageSize;
14139 this.store.load(options);
14142 * this code will make the page width larger, at the beginning, the list not align correctly,
14143 * we should expand the list on onLoad
14144 * so command out it
14149 this.selectedIndex = -1;
14154 this.loadNext = false;
14158 getParams : function(q){
14160 //p[this.queryParam] = q;
14164 p.limit = this.pageSize;
14170 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14172 collapse : function(){
14173 if(!this.isExpanded()){
14179 this.hasFocus = false;
14183 this.cancelBtn.hide();
14184 this.trigger.show();
14187 this.tickableInputEl().dom.value = '';
14188 this.tickableInputEl().blur();
14193 Roo.get(document).un('mousedown', this.collapseIf, this);
14194 Roo.get(document).un('mousewheel', this.collapseIf, this);
14195 if (!this.editable) {
14196 Roo.get(document).un('keydown', this.listKeyPress, this);
14198 this.fireEvent('collapse', this);
14204 collapseIf : function(e){
14205 var in_combo = e.within(this.el);
14206 var in_list = e.within(this.list);
14207 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14209 if (in_combo || in_list || is_list) {
14210 //e.stopPropagation();
14215 this.onTickableFooterButtonClick(e, false, false);
14223 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14225 expand : function(){
14227 if(this.isExpanded() || !this.hasFocus){
14231 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14232 this.list.setWidth(lw);
14238 this.restrictHeight();
14242 this.tickItems = Roo.apply([], this.item);
14245 this.cancelBtn.show();
14246 this.trigger.hide();
14249 this.tickableInputEl().focus();
14254 Roo.get(document).on('mousedown', this.collapseIf, this);
14255 Roo.get(document).on('mousewheel', this.collapseIf, this);
14256 if (!this.editable) {
14257 Roo.get(document).on('keydown', this.listKeyPress, this);
14260 this.fireEvent('expand', this);
14264 // Implements the default empty TriggerField.onTriggerClick function
14265 onTriggerClick : function(e)
14267 Roo.log('trigger click');
14269 if(this.disabled || !this.triggerList){
14274 this.loadNext = false;
14276 if(this.isExpanded()){
14278 if (!this.blockFocus) {
14279 this.inputEl().focus();
14283 this.hasFocus = true;
14284 if(this.triggerAction == 'all') {
14285 this.doQuery(this.allQuery, true);
14287 this.doQuery(this.getRawValue());
14289 if (!this.blockFocus) {
14290 this.inputEl().focus();
14295 onTickableTriggerClick : function(e)
14302 this.loadNext = false;
14303 this.hasFocus = true;
14305 if(this.triggerAction == 'all') {
14306 this.doQuery(this.allQuery, true);
14308 this.doQuery(this.getRawValue());
14312 onSearchFieldClick : function(e)
14314 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14315 this.onTickableFooterButtonClick(e, false, false);
14319 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14324 this.loadNext = false;
14325 this.hasFocus = true;
14327 if(this.triggerAction == 'all') {
14328 this.doQuery(this.allQuery, true);
14330 this.doQuery(this.getRawValue());
14334 listKeyPress : function(e)
14336 //Roo.log('listkeypress');
14337 // scroll to first matching element based on key pres..
14338 if (e.isSpecialKey()) {
14341 var k = String.fromCharCode(e.getKey()).toUpperCase();
14344 var csel = this.view.getSelectedNodes();
14345 var cselitem = false;
14347 var ix = this.view.indexOf(csel[0]);
14348 cselitem = this.store.getAt(ix);
14349 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14355 this.store.each(function(v) {
14357 // start at existing selection.
14358 if (cselitem.id == v.id) {
14364 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14365 match = this.store.indexOf(v);
14371 if (match === false) {
14372 return true; // no more action?
14375 this.view.select(match);
14376 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14377 sn.scrollIntoView(sn.dom.parentNode, false);
14380 onViewScroll : function(e, t){
14382 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){
14386 this.hasQuery = true;
14388 this.loading = this.list.select('.loading', true).first();
14390 if(this.loading === null){
14391 this.list.createChild({
14393 cls: 'loading roo-select2-more-results roo-select2-active',
14394 html: 'Loading more results...'
14397 this.loading = this.list.select('.loading', true).first();
14399 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14401 this.loading.hide();
14404 this.loading.show();
14409 this.loadNext = true;
14411 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14416 addItem : function(o)
14418 var dv = ''; // display value
14420 if (this.displayField) {
14421 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14423 // this is an error condition!!!
14424 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14431 var choice = this.choices.createChild({
14433 cls: 'roo-select2-search-choice',
14442 cls: 'roo-select2-search-choice-close fa fa-times',
14447 }, this.searchField);
14449 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14451 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14459 this.inputEl().dom.value = '';
14464 onRemoveItem : function(e, _self, o)
14466 e.preventDefault();
14468 this.lastItem = Roo.apply([], this.item);
14470 var index = this.item.indexOf(o.data) * 1;
14473 Roo.log('not this item?!');
14477 this.item.splice(index, 1);
14482 this.fireEvent('remove', this, e);
14488 syncValue : function()
14490 if(!this.item.length){
14497 Roo.each(this.item, function(i){
14498 if(_this.valueField){
14499 value.push(i[_this.valueField]);
14506 this.value = value.join(',');
14508 if(this.hiddenField){
14509 this.hiddenField.dom.value = this.value;
14512 this.store.fireEvent("datachanged", this.store);
14517 clearItem : function()
14519 if(!this.multiple){
14525 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14533 if(this.tickable && !Roo.isTouch){
14534 this.view.refresh();
14538 inputEl: function ()
14540 if(Roo.isIOS && this.useNativeIOS){
14541 return this.el.select('select.roo-ios-select', true).first();
14544 if(Roo.isTouch && this.mobileTouchView){
14545 return this.el.select('input.form-control',true).first();
14549 return this.searchField;
14552 return this.el.select('input.form-control',true).first();
14555 onTickableFooterButtonClick : function(e, btn, el)
14557 e.preventDefault();
14559 this.lastItem = Roo.apply([], this.item);
14561 if(btn && btn.name == 'cancel'){
14562 this.tickItems = Roo.apply([], this.item);
14571 Roo.each(this.tickItems, function(o){
14579 validate : function()
14581 var v = this.getRawValue();
14584 v = this.getValue();
14587 if(this.disabled || this.allowBlank || v.length){
14592 this.markInvalid();
14596 tickableInputEl : function()
14598 if(!this.tickable || !this.editable){
14599 return this.inputEl();
14602 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14606 getAutoCreateTouchView : function()
14611 cls: 'form-group' //input-group
14617 type : this.inputType,
14618 cls : 'form-control x-combo-noedit',
14619 autocomplete: 'new-password',
14620 placeholder : this.placeholder || '',
14625 input.name = this.name;
14629 input.cls += ' input-' + this.size;
14632 if (this.disabled) {
14633 input.disabled = true;
14644 inputblock.cls += ' input-group';
14646 inputblock.cn.unshift({
14648 cls : 'input-group-addon',
14653 if(this.removable && !this.multiple){
14654 inputblock.cls += ' roo-removable';
14656 inputblock.cn.push({
14659 cls : 'roo-combo-removable-btn close'
14663 if(this.hasFeedback && !this.allowBlank){
14665 inputblock.cls += ' has-feedback';
14667 inputblock.cn.push({
14669 cls: 'glyphicon form-control-feedback'
14676 inputblock.cls += (this.before) ? '' : ' input-group';
14678 inputblock.cn.push({
14680 cls : 'input-group-addon',
14691 cls: 'form-hidden-field'
14705 cls: 'form-hidden-field'
14709 cls: 'roo-select2-choices',
14713 cls: 'roo-select2-search-field',
14726 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14732 if(!this.multiple && this.showToggleBtn){
14739 if (this.caret != false) {
14742 cls: 'fa fa-' + this.caret
14749 cls : 'input-group-addon btn dropdown-toggle',
14754 cls: 'combobox-clear',
14768 combobox.cls += ' roo-select2-container-multi';
14771 var align = this.labelAlign || this.parentLabelAlign();
14773 if (align ==='left' && this.fieldLabel.length) {
14778 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14779 tooltip : 'This field is required'
14783 cls : 'control-label',
14784 html : this.fieldLabel
14795 var labelCfg = cfg.cn[1];
14796 var contentCfg = cfg.cn[2];
14799 if(this.indicatorpos == 'right'){
14804 cls : 'control-label',
14808 html : this.fieldLabel
14812 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14813 tooltip : 'This field is required'
14826 labelCfg = cfg.cn[0];
14827 contentCfg = cfg.cn[1];
14832 if(this.labelWidth > 12){
14833 labelCfg.style = "width: " + this.labelWidth + 'px';
14836 if(this.labelWidth < 13 && this.labelmd == 0){
14837 this.labelmd = this.labelWidth;
14840 if(this.labellg > 0){
14841 labelCfg.cls += ' col-lg-' + this.labellg;
14842 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14845 if(this.labelmd > 0){
14846 labelCfg.cls += ' col-md-' + this.labelmd;
14847 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14850 if(this.labelsm > 0){
14851 labelCfg.cls += ' col-sm-' + this.labelsm;
14852 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14855 if(this.labelxs > 0){
14856 labelCfg.cls += ' col-xs-' + this.labelxs;
14857 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14861 } else if ( this.fieldLabel.length) {
14865 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14866 tooltip : 'This field is required'
14870 cls : 'control-label',
14871 html : this.fieldLabel
14882 if(this.indicatorpos == 'right'){
14886 cls : 'control-label',
14887 html : this.fieldLabel,
14891 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14892 tooltip : 'This field is required'
14909 var settings = this;
14911 ['xs','sm','md','lg'].map(function(size){
14912 if (settings[size]) {
14913 cfg.cls += ' col-' + size + '-' + settings[size];
14920 initTouchView : function()
14922 this.renderTouchView();
14924 this.touchViewEl.on('scroll', function(){
14925 this.el.dom.scrollTop = 0;
14928 this.originalValue = this.getValue();
14930 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14932 this.inputEl().on("click", this.showTouchView, this);
14933 if (this.triggerEl) {
14934 this.triggerEl.on("click", this.showTouchView, this);
14938 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14939 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14941 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14943 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14944 this.store.on('load', this.onTouchViewLoad, this);
14945 this.store.on('loadexception', this.onTouchViewLoadException, this);
14947 if(this.hiddenName){
14949 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14951 this.hiddenField.dom.value =
14952 this.hiddenValue !== undefined ? this.hiddenValue :
14953 this.value !== undefined ? this.value : '';
14955 this.el.dom.removeAttribute('name');
14956 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14960 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14961 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14964 if(this.removable && !this.multiple){
14965 var close = this.closeTriggerEl();
14967 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14968 close.on('click', this.removeBtnClick, this, close);
14972 * fix the bug in Safari iOS8
14974 this.inputEl().on("focus", function(e){
14975 document.activeElement.blur();
14983 renderTouchView : function()
14985 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14986 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14988 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14989 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14991 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14992 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14993 this.touchViewBodyEl.setStyle('overflow', 'auto');
14995 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14996 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14998 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14999 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15003 showTouchView : function()
15009 this.touchViewHeaderEl.hide();
15011 if(this.modalTitle.length){
15012 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15013 this.touchViewHeaderEl.show();
15016 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15017 this.touchViewEl.show();
15019 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15021 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15022 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15024 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15026 if(this.modalTitle.length){
15027 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15030 this.touchViewBodyEl.setHeight(bodyHeight);
15034 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15036 this.touchViewEl.addClass('in');
15039 this.doTouchViewQuery();
15043 hideTouchView : function()
15045 this.touchViewEl.removeClass('in');
15049 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15051 this.touchViewEl.setStyle('display', 'none');
15056 setTouchViewValue : function()
15063 Roo.each(this.tickItems, function(o){
15068 this.hideTouchView();
15071 doTouchViewQuery : function()
15080 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15084 if(!this.alwaysQuery || this.mode == 'local'){
15085 this.onTouchViewLoad();
15092 onTouchViewBeforeLoad : function(combo,opts)
15098 onTouchViewLoad : function()
15100 if(this.store.getCount() < 1){
15101 this.onTouchViewEmptyResults();
15105 this.clearTouchView();
15107 var rawValue = this.getRawValue();
15109 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15111 this.tickItems = [];
15113 this.store.data.each(function(d, rowIndex){
15114 var row = this.touchViewListGroup.createChild(template);
15116 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15117 row.addClass(d.data.cls);
15120 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15123 html : d.data[this.displayField]
15126 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15127 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15130 row.removeClass('selected');
15131 if(!this.multiple && this.valueField &&
15132 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15135 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15136 row.addClass('selected');
15139 if(this.multiple && this.valueField &&
15140 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15144 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15145 this.tickItems.push(d.data);
15148 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15152 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15154 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15156 if(this.modalTitle.length){
15157 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15160 var listHeight = this.touchViewListGroup.getHeight();
15164 if(firstChecked && listHeight > bodyHeight){
15165 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15170 onTouchViewLoadException : function()
15172 this.hideTouchView();
15175 onTouchViewEmptyResults : function()
15177 this.clearTouchView();
15179 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15181 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15185 clearTouchView : function()
15187 this.touchViewListGroup.dom.innerHTML = '';
15190 onTouchViewClick : function(e, el, o)
15192 e.preventDefault();
15195 var rowIndex = o.rowIndex;
15197 var r = this.store.getAt(rowIndex);
15199 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15201 if(!this.multiple){
15202 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15203 c.dom.removeAttribute('checked');
15206 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15208 this.setFromData(r.data);
15210 var close = this.closeTriggerEl();
15216 this.hideTouchView();
15218 this.fireEvent('select', this, r, rowIndex);
15223 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15224 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15225 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15229 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15230 this.addItem(r.data);
15231 this.tickItems.push(r.data);
15235 getAutoCreateNativeIOS : function()
15238 cls: 'form-group' //input-group,
15243 cls : 'roo-ios-select'
15247 combobox.name = this.name;
15250 if (this.disabled) {
15251 combobox.disabled = true;
15254 var settings = this;
15256 ['xs','sm','md','lg'].map(function(size){
15257 if (settings[size]) {
15258 cfg.cls += ' col-' + size + '-' + settings[size];
15268 initIOSView : function()
15270 this.store.on('load', this.onIOSViewLoad, this);
15275 onIOSViewLoad : function()
15277 if(this.store.getCount() < 1){
15281 this.clearIOSView();
15283 if(this.allowBlank) {
15285 var default_text = '-- SELECT --';
15287 if(this.placeholder.length){
15288 default_text = this.placeholder;
15291 if(this.emptyTitle.length){
15292 default_text += ' - ' + this.emptyTitle + ' -';
15295 var opt = this.inputEl().createChild({
15298 html : default_text
15302 o[this.valueField] = 0;
15303 o[this.displayField] = default_text;
15305 this.ios_options.push({
15312 this.store.data.each(function(d, rowIndex){
15316 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15317 html = d.data[this.displayField];
15322 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15323 value = d.data[this.valueField];
15332 if(this.value == d.data[this.valueField]){
15333 option['selected'] = true;
15336 var opt = this.inputEl().createChild(option);
15338 this.ios_options.push({
15345 this.inputEl().on('change', function(){
15346 this.fireEvent('select', this);
15351 clearIOSView: function()
15353 this.inputEl().dom.innerHTML = '';
15355 this.ios_options = [];
15358 setIOSValue: function(v)
15362 if(!this.ios_options){
15366 Roo.each(this.ios_options, function(opts){
15368 opts.el.dom.removeAttribute('selected');
15370 if(opts.data[this.valueField] != v){
15374 opts.el.dom.setAttribute('selected', true);
15380 * @cfg {Boolean} grow
15384 * @cfg {Number} growMin
15388 * @cfg {Number} growMax
15397 Roo.apply(Roo.bootstrap.ComboBox, {
15401 cls: 'modal-header',
15423 cls: 'list-group-item',
15427 cls: 'roo-combobox-list-group-item-value'
15431 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15445 listItemCheckbox : {
15447 cls: 'list-group-item',
15451 cls: 'roo-combobox-list-group-item-value'
15455 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15471 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15476 cls: 'modal-footer',
15484 cls: 'col-xs-6 text-left',
15487 cls: 'btn btn-danger roo-touch-view-cancel',
15493 cls: 'col-xs-6 text-right',
15496 cls: 'btn btn-success roo-touch-view-ok',
15507 Roo.apply(Roo.bootstrap.ComboBox, {
15509 touchViewTemplate : {
15511 cls: 'modal fade roo-combobox-touch-view',
15515 cls: 'modal-dialog',
15516 style : 'position:fixed', // we have to fix position....
15520 cls: 'modal-content',
15522 Roo.bootstrap.ComboBox.header,
15523 Roo.bootstrap.ComboBox.body,
15524 Roo.bootstrap.ComboBox.footer
15533 * Ext JS Library 1.1.1
15534 * Copyright(c) 2006-2007, Ext JS, LLC.
15536 * Originally Released Under LGPL - original licence link has changed is not relivant.
15539 * <script type="text/javascript">
15544 * @extends Roo.util.Observable
15545 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15546 * This class also supports single and multi selection modes. <br>
15547 * Create a data model bound view:
15549 var store = new Roo.data.Store(...);
15551 var view = new Roo.View({
15553 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15555 singleSelect: true,
15556 selectedClass: "ydataview-selected",
15560 // listen for node click?
15561 view.on("click", function(vw, index, node, e){
15562 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15566 dataModel.load("foobar.xml");
15568 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15570 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15571 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15573 * Note: old style constructor is still suported (container, template, config)
15576 * Create a new View
15577 * @param {Object} config The config object
15580 Roo.View = function(config, depreciated_tpl, depreciated_config){
15582 this.parent = false;
15584 if (typeof(depreciated_tpl) == 'undefined') {
15585 // new way.. - universal constructor.
15586 Roo.apply(this, config);
15587 this.el = Roo.get(this.el);
15590 this.el = Roo.get(config);
15591 this.tpl = depreciated_tpl;
15592 Roo.apply(this, depreciated_config);
15594 this.wrapEl = this.el.wrap().wrap();
15595 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15598 if(typeof(this.tpl) == "string"){
15599 this.tpl = new Roo.Template(this.tpl);
15601 // support xtype ctors..
15602 this.tpl = new Roo.factory(this.tpl, Roo);
15606 this.tpl.compile();
15611 * @event beforeclick
15612 * Fires before a click is processed. Returns false to cancel the default action.
15613 * @param {Roo.View} this
15614 * @param {Number} index The index of the target node
15615 * @param {HTMLElement} node The target node
15616 * @param {Roo.EventObject} e The raw event object
15618 "beforeclick" : true,
15621 * Fires when a template node is clicked.
15622 * @param {Roo.View} this
15623 * @param {Number} index The index of the target node
15624 * @param {HTMLElement} node The target node
15625 * @param {Roo.EventObject} e The raw event object
15630 * Fires when a template node is double clicked.
15631 * @param {Roo.View} this
15632 * @param {Number} index The index of the target node
15633 * @param {HTMLElement} node The target node
15634 * @param {Roo.EventObject} e The raw event object
15638 * @event contextmenu
15639 * Fires when a template node is right clicked.
15640 * @param {Roo.View} this
15641 * @param {Number} index The index of the target node
15642 * @param {HTMLElement} node The target node
15643 * @param {Roo.EventObject} e The raw event object
15645 "contextmenu" : true,
15647 * @event selectionchange
15648 * Fires when the selected nodes change.
15649 * @param {Roo.View} this
15650 * @param {Array} selections Array of the selected nodes
15652 "selectionchange" : true,
15655 * @event beforeselect
15656 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15657 * @param {Roo.View} this
15658 * @param {HTMLElement} node The node to be selected
15659 * @param {Array} selections Array of currently selected nodes
15661 "beforeselect" : true,
15663 * @event preparedata
15664 * Fires on every row to render, to allow you to change the data.
15665 * @param {Roo.View} this
15666 * @param {Object} data to be rendered (change this)
15668 "preparedata" : true
15676 "click": this.onClick,
15677 "dblclick": this.onDblClick,
15678 "contextmenu": this.onContextMenu,
15682 this.selections = [];
15684 this.cmp = new Roo.CompositeElementLite([]);
15686 this.store = Roo.factory(this.store, Roo.data);
15687 this.setStore(this.store, true);
15690 if ( this.footer && this.footer.xtype) {
15692 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15694 this.footer.dataSource = this.store;
15695 this.footer.container = fctr;
15696 this.footer = Roo.factory(this.footer, Roo);
15697 fctr.insertFirst(this.el);
15699 // this is a bit insane - as the paging toolbar seems to detach the el..
15700 // dom.parentNode.parentNode.parentNode
15701 // they get detached?
15705 Roo.View.superclass.constructor.call(this);
15710 Roo.extend(Roo.View, Roo.util.Observable, {
15713 * @cfg {Roo.data.Store} store Data store to load data from.
15718 * @cfg {String|Roo.Element} el The container element.
15723 * @cfg {String|Roo.Template} tpl The template used by this View
15727 * @cfg {String} dataName the named area of the template to use as the data area
15728 * Works with domtemplates roo-name="name"
15732 * @cfg {String} selectedClass The css class to add to selected nodes
15734 selectedClass : "x-view-selected",
15736 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15741 * @cfg {String} text to display on mask (default Loading)
15745 * @cfg {Boolean} multiSelect Allow multiple selection
15747 multiSelect : false,
15749 * @cfg {Boolean} singleSelect Allow single selection
15751 singleSelect: false,
15754 * @cfg {Boolean} toggleSelect - selecting
15756 toggleSelect : false,
15759 * @cfg {Boolean} tickable - selecting
15764 * Returns the element this view is bound to.
15765 * @return {Roo.Element}
15767 getEl : function(){
15768 return this.wrapEl;
15774 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15776 refresh : function(){
15777 //Roo.log('refresh');
15780 // if we are using something like 'domtemplate', then
15781 // the what gets used is:
15782 // t.applySubtemplate(NAME, data, wrapping data..)
15783 // the outer template then get' applied with
15784 // the store 'extra data'
15785 // and the body get's added to the
15786 // roo-name="data" node?
15787 // <span class='roo-tpl-{name}'></span> ?????
15791 this.clearSelections();
15792 this.el.update("");
15794 var records = this.store.getRange();
15795 if(records.length < 1) {
15797 // is this valid?? = should it render a template??
15799 this.el.update(this.emptyText);
15803 if (this.dataName) {
15804 this.el.update(t.apply(this.store.meta)); //????
15805 el = this.el.child('.roo-tpl-' + this.dataName);
15808 for(var i = 0, len = records.length; i < len; i++){
15809 var data = this.prepareData(records[i].data, i, records[i]);
15810 this.fireEvent("preparedata", this, data, i, records[i]);
15812 var d = Roo.apply({}, data);
15815 Roo.apply(d, {'roo-id' : Roo.id()});
15819 Roo.each(this.parent.item, function(item){
15820 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15823 Roo.apply(d, {'roo-data-checked' : 'checked'});
15827 html[html.length] = Roo.util.Format.trim(
15829 t.applySubtemplate(this.dataName, d, this.store.meta) :
15836 el.update(html.join(""));
15837 this.nodes = el.dom.childNodes;
15838 this.updateIndexes(0);
15843 * Function to override to reformat the data that is sent to
15844 * the template for each node.
15845 * DEPRICATED - use the preparedata event handler.
15846 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15847 * a JSON object for an UpdateManager bound view).
15849 prepareData : function(data, index, record)
15851 this.fireEvent("preparedata", this, data, index, record);
15855 onUpdate : function(ds, record){
15856 // Roo.log('on update');
15857 this.clearSelections();
15858 var index = this.store.indexOf(record);
15859 var n = this.nodes[index];
15860 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15861 n.parentNode.removeChild(n);
15862 this.updateIndexes(index, index);
15868 onAdd : function(ds, records, index)
15870 //Roo.log(['on Add', ds, records, index] );
15871 this.clearSelections();
15872 if(this.nodes.length == 0){
15876 var n = this.nodes[index];
15877 for(var i = 0, len = records.length; i < len; i++){
15878 var d = this.prepareData(records[i].data, i, records[i]);
15880 this.tpl.insertBefore(n, d);
15883 this.tpl.append(this.el, d);
15886 this.updateIndexes(index);
15889 onRemove : function(ds, record, index){
15890 // Roo.log('onRemove');
15891 this.clearSelections();
15892 var el = this.dataName ?
15893 this.el.child('.roo-tpl-' + this.dataName) :
15896 el.dom.removeChild(this.nodes[index]);
15897 this.updateIndexes(index);
15901 * Refresh an individual node.
15902 * @param {Number} index
15904 refreshNode : function(index){
15905 this.onUpdate(this.store, this.store.getAt(index));
15908 updateIndexes : function(startIndex, endIndex){
15909 var ns = this.nodes;
15910 startIndex = startIndex || 0;
15911 endIndex = endIndex || ns.length - 1;
15912 for(var i = startIndex; i <= endIndex; i++){
15913 ns[i].nodeIndex = i;
15918 * Changes the data store this view uses and refresh the view.
15919 * @param {Store} store
15921 setStore : function(store, initial){
15922 if(!initial && this.store){
15923 this.store.un("datachanged", this.refresh);
15924 this.store.un("add", this.onAdd);
15925 this.store.un("remove", this.onRemove);
15926 this.store.un("update", this.onUpdate);
15927 this.store.un("clear", this.refresh);
15928 this.store.un("beforeload", this.onBeforeLoad);
15929 this.store.un("load", this.onLoad);
15930 this.store.un("loadexception", this.onLoad);
15934 store.on("datachanged", this.refresh, this);
15935 store.on("add", this.onAdd, this);
15936 store.on("remove", this.onRemove, this);
15937 store.on("update", this.onUpdate, this);
15938 store.on("clear", this.refresh, this);
15939 store.on("beforeload", this.onBeforeLoad, this);
15940 store.on("load", this.onLoad, this);
15941 store.on("loadexception", this.onLoad, this);
15949 * onbeforeLoad - masks the loading area.
15952 onBeforeLoad : function(store,opts)
15954 //Roo.log('onBeforeLoad');
15956 this.el.update("");
15958 this.el.mask(this.mask ? this.mask : "Loading" );
15960 onLoad : function ()
15967 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15968 * @param {HTMLElement} node
15969 * @return {HTMLElement} The template node
15971 findItemFromChild : function(node){
15972 var el = this.dataName ?
15973 this.el.child('.roo-tpl-' + this.dataName,true) :
15976 if(!node || node.parentNode == el){
15979 var p = node.parentNode;
15980 while(p && p != el){
15981 if(p.parentNode == el){
15990 onClick : function(e){
15991 var item = this.findItemFromChild(e.getTarget());
15993 var index = this.indexOf(item);
15994 if(this.onItemClick(item, index, e) !== false){
15995 this.fireEvent("click", this, index, item, e);
15998 this.clearSelections();
16003 onContextMenu : function(e){
16004 var item = this.findItemFromChild(e.getTarget());
16006 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16011 onDblClick : function(e){
16012 var item = this.findItemFromChild(e.getTarget());
16014 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16018 onItemClick : function(item, index, e)
16020 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16023 if (this.toggleSelect) {
16024 var m = this.isSelected(item) ? 'unselect' : 'select';
16027 _t[m](item, true, false);
16030 if(this.multiSelect || this.singleSelect){
16031 if(this.multiSelect && e.shiftKey && this.lastSelection){
16032 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16034 this.select(item, this.multiSelect && e.ctrlKey);
16035 this.lastSelection = item;
16038 if(!this.tickable){
16039 e.preventDefault();
16047 * Get the number of selected nodes.
16050 getSelectionCount : function(){
16051 return this.selections.length;
16055 * Get the currently selected nodes.
16056 * @return {Array} An array of HTMLElements
16058 getSelectedNodes : function(){
16059 return this.selections;
16063 * Get the indexes of the selected nodes.
16066 getSelectedIndexes : function(){
16067 var indexes = [], s = this.selections;
16068 for(var i = 0, len = s.length; i < len; i++){
16069 indexes.push(s[i].nodeIndex);
16075 * Clear all selections
16076 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16078 clearSelections : function(suppressEvent){
16079 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16080 this.cmp.elements = this.selections;
16081 this.cmp.removeClass(this.selectedClass);
16082 this.selections = [];
16083 if(!suppressEvent){
16084 this.fireEvent("selectionchange", this, this.selections);
16090 * Returns true if the passed node is selected
16091 * @param {HTMLElement/Number} node The node or node index
16092 * @return {Boolean}
16094 isSelected : function(node){
16095 var s = this.selections;
16099 node = this.getNode(node);
16100 return s.indexOf(node) !== -1;
16105 * @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
16106 * @param {Boolean} keepExisting (optional) true to keep existing selections
16107 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16109 select : function(nodeInfo, keepExisting, suppressEvent){
16110 if(nodeInfo instanceof Array){
16112 this.clearSelections(true);
16114 for(var i = 0, len = nodeInfo.length; i < len; i++){
16115 this.select(nodeInfo[i], true, true);
16119 var node = this.getNode(nodeInfo);
16120 if(!node || this.isSelected(node)){
16121 return; // already selected.
16124 this.clearSelections(true);
16127 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16128 Roo.fly(node).addClass(this.selectedClass);
16129 this.selections.push(node);
16130 if(!suppressEvent){
16131 this.fireEvent("selectionchange", this, this.selections);
16139 * @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
16140 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16141 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16143 unselect : function(nodeInfo, keepExisting, suppressEvent)
16145 if(nodeInfo instanceof Array){
16146 Roo.each(this.selections, function(s) {
16147 this.unselect(s, nodeInfo);
16151 var node = this.getNode(nodeInfo);
16152 if(!node || !this.isSelected(node)){
16153 //Roo.log("not selected");
16154 return; // not selected.
16158 Roo.each(this.selections, function(s) {
16160 Roo.fly(node).removeClass(this.selectedClass);
16167 this.selections= ns;
16168 this.fireEvent("selectionchange", this, this.selections);
16172 * Gets a template node.
16173 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16174 * @return {HTMLElement} The node or null if it wasn't found
16176 getNode : function(nodeInfo){
16177 if(typeof nodeInfo == "string"){
16178 return document.getElementById(nodeInfo);
16179 }else if(typeof nodeInfo == "number"){
16180 return this.nodes[nodeInfo];
16186 * Gets a range template nodes.
16187 * @param {Number} startIndex
16188 * @param {Number} endIndex
16189 * @return {Array} An array of nodes
16191 getNodes : function(start, end){
16192 var ns = this.nodes;
16193 start = start || 0;
16194 end = typeof end == "undefined" ? ns.length - 1 : end;
16197 for(var i = start; i <= end; i++){
16201 for(var i = start; i >= end; i--){
16209 * Finds the index of the passed node
16210 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16211 * @return {Number} The index of the node or -1
16213 indexOf : function(node){
16214 node = this.getNode(node);
16215 if(typeof node.nodeIndex == "number"){
16216 return node.nodeIndex;
16218 var ns = this.nodes;
16219 for(var i = 0, len = ns.length; i < len; i++){
16230 * based on jquery fullcalendar
16234 Roo.bootstrap = Roo.bootstrap || {};
16236 * @class Roo.bootstrap.Calendar
16237 * @extends Roo.bootstrap.Component
16238 * Bootstrap Calendar class
16239 * @cfg {Boolean} loadMask (true|false) default false
16240 * @cfg {Object} header generate the user specific header of the calendar, default false
16243 * Create a new Container
16244 * @param {Object} config The config object
16249 Roo.bootstrap.Calendar = function(config){
16250 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16254 * Fires when a date is selected
16255 * @param {DatePicker} this
16256 * @param {Date} date The selected date
16260 * @event monthchange
16261 * Fires when the displayed month changes
16262 * @param {DatePicker} this
16263 * @param {Date} date The selected month
16265 'monthchange': true,
16267 * @event evententer
16268 * Fires when mouse over an event
16269 * @param {Calendar} this
16270 * @param {event} Event
16272 'evententer': true,
16274 * @event eventleave
16275 * Fires when the mouse leaves an
16276 * @param {Calendar} this
16279 'eventleave': true,
16281 * @event eventclick
16282 * Fires when the mouse click an
16283 * @param {Calendar} this
16292 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16295 * @cfg {Number} startDay
16296 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16304 getAutoCreate : function(){
16307 var fc_button = function(name, corner, style, content ) {
16308 return Roo.apply({},{
16310 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16312 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16315 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16326 style : 'width:100%',
16333 cls : 'fc-header-left',
16335 fc_button('prev', 'left', 'arrow', '‹' ),
16336 fc_button('next', 'right', 'arrow', '›' ),
16337 { tag: 'span', cls: 'fc-header-space' },
16338 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16346 cls : 'fc-header-center',
16350 cls: 'fc-header-title',
16353 html : 'month / year'
16361 cls : 'fc-header-right',
16363 /* fc_button('month', 'left', '', 'month' ),
16364 fc_button('week', '', '', 'week' ),
16365 fc_button('day', 'right', '', 'day' )
16377 header = this.header;
16380 var cal_heads = function() {
16382 // fixme - handle this.
16384 for (var i =0; i < Date.dayNames.length; i++) {
16385 var d = Date.dayNames[i];
16388 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16389 html : d.substring(0,3)
16393 ret[0].cls += ' fc-first';
16394 ret[6].cls += ' fc-last';
16397 var cal_cell = function(n) {
16400 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16405 cls: 'fc-day-number',
16409 cls: 'fc-day-content',
16413 style: 'position: relative;' // height: 17px;
16425 var cal_rows = function() {
16428 for (var r = 0; r < 6; r++) {
16435 for (var i =0; i < Date.dayNames.length; i++) {
16436 var d = Date.dayNames[i];
16437 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16440 row.cn[0].cls+=' fc-first';
16441 row.cn[0].cn[0].style = 'min-height:90px';
16442 row.cn[6].cls+=' fc-last';
16446 ret[0].cls += ' fc-first';
16447 ret[4].cls += ' fc-prev-last';
16448 ret[5].cls += ' fc-last';
16455 cls: 'fc-border-separate',
16456 style : 'width:100%',
16464 cls : 'fc-first fc-last',
16482 cls : 'fc-content',
16483 style : "position: relative;",
16486 cls : 'fc-view fc-view-month fc-grid',
16487 style : 'position: relative',
16488 unselectable : 'on',
16491 cls : 'fc-event-container',
16492 style : 'position:absolute;z-index:8;top:0;left:0;'
16510 initEvents : function()
16513 throw "can not find store for calendar";
16519 style: "text-align:center",
16523 style: "background-color:white;width:50%;margin:250 auto",
16527 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16538 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16540 var size = this.el.select('.fc-content', true).first().getSize();
16541 this.maskEl.setSize(size.width, size.height);
16542 this.maskEl.enableDisplayMode("block");
16543 if(!this.loadMask){
16544 this.maskEl.hide();
16547 this.store = Roo.factory(this.store, Roo.data);
16548 this.store.on('load', this.onLoad, this);
16549 this.store.on('beforeload', this.onBeforeLoad, this);
16553 this.cells = this.el.select('.fc-day',true);
16554 //Roo.log(this.cells);
16555 this.textNodes = this.el.query('.fc-day-number');
16556 this.cells.addClassOnOver('fc-state-hover');
16558 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16559 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16560 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16561 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16563 this.on('monthchange', this.onMonthChange, this);
16565 this.update(new Date().clearTime());
16568 resize : function() {
16569 var sz = this.el.getSize();
16571 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16572 this.el.select('.fc-day-content div',true).setHeight(34);
16577 showPrevMonth : function(e){
16578 this.update(this.activeDate.add("mo", -1));
16580 showToday : function(e){
16581 this.update(new Date().clearTime());
16584 showNextMonth : function(e){
16585 this.update(this.activeDate.add("mo", 1));
16589 showPrevYear : function(){
16590 this.update(this.activeDate.add("y", -1));
16594 showNextYear : function(){
16595 this.update(this.activeDate.add("y", 1));
16600 update : function(date)
16602 var vd = this.activeDate;
16603 this.activeDate = date;
16604 // if(vd && this.el){
16605 // var t = date.getTime();
16606 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16607 // Roo.log('using add remove');
16609 // this.fireEvent('monthchange', this, date);
16611 // this.cells.removeClass("fc-state-highlight");
16612 // this.cells.each(function(c){
16613 // if(c.dateValue == t){
16614 // c.addClass("fc-state-highlight");
16615 // setTimeout(function(){
16616 // try{c.dom.firstChild.focus();}catch(e){}
16626 var days = date.getDaysInMonth();
16628 var firstOfMonth = date.getFirstDateOfMonth();
16629 var startingPos = firstOfMonth.getDay()-this.startDay;
16631 if(startingPos < this.startDay){
16635 var pm = date.add(Date.MONTH, -1);
16636 var prevStart = pm.getDaysInMonth()-startingPos;
16638 this.cells = this.el.select('.fc-day',true);
16639 this.textNodes = this.el.query('.fc-day-number');
16640 this.cells.addClassOnOver('fc-state-hover');
16642 var cells = this.cells.elements;
16643 var textEls = this.textNodes;
16645 Roo.each(cells, function(cell){
16646 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16649 days += startingPos;
16651 // convert everything to numbers so it's fast
16652 var day = 86400000;
16653 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16656 //Roo.log(prevStart);
16658 var today = new Date().clearTime().getTime();
16659 var sel = date.clearTime().getTime();
16660 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16661 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16662 var ddMatch = this.disabledDatesRE;
16663 var ddText = this.disabledDatesText;
16664 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16665 var ddaysText = this.disabledDaysText;
16666 var format = this.format;
16668 var setCellClass = function(cal, cell){
16672 //Roo.log('set Cell Class');
16674 var t = d.getTime();
16678 cell.dateValue = t;
16680 cell.className += " fc-today";
16681 cell.className += " fc-state-highlight";
16682 cell.title = cal.todayText;
16685 // disable highlight in other month..
16686 //cell.className += " fc-state-highlight";
16691 cell.className = " fc-state-disabled";
16692 cell.title = cal.minText;
16696 cell.className = " fc-state-disabled";
16697 cell.title = cal.maxText;
16701 if(ddays.indexOf(d.getDay()) != -1){
16702 cell.title = ddaysText;
16703 cell.className = " fc-state-disabled";
16706 if(ddMatch && format){
16707 var fvalue = d.dateFormat(format);
16708 if(ddMatch.test(fvalue)){
16709 cell.title = ddText.replace("%0", fvalue);
16710 cell.className = " fc-state-disabled";
16714 if (!cell.initialClassName) {
16715 cell.initialClassName = cell.dom.className;
16718 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16723 for(; i < startingPos; i++) {
16724 textEls[i].innerHTML = (++prevStart);
16725 d.setDate(d.getDate()+1);
16727 cells[i].className = "fc-past fc-other-month";
16728 setCellClass(this, cells[i]);
16733 for(; i < days; i++){
16734 intDay = i - startingPos + 1;
16735 textEls[i].innerHTML = (intDay);
16736 d.setDate(d.getDate()+1);
16738 cells[i].className = ''; // "x-date-active";
16739 setCellClass(this, cells[i]);
16743 for(; i < 42; i++) {
16744 textEls[i].innerHTML = (++extraDays);
16745 d.setDate(d.getDate()+1);
16747 cells[i].className = "fc-future fc-other-month";
16748 setCellClass(this, cells[i]);
16751 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16753 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16755 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16756 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16758 if(totalRows != 6){
16759 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16760 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16763 this.fireEvent('monthchange', this, date);
16767 if(!this.internalRender){
16768 var main = this.el.dom.firstChild;
16769 var w = main.offsetWidth;
16770 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16771 Roo.fly(main).setWidth(w);
16772 this.internalRender = true;
16773 // opera does not respect the auto grow header center column
16774 // then, after it gets a width opera refuses to recalculate
16775 // without a second pass
16776 if(Roo.isOpera && !this.secondPass){
16777 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16778 this.secondPass = true;
16779 this.update.defer(10, this, [date]);
16786 findCell : function(dt) {
16787 dt = dt.clearTime().getTime();
16789 this.cells.each(function(c){
16790 //Roo.log("check " +c.dateValue + '?=' + dt);
16791 if(c.dateValue == dt){
16801 findCells : function(ev) {
16802 var s = ev.start.clone().clearTime().getTime();
16804 var e= ev.end.clone().clearTime().getTime();
16807 this.cells.each(function(c){
16808 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16810 if(c.dateValue > e){
16813 if(c.dateValue < s){
16822 // findBestRow: function(cells)
16826 // for (var i =0 ; i < cells.length;i++) {
16827 // ret = Math.max(cells[i].rows || 0,ret);
16834 addItem : function(ev)
16836 // look for vertical location slot in
16837 var cells = this.findCells(ev);
16839 // ev.row = this.findBestRow(cells);
16841 // work out the location.
16845 for(var i =0; i < cells.length; i++) {
16847 cells[i].row = cells[0].row;
16850 cells[i].row = cells[i].row + 1;
16860 if (crow.start.getY() == cells[i].getY()) {
16862 crow.end = cells[i];
16879 cells[0].events.push(ev);
16881 this.calevents.push(ev);
16884 clearEvents: function() {
16886 if(!this.calevents){
16890 Roo.each(this.cells.elements, function(c){
16896 Roo.each(this.calevents, function(e) {
16897 Roo.each(e.els, function(el) {
16898 el.un('mouseenter' ,this.onEventEnter, this);
16899 el.un('mouseleave' ,this.onEventLeave, this);
16904 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16910 renderEvents: function()
16914 this.cells.each(function(c) {
16923 if(c.row != c.events.length){
16924 r = 4 - (4 - (c.row - c.events.length));
16927 c.events = ev.slice(0, r);
16928 c.more = ev.slice(r);
16930 if(c.more.length && c.more.length == 1){
16931 c.events.push(c.more.pop());
16934 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16938 this.cells.each(function(c) {
16940 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16943 for (var e = 0; e < c.events.length; e++){
16944 var ev = c.events[e];
16945 var rows = ev.rows;
16947 for(var i = 0; i < rows.length; i++) {
16949 // how many rows should it span..
16952 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16953 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16955 unselectable : "on",
16958 cls: 'fc-event-inner',
16962 // cls: 'fc-event-time',
16963 // html : cells.length > 1 ? '' : ev.time
16967 cls: 'fc-event-title',
16968 html : String.format('{0}', ev.title)
16975 cls: 'ui-resizable-handle ui-resizable-e',
16976 html : '  '
16983 cfg.cls += ' fc-event-start';
16985 if ((i+1) == rows.length) {
16986 cfg.cls += ' fc-event-end';
16989 var ctr = _this.el.select('.fc-event-container',true).first();
16990 var cg = ctr.createChild(cfg);
16992 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16993 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16995 var r = (c.more.length) ? 1 : 0;
16996 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16997 cg.setWidth(ebox.right - sbox.x -2);
16999 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17000 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17001 cg.on('click', _this.onEventClick, _this, ev);
17012 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17013 style : 'position: absolute',
17014 unselectable : "on",
17017 cls: 'fc-event-inner',
17021 cls: 'fc-event-title',
17029 cls: 'ui-resizable-handle ui-resizable-e',
17030 html : '  '
17036 var ctr = _this.el.select('.fc-event-container',true).first();
17037 var cg = ctr.createChild(cfg);
17039 var sbox = c.select('.fc-day-content',true).first().getBox();
17040 var ebox = c.select('.fc-day-content',true).first().getBox();
17042 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17043 cg.setWidth(ebox.right - sbox.x -2);
17045 cg.on('click', _this.onMoreEventClick, _this, c.more);
17055 onEventEnter: function (e, el,event,d) {
17056 this.fireEvent('evententer', this, el, event);
17059 onEventLeave: function (e, el,event,d) {
17060 this.fireEvent('eventleave', this, el, event);
17063 onEventClick: function (e, el,event,d) {
17064 this.fireEvent('eventclick', this, el, event);
17067 onMonthChange: function () {
17071 onMoreEventClick: function(e, el, more)
17075 this.calpopover.placement = 'right';
17076 this.calpopover.setTitle('More');
17078 this.calpopover.setContent('');
17080 var ctr = this.calpopover.el.select('.popover-content', true).first();
17082 Roo.each(more, function(m){
17084 cls : 'fc-event-hori fc-event-draggable',
17087 var cg = ctr.createChild(cfg);
17089 cg.on('click', _this.onEventClick, _this, m);
17092 this.calpopover.show(el);
17097 onLoad: function ()
17099 this.calevents = [];
17102 if(this.store.getCount() > 0){
17103 this.store.data.each(function(d){
17106 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17107 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17108 time : d.data.start_time,
17109 title : d.data.title,
17110 description : d.data.description,
17111 venue : d.data.venue
17116 this.renderEvents();
17118 if(this.calevents.length && this.loadMask){
17119 this.maskEl.hide();
17123 onBeforeLoad: function()
17125 this.clearEvents();
17127 this.maskEl.show();
17141 * @class Roo.bootstrap.Popover
17142 * @extends Roo.bootstrap.Component
17143 * Bootstrap Popover class
17144 * @cfg {String} html contents of the popover (or false to use children..)
17145 * @cfg {String} title of popover (or false to hide)
17146 * @cfg {String} placement how it is placed
17147 * @cfg {String} trigger click || hover (or false to trigger manually)
17148 * @cfg {String} over what (parent or false to trigger manually.)
17149 * @cfg {Number} delay - delay before showing
17152 * Create a new Popover
17153 * @param {Object} config The config object
17156 Roo.bootstrap.Popover = function(config){
17157 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17163 * After the popover show
17165 * @param {Roo.bootstrap.Popover} this
17170 * After the popover hide
17172 * @param {Roo.bootstrap.Popover} this
17178 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17180 title: 'Fill in a title',
17183 placement : 'right',
17184 trigger : 'hover', // hover
17190 can_build_overlaid : false,
17192 getChildContainer : function()
17194 return this.el.select('.popover-content',true).first();
17197 getAutoCreate : function(){
17200 cls : 'popover roo-dynamic',
17201 style: 'display:block',
17207 cls : 'popover-inner',
17211 cls: 'popover-title',
17215 cls : 'popover-content',
17226 setTitle: function(str)
17229 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17231 setContent: function(str)
17234 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17236 // as it get's added to the bottom of the page.
17237 onRender : function(ct, position)
17239 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17241 var cfg = Roo.apply({}, this.getAutoCreate());
17245 cfg.cls += ' ' + this.cls;
17248 cfg.style = this.style;
17250 //Roo.log("adding to ");
17251 this.el = Roo.get(document.body).createChild(cfg, position);
17252 // Roo.log(this.el);
17257 initEvents : function()
17259 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17260 this.el.enableDisplayMode('block');
17262 if (this.over === false) {
17265 if (this.triggers === false) {
17268 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17269 var triggers = this.trigger ? this.trigger.split(' ') : [];
17270 Roo.each(triggers, function(trigger) {
17272 if (trigger == 'click') {
17273 on_el.on('click', this.toggle, this);
17274 } else if (trigger != 'manual') {
17275 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17276 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17278 on_el.on(eventIn ,this.enter, this);
17279 on_el.on(eventOut, this.leave, this);
17290 toggle : function () {
17291 this.hoverState == 'in' ? this.leave() : this.enter();
17294 enter : function () {
17296 clearTimeout(this.timeout);
17298 this.hoverState = 'in';
17300 if (!this.delay || !this.delay.show) {
17305 this.timeout = setTimeout(function () {
17306 if (_t.hoverState == 'in') {
17309 }, this.delay.show)
17312 leave : function() {
17313 clearTimeout(this.timeout);
17315 this.hoverState = 'out';
17317 if (!this.delay || !this.delay.hide) {
17322 this.timeout = setTimeout(function () {
17323 if (_t.hoverState == 'out') {
17326 }, this.delay.hide)
17329 show : function (on_el)
17332 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17336 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17337 if (this.html !== false) {
17338 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17340 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17341 if (!this.title.length) {
17342 this.el.select('.popover-title',true).hide();
17345 var placement = typeof this.placement == 'function' ?
17346 this.placement.call(this, this.el, on_el) :
17349 var autoToken = /\s?auto?\s?/i;
17350 var autoPlace = autoToken.test(placement);
17352 placement = placement.replace(autoToken, '') || 'top';
17356 //this.el.setXY([0,0]);
17358 this.el.dom.style.display='block';
17359 this.el.addClass(placement);
17361 //this.el.appendTo(on_el);
17363 var p = this.getPosition();
17364 var box = this.el.getBox();
17369 var align = Roo.bootstrap.Popover.alignment[placement];
17372 this.el.alignTo(on_el, align[0],align[1]);
17373 //var arrow = this.el.select('.arrow',true).first();
17374 //arrow.set(align[2],
17376 this.el.addClass('in');
17379 if (this.el.hasClass('fade')) {
17383 this.hoverState = 'in';
17385 this.fireEvent('show', this);
17390 this.el.setXY([0,0]);
17391 this.el.removeClass('in');
17393 this.hoverState = null;
17395 this.fireEvent('hide', this);
17400 Roo.bootstrap.Popover.alignment = {
17401 'left' : ['r-l', [-10,0], 'right'],
17402 'right' : ['l-r', [10,0], 'left'],
17403 'bottom' : ['t-b', [0,10], 'top'],
17404 'top' : [ 'b-t', [0,-10], 'bottom']
17415 * @class Roo.bootstrap.Progress
17416 * @extends Roo.bootstrap.Component
17417 * Bootstrap Progress class
17418 * @cfg {Boolean} striped striped of the progress bar
17419 * @cfg {Boolean} active animated of the progress bar
17423 * Create a new Progress
17424 * @param {Object} config The config object
17427 Roo.bootstrap.Progress = function(config){
17428 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17431 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17436 getAutoCreate : function(){
17444 cfg.cls += ' progress-striped';
17448 cfg.cls += ' active';
17467 * @class Roo.bootstrap.ProgressBar
17468 * @extends Roo.bootstrap.Component
17469 * Bootstrap ProgressBar class
17470 * @cfg {Number} aria_valuenow aria-value now
17471 * @cfg {Number} aria_valuemin aria-value min
17472 * @cfg {Number} aria_valuemax aria-value max
17473 * @cfg {String} label label for the progress bar
17474 * @cfg {String} panel (success | info | warning | danger )
17475 * @cfg {String} role role of the progress bar
17476 * @cfg {String} sr_only text
17480 * Create a new ProgressBar
17481 * @param {Object} config The config object
17484 Roo.bootstrap.ProgressBar = function(config){
17485 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17488 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17492 aria_valuemax : 100,
17498 getAutoCreate : function()
17503 cls: 'progress-bar',
17504 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17516 cfg.role = this.role;
17519 if(this.aria_valuenow){
17520 cfg['aria-valuenow'] = this.aria_valuenow;
17523 if(this.aria_valuemin){
17524 cfg['aria-valuemin'] = this.aria_valuemin;
17527 if(this.aria_valuemax){
17528 cfg['aria-valuemax'] = this.aria_valuemax;
17531 if(this.label && !this.sr_only){
17532 cfg.html = this.label;
17536 cfg.cls += ' progress-bar-' + this.panel;
17542 update : function(aria_valuenow)
17544 this.aria_valuenow = aria_valuenow;
17546 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17561 * @class Roo.bootstrap.TabGroup
17562 * @extends Roo.bootstrap.Column
17563 * Bootstrap Column class
17564 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17565 * @cfg {Boolean} carousel true to make the group behave like a carousel
17566 * @cfg {Boolean} bullets show bullets for the panels
17567 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17568 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17569 * @cfg {Boolean} showarrow (true|false) show arrow default true
17572 * Create a new TabGroup
17573 * @param {Object} config The config object
17576 Roo.bootstrap.TabGroup = function(config){
17577 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17579 this.navId = Roo.id();
17582 Roo.bootstrap.TabGroup.register(this);
17586 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17589 transition : false,
17594 slideOnTouch : false,
17597 getAutoCreate : function()
17599 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17601 cfg.cls += ' tab-content';
17603 if (this.carousel) {
17604 cfg.cls += ' carousel slide';
17607 cls : 'carousel-inner',
17611 if(this.bullets && !Roo.isTouch){
17614 cls : 'carousel-bullets',
17618 if(this.bullets_cls){
17619 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17626 cfg.cn[0].cn.push(bullets);
17629 if(this.showarrow){
17630 cfg.cn[0].cn.push({
17632 class : 'carousel-arrow',
17636 class : 'carousel-prev',
17640 class : 'fa fa-chevron-left'
17646 class : 'carousel-next',
17650 class : 'fa fa-chevron-right'
17663 initEvents: function()
17665 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17666 // this.el.on("touchstart", this.onTouchStart, this);
17669 if(this.autoslide){
17672 this.slideFn = window.setInterval(function() {
17673 _this.showPanelNext();
17677 if(this.showarrow){
17678 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17679 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17685 // onTouchStart : function(e, el, o)
17687 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17691 // this.showPanelNext();
17695 getChildContainer : function()
17697 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17701 * register a Navigation item
17702 * @param {Roo.bootstrap.NavItem} the navitem to add
17704 register : function(item)
17706 this.tabs.push( item);
17707 item.navId = this.navId; // not really needed..
17712 getActivePanel : function()
17715 Roo.each(this.tabs, function(t) {
17725 getPanelByName : function(n)
17728 Roo.each(this.tabs, function(t) {
17729 if (t.tabId == n) {
17737 indexOfPanel : function(p)
17740 Roo.each(this.tabs, function(t,i) {
17741 if (t.tabId == p.tabId) {
17750 * show a specific panel
17751 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17752 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17754 showPanel : function (pan)
17756 if(this.transition || typeof(pan) == 'undefined'){
17757 Roo.log("waiting for the transitionend");
17761 if (typeof(pan) == 'number') {
17762 pan = this.tabs[pan];
17765 if (typeof(pan) == 'string') {
17766 pan = this.getPanelByName(pan);
17769 var cur = this.getActivePanel();
17772 Roo.log('pan or acitve pan is undefined');
17776 if (pan.tabId == this.getActivePanel().tabId) {
17780 if (false === cur.fireEvent('beforedeactivate')) {
17784 if(this.bullets > 0 && !Roo.isTouch){
17785 this.setActiveBullet(this.indexOfPanel(pan));
17788 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17790 this.transition = true;
17791 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17792 var lr = dir == 'next' ? 'left' : 'right';
17793 pan.el.addClass(dir); // or prev
17794 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17795 cur.el.addClass(lr); // or right
17796 pan.el.addClass(lr);
17799 cur.el.on('transitionend', function() {
17800 Roo.log("trans end?");
17802 pan.el.removeClass([lr,dir]);
17803 pan.setActive(true);
17805 cur.el.removeClass([lr]);
17806 cur.setActive(false);
17808 _this.transition = false;
17810 }, this, { single: true } );
17815 cur.setActive(false);
17816 pan.setActive(true);
17821 showPanelNext : function()
17823 var i = this.indexOfPanel(this.getActivePanel());
17825 if (i >= this.tabs.length - 1 && !this.autoslide) {
17829 if (i >= this.tabs.length - 1 && this.autoslide) {
17833 this.showPanel(this.tabs[i+1]);
17836 showPanelPrev : function()
17838 var i = this.indexOfPanel(this.getActivePanel());
17840 if (i < 1 && !this.autoslide) {
17844 if (i < 1 && this.autoslide) {
17845 i = this.tabs.length;
17848 this.showPanel(this.tabs[i-1]);
17852 addBullet: function()
17854 if(!this.bullets || Roo.isTouch){
17857 var ctr = this.el.select('.carousel-bullets',true).first();
17858 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17859 var bullet = ctr.createChild({
17860 cls : 'bullet bullet-' + i
17861 },ctr.dom.lastChild);
17866 bullet.on('click', (function(e, el, o, ii, t){
17868 e.preventDefault();
17870 this.showPanel(ii);
17872 if(this.autoslide && this.slideFn){
17873 clearInterval(this.slideFn);
17874 this.slideFn = window.setInterval(function() {
17875 _this.showPanelNext();
17879 }).createDelegate(this, [i, bullet], true));
17884 setActiveBullet : function(i)
17890 Roo.each(this.el.select('.bullet', true).elements, function(el){
17891 el.removeClass('selected');
17894 var bullet = this.el.select('.bullet-' + i, true).first();
17900 bullet.addClass('selected');
17911 Roo.apply(Roo.bootstrap.TabGroup, {
17915 * register a Navigation Group
17916 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17918 register : function(navgrp)
17920 this.groups[navgrp.navId] = navgrp;
17924 * fetch a Navigation Group based on the navigation ID
17925 * if one does not exist , it will get created.
17926 * @param {string} the navgroup to add
17927 * @returns {Roo.bootstrap.NavGroup} the navgroup
17929 get: function(navId) {
17930 if (typeof(this.groups[navId]) == 'undefined') {
17931 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17933 return this.groups[navId] ;
17948 * @class Roo.bootstrap.TabPanel
17949 * @extends Roo.bootstrap.Component
17950 * Bootstrap TabPanel class
17951 * @cfg {Boolean} active panel active
17952 * @cfg {String} html panel content
17953 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17954 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17955 * @cfg {String} href click to link..
17959 * Create a new TabPanel
17960 * @param {Object} config The config object
17963 Roo.bootstrap.TabPanel = function(config){
17964 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17968 * Fires when the active status changes
17969 * @param {Roo.bootstrap.TabPanel} this
17970 * @param {Boolean} state the new state
17975 * @event beforedeactivate
17976 * Fires before a tab is de-activated - can be used to do validation on a form.
17977 * @param {Roo.bootstrap.TabPanel} this
17978 * @return {Boolean} false if there is an error
17981 'beforedeactivate': true
17984 this.tabId = this.tabId || Roo.id();
17988 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17996 getAutoCreate : function(){
17999 // item is needed for carousel - not sure if it has any effect otherwise
18000 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18001 html: this.html || ''
18005 cfg.cls += ' active';
18009 cfg.tabId = this.tabId;
18016 initEvents: function()
18018 var p = this.parent();
18020 this.navId = this.navId || p.navId;
18022 if (typeof(this.navId) != 'undefined') {
18023 // not really needed.. but just in case.. parent should be a NavGroup.
18024 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18028 var i = tg.tabs.length - 1;
18030 if(this.active && tg.bullets > 0 && i < tg.bullets){
18031 tg.setActiveBullet(i);
18035 this.el.on('click', this.onClick, this);
18038 this.el.on("touchstart", this.onTouchStart, this);
18039 this.el.on("touchmove", this.onTouchMove, this);
18040 this.el.on("touchend", this.onTouchEnd, this);
18045 onRender : function(ct, position)
18047 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18050 setActive : function(state)
18052 Roo.log("panel - set active " + this.tabId + "=" + state);
18054 this.active = state;
18056 this.el.removeClass('active');
18058 } else if (!this.el.hasClass('active')) {
18059 this.el.addClass('active');
18062 this.fireEvent('changed', this, state);
18065 onClick : function(e)
18067 e.preventDefault();
18069 if(!this.href.length){
18073 window.location.href = this.href;
18082 onTouchStart : function(e)
18084 this.swiping = false;
18086 this.startX = e.browserEvent.touches[0].clientX;
18087 this.startY = e.browserEvent.touches[0].clientY;
18090 onTouchMove : function(e)
18092 this.swiping = true;
18094 this.endX = e.browserEvent.touches[0].clientX;
18095 this.endY = e.browserEvent.touches[0].clientY;
18098 onTouchEnd : function(e)
18105 var tabGroup = this.parent();
18107 if(this.endX > this.startX){ // swiping right
18108 tabGroup.showPanelPrev();
18112 if(this.startX > this.endX){ // swiping left
18113 tabGroup.showPanelNext();
18132 * @class Roo.bootstrap.DateField
18133 * @extends Roo.bootstrap.Input
18134 * Bootstrap DateField class
18135 * @cfg {Number} weekStart default 0
18136 * @cfg {String} viewMode default empty, (months|years)
18137 * @cfg {String} minViewMode default empty, (months|years)
18138 * @cfg {Number} startDate default -Infinity
18139 * @cfg {Number} endDate default Infinity
18140 * @cfg {Boolean} todayHighlight default false
18141 * @cfg {Boolean} todayBtn default false
18142 * @cfg {Boolean} calendarWeeks default false
18143 * @cfg {Object} daysOfWeekDisabled default empty
18144 * @cfg {Boolean} singleMode default false (true | false)
18146 * @cfg {Boolean} keyboardNavigation default true
18147 * @cfg {String} language default en
18150 * Create a new DateField
18151 * @param {Object} config The config object
18154 Roo.bootstrap.DateField = function(config){
18155 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18159 * Fires when this field show.
18160 * @param {Roo.bootstrap.DateField} this
18161 * @param {Mixed} date The date value
18166 * Fires when this field hide.
18167 * @param {Roo.bootstrap.DateField} this
18168 * @param {Mixed} date The date value
18173 * Fires when select a date.
18174 * @param {Roo.bootstrap.DateField} this
18175 * @param {Mixed} date The date value
18179 * @event beforeselect
18180 * Fires when before select a date.
18181 * @param {Roo.bootstrap.DateField} this
18182 * @param {Mixed} date The date value
18184 beforeselect : true
18188 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18191 * @cfg {String} format
18192 * The default date format string which can be overriden for localization support. The format must be
18193 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18197 * @cfg {String} altFormats
18198 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18199 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18201 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18209 todayHighlight : false,
18215 keyboardNavigation: true,
18217 calendarWeeks: false,
18219 startDate: -Infinity,
18223 daysOfWeekDisabled: [],
18227 singleMode : false,
18229 UTCDate: function()
18231 return new Date(Date.UTC.apply(Date, arguments));
18234 UTCToday: function()
18236 var today = new Date();
18237 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18240 getDate: function() {
18241 var d = this.getUTCDate();
18242 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18245 getUTCDate: function() {
18249 setDate: function(d) {
18250 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18253 setUTCDate: function(d) {
18255 this.setValue(this.formatDate(this.date));
18258 onRender: function(ct, position)
18261 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18263 this.language = this.language || 'en';
18264 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18265 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18267 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18268 this.format = this.format || 'm/d/y';
18269 this.isInline = false;
18270 this.isInput = true;
18271 this.component = this.el.select('.add-on', true).first() || false;
18272 this.component = (this.component && this.component.length === 0) ? false : this.component;
18273 this.hasInput = this.component && this.inputEl().length;
18275 if (typeof(this.minViewMode === 'string')) {
18276 switch (this.minViewMode) {
18278 this.minViewMode = 1;
18281 this.minViewMode = 2;
18284 this.minViewMode = 0;
18289 if (typeof(this.viewMode === 'string')) {
18290 switch (this.viewMode) {
18303 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18305 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18307 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18309 this.picker().on('mousedown', this.onMousedown, this);
18310 this.picker().on('click', this.onClick, this);
18312 this.picker().addClass('datepicker-dropdown');
18314 this.startViewMode = this.viewMode;
18316 if(this.singleMode){
18317 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18318 v.setVisibilityMode(Roo.Element.DISPLAY);
18322 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18323 v.setStyle('width', '189px');
18327 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18328 if(!this.calendarWeeks){
18333 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18334 v.attr('colspan', function(i, val){
18335 return parseInt(val) + 1;
18340 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18342 this.setStartDate(this.startDate);
18343 this.setEndDate(this.endDate);
18345 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18352 if(this.isInline) {
18357 picker : function()
18359 return this.pickerEl;
18360 // return this.el.select('.datepicker', true).first();
18363 fillDow: function()
18365 var dowCnt = this.weekStart;
18374 if(this.calendarWeeks){
18382 while (dowCnt < this.weekStart + 7) {
18386 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18390 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18393 fillMonths: function()
18396 var months = this.picker().select('>.datepicker-months td', true).first();
18398 months.dom.innerHTML = '';
18404 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18407 months.createChild(month);
18414 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;
18416 if (this.date < this.startDate) {
18417 this.viewDate = new Date(this.startDate);
18418 } else if (this.date > this.endDate) {
18419 this.viewDate = new Date(this.endDate);
18421 this.viewDate = new Date(this.date);
18429 var d = new Date(this.viewDate),
18430 year = d.getUTCFullYear(),
18431 month = d.getUTCMonth(),
18432 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18433 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18434 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18435 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18436 currentDate = this.date && this.date.valueOf(),
18437 today = this.UTCToday();
18439 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18441 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18443 // this.picker.select('>tfoot th.today').
18444 // .text(dates[this.language].today)
18445 // .toggle(this.todayBtn !== false);
18447 this.updateNavArrows();
18450 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18452 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18454 prevMonth.setUTCDate(day);
18456 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18458 var nextMonth = new Date(prevMonth);
18460 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18462 nextMonth = nextMonth.valueOf();
18464 var fillMonths = false;
18466 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18468 while(prevMonth.valueOf() < nextMonth) {
18471 if (prevMonth.getUTCDay() === this.weekStart) {
18473 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18481 if(this.calendarWeeks){
18482 // ISO 8601: First week contains first thursday.
18483 // ISO also states week starts on Monday, but we can be more abstract here.
18485 // Start of current week: based on weekstart/current date
18486 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18487 // Thursday of this week
18488 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18489 // First Thursday of year, year from thursday
18490 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18491 // Calendar week: ms between thursdays, div ms per day, div 7 days
18492 calWeek = (th - yth) / 864e5 / 7 + 1;
18494 fillMonths.cn.push({
18502 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18504 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18507 if (this.todayHighlight &&
18508 prevMonth.getUTCFullYear() == today.getFullYear() &&
18509 prevMonth.getUTCMonth() == today.getMonth() &&
18510 prevMonth.getUTCDate() == today.getDate()) {
18511 clsName += ' today';
18514 if (currentDate && prevMonth.valueOf() === currentDate) {
18515 clsName += ' active';
18518 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18519 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18520 clsName += ' disabled';
18523 fillMonths.cn.push({
18525 cls: 'day ' + clsName,
18526 html: prevMonth.getDate()
18529 prevMonth.setDate(prevMonth.getDate()+1);
18532 var currentYear = this.date && this.date.getUTCFullYear();
18533 var currentMonth = this.date && this.date.getUTCMonth();
18535 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18537 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18538 v.removeClass('active');
18540 if(currentYear === year && k === currentMonth){
18541 v.addClass('active');
18544 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18545 v.addClass('disabled');
18551 year = parseInt(year/10, 10) * 10;
18553 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18555 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18558 for (var i = -1; i < 11; i++) {
18559 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18561 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18569 showMode: function(dir)
18572 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18575 Roo.each(this.picker().select('>div',true).elements, function(v){
18576 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18579 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18584 if(this.isInline) {
18588 this.picker().removeClass(['bottom', 'top']);
18590 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18592 * place to the top of element!
18596 this.picker().addClass('top');
18597 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18602 this.picker().addClass('bottom');
18604 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18607 parseDate : function(value)
18609 if(!value || value instanceof Date){
18612 var v = Date.parseDate(value, this.format);
18613 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18614 v = Date.parseDate(value, 'Y-m-d');
18616 if(!v && this.altFormats){
18617 if(!this.altFormatsArray){
18618 this.altFormatsArray = this.altFormats.split("|");
18620 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18621 v = Date.parseDate(value, this.altFormatsArray[i]);
18627 formatDate : function(date, fmt)
18629 return (!date || !(date instanceof Date)) ?
18630 date : date.dateFormat(fmt || this.format);
18633 onFocus : function()
18635 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18639 onBlur : function()
18641 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18643 var d = this.inputEl().getValue();
18652 this.picker().show();
18656 this.fireEvent('show', this, this.date);
18661 if(this.isInline) {
18664 this.picker().hide();
18665 this.viewMode = this.startViewMode;
18668 this.fireEvent('hide', this, this.date);
18672 onMousedown: function(e)
18674 e.stopPropagation();
18675 e.preventDefault();
18680 Roo.bootstrap.DateField.superclass.keyup.call(this);
18684 setValue: function(v)
18686 if(this.fireEvent('beforeselect', this, v) !== false){
18687 var d = new Date(this.parseDate(v) ).clearTime();
18689 if(isNaN(d.getTime())){
18690 this.date = this.viewDate = '';
18691 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18695 v = this.formatDate(d);
18697 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18699 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18703 this.fireEvent('select', this, this.date);
18707 getValue: function()
18709 return this.formatDate(this.date);
18712 fireKey: function(e)
18714 if (!this.picker().isVisible()){
18715 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18721 var dateChanged = false,
18723 newDate, newViewDate;
18728 e.preventDefault();
18732 if (!this.keyboardNavigation) {
18735 dir = e.keyCode == 37 ? -1 : 1;
18738 newDate = this.moveYear(this.date, dir);
18739 newViewDate = this.moveYear(this.viewDate, dir);
18740 } else if (e.shiftKey){
18741 newDate = this.moveMonth(this.date, dir);
18742 newViewDate = this.moveMonth(this.viewDate, dir);
18744 newDate = new Date(this.date);
18745 newDate.setUTCDate(this.date.getUTCDate() + dir);
18746 newViewDate = new Date(this.viewDate);
18747 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18749 if (this.dateWithinRange(newDate)){
18750 this.date = newDate;
18751 this.viewDate = newViewDate;
18752 this.setValue(this.formatDate(this.date));
18754 e.preventDefault();
18755 dateChanged = true;
18760 if (!this.keyboardNavigation) {
18763 dir = e.keyCode == 38 ? -1 : 1;
18765 newDate = this.moveYear(this.date, dir);
18766 newViewDate = this.moveYear(this.viewDate, dir);
18767 } else if (e.shiftKey){
18768 newDate = this.moveMonth(this.date, dir);
18769 newViewDate = this.moveMonth(this.viewDate, dir);
18771 newDate = new Date(this.date);
18772 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18773 newViewDate = new Date(this.viewDate);
18774 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18776 if (this.dateWithinRange(newDate)){
18777 this.date = newDate;
18778 this.viewDate = newViewDate;
18779 this.setValue(this.formatDate(this.date));
18781 e.preventDefault();
18782 dateChanged = true;
18786 this.setValue(this.formatDate(this.date));
18788 e.preventDefault();
18791 this.setValue(this.formatDate(this.date));
18805 onClick: function(e)
18807 e.stopPropagation();
18808 e.preventDefault();
18810 var target = e.getTarget();
18812 if(target.nodeName.toLowerCase() === 'i'){
18813 target = Roo.get(target).dom.parentNode;
18816 var nodeName = target.nodeName;
18817 var className = target.className;
18818 var html = target.innerHTML;
18819 //Roo.log(nodeName);
18821 switch(nodeName.toLowerCase()) {
18823 switch(className) {
18829 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18830 switch(this.viewMode){
18832 this.viewDate = this.moveMonth(this.viewDate, dir);
18836 this.viewDate = this.moveYear(this.viewDate, dir);
18842 var date = new Date();
18843 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18845 this.setValue(this.formatDate(this.date));
18852 if (className.indexOf('disabled') < 0) {
18853 this.viewDate.setUTCDate(1);
18854 if (className.indexOf('month') > -1) {
18855 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18857 var year = parseInt(html, 10) || 0;
18858 this.viewDate.setUTCFullYear(year);
18862 if(this.singleMode){
18863 this.setValue(this.formatDate(this.viewDate));
18874 //Roo.log(className);
18875 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18876 var day = parseInt(html, 10) || 1;
18877 var year = this.viewDate.getUTCFullYear(),
18878 month = this.viewDate.getUTCMonth();
18880 if (className.indexOf('old') > -1) {
18887 } else if (className.indexOf('new') > -1) {
18895 //Roo.log([year,month,day]);
18896 this.date = this.UTCDate(year, month, day,0,0,0,0);
18897 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18899 //Roo.log(this.formatDate(this.date));
18900 this.setValue(this.formatDate(this.date));
18907 setStartDate: function(startDate)
18909 this.startDate = startDate || -Infinity;
18910 if (this.startDate !== -Infinity) {
18911 this.startDate = this.parseDate(this.startDate);
18914 this.updateNavArrows();
18917 setEndDate: function(endDate)
18919 this.endDate = endDate || Infinity;
18920 if (this.endDate !== Infinity) {
18921 this.endDate = this.parseDate(this.endDate);
18924 this.updateNavArrows();
18927 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18929 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18930 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18931 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18933 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18934 return parseInt(d, 10);
18937 this.updateNavArrows();
18940 updateNavArrows: function()
18942 if(this.singleMode){
18946 var d = new Date(this.viewDate),
18947 year = d.getUTCFullYear(),
18948 month = d.getUTCMonth();
18950 Roo.each(this.picker().select('.prev', true).elements, function(v){
18952 switch (this.viewMode) {
18955 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18961 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18968 Roo.each(this.picker().select('.next', true).elements, function(v){
18970 switch (this.viewMode) {
18973 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18979 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18987 moveMonth: function(date, dir)
18992 var new_date = new Date(date.valueOf()),
18993 day = new_date.getUTCDate(),
18994 month = new_date.getUTCMonth(),
18995 mag = Math.abs(dir),
18997 dir = dir > 0 ? 1 : -1;
19000 // If going back one month, make sure month is not current month
19001 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19003 return new_date.getUTCMonth() == month;
19005 // If going forward one month, make sure month is as expected
19006 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19008 return new_date.getUTCMonth() != new_month;
19010 new_month = month + dir;
19011 new_date.setUTCMonth(new_month);
19012 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19013 if (new_month < 0 || new_month > 11) {
19014 new_month = (new_month + 12) % 12;
19017 // For magnitudes >1, move one month at a time...
19018 for (var i=0; i<mag; i++) {
19019 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19020 new_date = this.moveMonth(new_date, dir);
19022 // ...then reset the day, keeping it in the new month
19023 new_month = new_date.getUTCMonth();
19024 new_date.setUTCDate(day);
19026 return new_month != new_date.getUTCMonth();
19029 // Common date-resetting loop -- if date is beyond end of month, make it
19032 new_date.setUTCDate(--day);
19033 new_date.setUTCMonth(new_month);
19038 moveYear: function(date, dir)
19040 return this.moveMonth(date, dir*12);
19043 dateWithinRange: function(date)
19045 return date >= this.startDate && date <= this.endDate;
19051 this.picker().remove();
19054 validateValue : function(value)
19056 if(value.length < 1) {
19057 if(this.allowBlank){
19063 if(value.length < this.minLength){
19066 if(value.length > this.maxLength){
19070 var vt = Roo.form.VTypes;
19071 if(!vt[this.vtype](value, this)){
19075 if(typeof this.validator == "function"){
19076 var msg = this.validator(value);
19082 if(this.regex && !this.regex.test(value)){
19086 if(typeof(this.parseDate(value)) == 'undefined'){
19090 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19094 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19104 Roo.apply(Roo.bootstrap.DateField, {
19115 html: '<i class="fa fa-arrow-left"/>'
19125 html: '<i class="fa fa-arrow-right"/>'
19167 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19168 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19169 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19170 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19171 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19184 navFnc: 'FullYear',
19189 navFnc: 'FullYear',
19194 Roo.apply(Roo.bootstrap.DateField, {
19198 cls: 'datepicker dropdown-menu roo-dynamic',
19202 cls: 'datepicker-days',
19206 cls: 'table-condensed',
19208 Roo.bootstrap.DateField.head,
19212 Roo.bootstrap.DateField.footer
19219 cls: 'datepicker-months',
19223 cls: 'table-condensed',
19225 Roo.bootstrap.DateField.head,
19226 Roo.bootstrap.DateField.content,
19227 Roo.bootstrap.DateField.footer
19234 cls: 'datepicker-years',
19238 cls: 'table-condensed',
19240 Roo.bootstrap.DateField.head,
19241 Roo.bootstrap.DateField.content,
19242 Roo.bootstrap.DateField.footer
19261 * @class Roo.bootstrap.TimeField
19262 * @extends Roo.bootstrap.Input
19263 * Bootstrap DateField class
19267 * Create a new TimeField
19268 * @param {Object} config The config object
19271 Roo.bootstrap.TimeField = function(config){
19272 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19276 * Fires when this field show.
19277 * @param {Roo.bootstrap.DateField} thisthis
19278 * @param {Mixed} date The date value
19283 * Fires when this field hide.
19284 * @param {Roo.bootstrap.DateField} this
19285 * @param {Mixed} date The date value
19290 * Fires when select a date.
19291 * @param {Roo.bootstrap.DateField} this
19292 * @param {Mixed} date The date value
19298 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19301 * @cfg {String} format
19302 * The default time format string which can be overriden for localization support. The format must be
19303 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19307 onRender: function(ct, position)
19310 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19312 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19314 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19316 this.pop = this.picker().select('>.datepicker-time',true).first();
19317 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19319 this.picker().on('mousedown', this.onMousedown, this);
19320 this.picker().on('click', this.onClick, this);
19322 this.picker().addClass('datepicker-dropdown');
19327 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19328 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19329 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19330 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19331 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19332 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19336 fireKey: function(e){
19337 if (!this.picker().isVisible()){
19338 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19344 e.preventDefault();
19352 this.onTogglePeriod();
19355 this.onIncrementMinutes();
19358 this.onDecrementMinutes();
19367 onClick: function(e) {
19368 e.stopPropagation();
19369 e.preventDefault();
19372 picker : function()
19374 return this.el.select('.datepicker', true).first();
19377 fillTime: function()
19379 var time = this.pop.select('tbody', true).first();
19381 time.dom.innerHTML = '';
19396 cls: 'hours-up glyphicon glyphicon-chevron-up'
19416 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19437 cls: 'timepicker-hour',
19452 cls: 'timepicker-minute',
19467 cls: 'btn btn-primary period',
19489 cls: 'hours-down glyphicon glyphicon-chevron-down'
19509 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19527 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19534 var hours = this.time.getHours();
19535 var minutes = this.time.getMinutes();
19548 hours = hours - 12;
19552 hours = '0' + hours;
19556 minutes = '0' + minutes;
19559 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19560 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19561 this.pop.select('button', true).first().dom.innerHTML = period;
19567 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19569 var cls = ['bottom'];
19571 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19578 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19583 this.picker().addClass(cls.join('-'));
19587 Roo.each(cls, function(c){
19589 _this.picker().setTop(_this.inputEl().getHeight());
19593 _this.picker().setTop(0 - _this.picker().getHeight());
19598 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19602 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19609 onFocus : function()
19611 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19615 onBlur : function()
19617 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19623 this.picker().show();
19628 this.fireEvent('show', this, this.date);
19633 this.picker().hide();
19636 this.fireEvent('hide', this, this.date);
19639 setTime : function()
19642 this.setValue(this.time.format(this.format));
19644 this.fireEvent('select', this, this.date);
19649 onMousedown: function(e){
19650 e.stopPropagation();
19651 e.preventDefault();
19654 onIncrementHours: function()
19656 Roo.log('onIncrementHours');
19657 this.time = this.time.add(Date.HOUR, 1);
19662 onDecrementHours: function()
19664 Roo.log('onDecrementHours');
19665 this.time = this.time.add(Date.HOUR, -1);
19669 onIncrementMinutes: function()
19671 Roo.log('onIncrementMinutes');
19672 this.time = this.time.add(Date.MINUTE, 1);
19676 onDecrementMinutes: function()
19678 Roo.log('onDecrementMinutes');
19679 this.time = this.time.add(Date.MINUTE, -1);
19683 onTogglePeriod: function()
19685 Roo.log('onTogglePeriod');
19686 this.time = this.time.add(Date.HOUR, 12);
19693 Roo.apply(Roo.bootstrap.TimeField, {
19723 cls: 'btn btn-info ok',
19735 Roo.apply(Roo.bootstrap.TimeField, {
19739 cls: 'datepicker dropdown-menu',
19743 cls: 'datepicker-time',
19747 cls: 'table-condensed',
19749 Roo.bootstrap.TimeField.content,
19750 Roo.bootstrap.TimeField.footer
19769 * @class Roo.bootstrap.MonthField
19770 * @extends Roo.bootstrap.Input
19771 * Bootstrap MonthField class
19773 * @cfg {String} language default en
19776 * Create a new MonthField
19777 * @param {Object} config The config object
19780 Roo.bootstrap.MonthField = function(config){
19781 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19786 * Fires when this field show.
19787 * @param {Roo.bootstrap.MonthField} this
19788 * @param {Mixed} date The date value
19793 * Fires when this field hide.
19794 * @param {Roo.bootstrap.MonthField} this
19795 * @param {Mixed} date The date value
19800 * Fires when select a date.
19801 * @param {Roo.bootstrap.MonthField} this
19802 * @param {String} oldvalue The old value
19803 * @param {String} newvalue The new value
19809 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19811 onRender: function(ct, position)
19814 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19816 this.language = this.language || 'en';
19817 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19818 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19820 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19821 this.isInline = false;
19822 this.isInput = true;
19823 this.component = this.el.select('.add-on', true).first() || false;
19824 this.component = (this.component && this.component.length === 0) ? false : this.component;
19825 this.hasInput = this.component && this.inputEL().length;
19827 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19829 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19831 this.picker().on('mousedown', this.onMousedown, this);
19832 this.picker().on('click', this.onClick, this);
19834 this.picker().addClass('datepicker-dropdown');
19836 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19837 v.setStyle('width', '189px');
19844 if(this.isInline) {
19850 setValue: function(v, suppressEvent)
19852 var o = this.getValue();
19854 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19858 if(suppressEvent !== true){
19859 this.fireEvent('select', this, o, v);
19864 getValue: function()
19869 onClick: function(e)
19871 e.stopPropagation();
19872 e.preventDefault();
19874 var target = e.getTarget();
19876 if(target.nodeName.toLowerCase() === 'i'){
19877 target = Roo.get(target).dom.parentNode;
19880 var nodeName = target.nodeName;
19881 var className = target.className;
19882 var html = target.innerHTML;
19884 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19888 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19890 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19896 picker : function()
19898 return this.pickerEl;
19901 fillMonths: function()
19904 var months = this.picker().select('>.datepicker-months td', true).first();
19906 months.dom.innerHTML = '';
19912 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19915 months.createChild(month);
19924 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19925 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19928 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19929 e.removeClass('active');
19931 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19932 e.addClass('active');
19939 if(this.isInline) {
19943 this.picker().removeClass(['bottom', 'top']);
19945 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19947 * place to the top of element!
19951 this.picker().addClass('top');
19952 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19957 this.picker().addClass('bottom');
19959 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19962 onFocus : function()
19964 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19968 onBlur : function()
19970 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19972 var d = this.inputEl().getValue();
19981 this.picker().show();
19982 this.picker().select('>.datepicker-months', true).first().show();
19986 this.fireEvent('show', this, this.date);
19991 if(this.isInline) {
19994 this.picker().hide();
19995 this.fireEvent('hide', this, this.date);
19999 onMousedown: function(e)
20001 e.stopPropagation();
20002 e.preventDefault();
20007 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20011 fireKey: function(e)
20013 if (!this.picker().isVisible()){
20014 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20025 e.preventDefault();
20029 dir = e.keyCode == 37 ? -1 : 1;
20031 this.vIndex = this.vIndex + dir;
20033 if(this.vIndex < 0){
20037 if(this.vIndex > 11){
20041 if(isNaN(this.vIndex)){
20045 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20051 dir = e.keyCode == 38 ? -1 : 1;
20053 this.vIndex = this.vIndex + dir * 4;
20055 if(this.vIndex < 0){
20059 if(this.vIndex > 11){
20063 if(isNaN(this.vIndex)){
20067 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20072 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20073 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20077 e.preventDefault();
20080 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20081 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20097 this.picker().remove();
20102 Roo.apply(Roo.bootstrap.MonthField, {
20121 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20122 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20127 Roo.apply(Roo.bootstrap.MonthField, {
20131 cls: 'datepicker dropdown-menu roo-dynamic',
20135 cls: 'datepicker-months',
20139 cls: 'table-condensed',
20141 Roo.bootstrap.DateField.content
20161 * @class Roo.bootstrap.CheckBox
20162 * @extends Roo.bootstrap.Input
20163 * Bootstrap CheckBox class
20165 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20166 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20167 * @cfg {String} boxLabel The text that appears beside the checkbox
20168 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20169 * @cfg {Boolean} checked initnal the element
20170 * @cfg {Boolean} inline inline the element (default false)
20171 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20172 * @cfg {String} tooltip label tooltip
20175 * Create a new CheckBox
20176 * @param {Object} config The config object
20179 Roo.bootstrap.CheckBox = function(config){
20180 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20185 * Fires when the element is checked or unchecked.
20186 * @param {Roo.bootstrap.CheckBox} this This input
20187 * @param {Boolean} checked The new checked value
20192 * Fires when the element is click.
20193 * @param {Roo.bootstrap.CheckBox} this This input
20200 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20202 inputType: 'checkbox',
20211 getAutoCreate : function()
20213 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20219 cfg.cls = 'form-group ' + this.inputType; //input-group
20222 cfg.cls += ' ' + this.inputType + '-inline';
20228 type : this.inputType,
20229 value : this.inputValue,
20230 cls : 'roo-' + this.inputType, //'form-box',
20231 placeholder : this.placeholder || ''
20235 if(this.inputType != 'radio'){
20239 cls : 'roo-hidden-value',
20240 value : this.checked ? this.inputValue : this.valueOff
20245 if (this.weight) { // Validity check?
20246 cfg.cls += " " + this.inputType + "-" + this.weight;
20249 if (this.disabled) {
20250 input.disabled=true;
20254 input.checked = this.checked;
20259 input.name = this.name;
20261 if(this.inputType != 'radio'){
20262 hidden.name = this.name;
20263 input.name = '_hidden_' + this.name;
20268 input.cls += ' input-' + this.size;
20273 ['xs','sm','md','lg'].map(function(size){
20274 if (settings[size]) {
20275 cfg.cls += ' col-' + size + '-' + settings[size];
20279 var inputblock = input;
20281 if (this.before || this.after) {
20284 cls : 'input-group',
20289 inputblock.cn.push({
20291 cls : 'input-group-addon',
20296 inputblock.cn.push(input);
20298 if(this.inputType != 'radio'){
20299 inputblock.cn.push(hidden);
20303 inputblock.cn.push({
20305 cls : 'input-group-addon',
20312 if (align ==='left' && this.fieldLabel.length) {
20313 // Roo.log("left and has label");
20318 cls : 'control-label',
20319 html : this.fieldLabel
20329 if(this.labelWidth > 12){
20330 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20333 if(this.labelWidth < 13 && this.labelmd == 0){
20334 this.labelmd = this.labelWidth;
20337 if(this.labellg > 0){
20338 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20339 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20342 if(this.labelmd > 0){
20343 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20344 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20347 if(this.labelsm > 0){
20348 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20349 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20352 if(this.labelxs > 0){
20353 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20354 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20357 } else if ( this.fieldLabel.length) {
20358 // Roo.log(" label");
20362 tag: this.boxLabel ? 'span' : 'label',
20364 cls: 'control-label box-input-label',
20365 //cls : 'input-group-addon',
20366 html : this.fieldLabel
20375 // Roo.log(" no label && no align");
20376 cfg.cn = [ inputblock ] ;
20382 var boxLabelCfg = {
20384 //'for': id, // box label is handled by onclick - so no for...
20386 html: this.boxLabel
20390 boxLabelCfg.tooltip = this.tooltip;
20393 cfg.cn.push(boxLabelCfg);
20396 if(this.inputType != 'radio'){
20397 cfg.cn.push(hidden);
20405 * return the real input element.
20407 inputEl: function ()
20409 return this.el.select('input.roo-' + this.inputType,true).first();
20411 hiddenEl: function ()
20413 return this.el.select('input.roo-hidden-value',true).first();
20416 labelEl: function()
20418 return this.el.select('label.control-label',true).first();
20420 /* depricated... */
20424 return this.labelEl();
20427 boxLabelEl: function()
20429 return this.el.select('label.box-label',true).first();
20432 initEvents : function()
20434 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20436 this.inputEl().on('click', this.onClick, this);
20438 if (this.boxLabel) {
20439 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20442 this.startValue = this.getValue();
20445 Roo.bootstrap.CheckBox.register(this);
20449 onClick : function(e)
20451 if(this.fireEvent('click', this, e) !== false){
20452 this.setChecked(!this.checked);
20457 setChecked : function(state,suppressEvent)
20459 this.startValue = this.getValue();
20461 if(this.inputType == 'radio'){
20463 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20464 e.dom.checked = false;
20467 this.inputEl().dom.checked = true;
20469 this.inputEl().dom.value = this.inputValue;
20471 if(suppressEvent !== true){
20472 this.fireEvent('check', this, true);
20480 this.checked = state;
20482 this.inputEl().dom.checked = state;
20485 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20487 if(suppressEvent !== true){
20488 this.fireEvent('check', this, state);
20494 getValue : function()
20496 if(this.inputType == 'radio'){
20497 return this.getGroupValue();
20500 return this.hiddenEl().dom.value;
20504 getGroupValue : function()
20506 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20510 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20513 setValue : function(v,suppressEvent)
20515 if(this.inputType == 'radio'){
20516 this.setGroupValue(v, suppressEvent);
20520 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20525 setGroupValue : function(v, suppressEvent)
20527 this.startValue = this.getValue();
20529 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20530 e.dom.checked = false;
20532 if(e.dom.value == v){
20533 e.dom.checked = true;
20537 if(suppressEvent !== true){
20538 this.fireEvent('check', this, true);
20546 validate : function()
20550 (this.inputType == 'radio' && this.validateRadio()) ||
20551 (this.inputType == 'checkbox' && this.validateCheckbox())
20557 this.markInvalid();
20561 validateRadio : function()
20563 if(this.allowBlank){
20569 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20570 if(!e.dom.checked){
20582 validateCheckbox : function()
20585 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20586 //return (this.getValue() == this.inputValue) ? true : false;
20589 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20597 for(var i in group){
20598 if(group[i].el.isVisible(true)){
20606 for(var i in group){
20611 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20618 * Mark this field as valid
20620 markValid : function()
20624 this.fireEvent('valid', this);
20626 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20629 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20636 if(this.inputType == 'radio'){
20637 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20638 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20639 e.findParent('.form-group', false, true).addClass(_this.validClass);
20646 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20647 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20651 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20657 for(var i in group){
20658 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20659 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20664 * Mark this field as invalid
20665 * @param {String} msg The validation message
20667 markInvalid : function(msg)
20669 if(this.allowBlank){
20675 this.fireEvent('invalid', this, msg);
20677 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20680 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20684 label.markInvalid();
20687 if(this.inputType == 'radio'){
20688 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20689 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20690 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20697 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20698 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20702 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20708 for(var i in group){
20709 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20710 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20715 clearInvalid : function()
20717 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20719 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20721 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20723 if (label && label.iconEl) {
20724 label.iconEl.removeClass(label.validClass);
20725 label.iconEl.removeClass(label.invalidClass);
20729 disable : function()
20731 if(this.inputType != 'radio'){
20732 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20739 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20740 _this.getActionEl().addClass(this.disabledClass);
20741 e.dom.disabled = true;
20745 this.disabled = true;
20746 this.fireEvent("disable", this);
20750 enable : function()
20752 if(this.inputType != 'radio'){
20753 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20760 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20761 _this.getActionEl().removeClass(this.disabledClass);
20762 e.dom.disabled = false;
20766 this.disabled = false;
20767 this.fireEvent("enable", this);
20771 setBoxLabel : function(v)
20776 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20782 Roo.apply(Roo.bootstrap.CheckBox, {
20787 * register a CheckBox Group
20788 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20790 register : function(checkbox)
20792 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20793 this.groups[checkbox.groupId] = {};
20796 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20800 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20804 * fetch a CheckBox Group based on the group ID
20805 * @param {string} the group ID
20806 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20808 get: function(groupId) {
20809 if (typeof(this.groups[groupId]) == 'undefined') {
20813 return this.groups[groupId] ;
20826 * @class Roo.bootstrap.Radio
20827 * @extends Roo.bootstrap.Component
20828 * Bootstrap Radio class
20829 * @cfg {String} boxLabel - the label associated
20830 * @cfg {String} value - the value of radio
20833 * Create a new Radio
20834 * @param {Object} config The config object
20836 Roo.bootstrap.Radio = function(config){
20837 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20841 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20847 getAutoCreate : function()
20851 cls : 'form-group radio',
20856 html : this.boxLabel
20864 initEvents : function()
20866 this.parent().register(this);
20868 this.el.on('click', this.onClick, this);
20872 onClick : function()
20874 this.setChecked(true);
20877 setChecked : function(state, suppressEvent)
20879 this.parent().setValue(this.value, suppressEvent);
20883 setBoxLabel : function(v)
20888 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20903 * @class Roo.bootstrap.SecurePass
20904 * @extends Roo.bootstrap.Input
20905 * Bootstrap SecurePass class
20909 * Create a new SecurePass
20910 * @param {Object} config The config object
20913 Roo.bootstrap.SecurePass = function (config) {
20914 // these go here, so the translation tool can replace them..
20916 PwdEmpty: "Please type a password, and then retype it to confirm.",
20917 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20918 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20919 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20920 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20921 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20922 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20923 TooWeak: "Your password is Too Weak."
20925 this.meterLabel = "Password strength:";
20926 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20927 this.meterClass = [
20928 "roo-password-meter-tooweak",
20929 "roo-password-meter-weak",
20930 "roo-password-meter-medium",
20931 "roo-password-meter-strong",
20932 "roo-password-meter-grey"
20937 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20940 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20942 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20944 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20945 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20946 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20947 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20948 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20949 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20950 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20960 * @cfg {String/Object} Label for the strength meter (defaults to
20961 * 'Password strength:')
20966 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20967 * ['Weak', 'Medium', 'Strong'])
20970 pwdStrengths: false,
20983 initEvents: function ()
20985 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20987 if (this.el.is('input[type=password]') && Roo.isSafari) {
20988 this.el.on('keydown', this.SafariOnKeyDown, this);
20991 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20994 onRender: function (ct, position)
20996 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20997 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20998 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21000 this.trigger.createChild({
21005 cls: 'roo-password-meter-grey col-xs-12',
21008 //width: this.meterWidth + 'px'
21012 cls: 'roo-password-meter-text'
21018 if (this.hideTrigger) {
21019 this.trigger.setDisplayed(false);
21021 this.setSize(this.width || '', this.height || '');
21024 onDestroy: function ()
21026 if (this.trigger) {
21027 this.trigger.removeAllListeners();
21028 this.trigger.remove();
21031 this.wrap.remove();
21033 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21036 checkStrength: function ()
21038 var pwd = this.inputEl().getValue();
21039 if (pwd == this._lastPwd) {
21044 if (this.ClientSideStrongPassword(pwd)) {
21046 } else if (this.ClientSideMediumPassword(pwd)) {
21048 } else if (this.ClientSideWeakPassword(pwd)) {
21054 Roo.log('strength1: ' + strength);
21056 //var pm = this.trigger.child('div/div/div').dom;
21057 var pm = this.trigger.child('div/div');
21058 pm.removeClass(this.meterClass);
21059 pm.addClass(this.meterClass[strength]);
21062 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21064 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21066 this._lastPwd = pwd;
21070 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21072 this._lastPwd = '';
21074 var pm = this.trigger.child('div/div');
21075 pm.removeClass(this.meterClass);
21076 pm.addClass('roo-password-meter-grey');
21079 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21082 this.inputEl().dom.type='password';
21085 validateValue: function (value)
21088 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21091 if (value.length == 0) {
21092 if (this.allowBlank) {
21093 this.clearInvalid();
21097 this.markInvalid(this.errors.PwdEmpty);
21098 this.errorMsg = this.errors.PwdEmpty;
21106 if ('[\x21-\x7e]*'.match(value)) {
21107 this.markInvalid(this.errors.PwdBadChar);
21108 this.errorMsg = this.errors.PwdBadChar;
21111 if (value.length < 6) {
21112 this.markInvalid(this.errors.PwdShort);
21113 this.errorMsg = this.errors.PwdShort;
21116 if (value.length > 16) {
21117 this.markInvalid(this.errors.PwdLong);
21118 this.errorMsg = this.errors.PwdLong;
21122 if (this.ClientSideStrongPassword(value)) {
21124 } else if (this.ClientSideMediumPassword(value)) {
21126 } else if (this.ClientSideWeakPassword(value)) {
21133 if (strength < 2) {
21134 //this.markInvalid(this.errors.TooWeak);
21135 this.errorMsg = this.errors.TooWeak;
21140 console.log('strength2: ' + strength);
21142 //var pm = this.trigger.child('div/div/div').dom;
21144 var pm = this.trigger.child('div/div');
21145 pm.removeClass(this.meterClass);
21146 pm.addClass(this.meterClass[strength]);
21148 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21150 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21152 this.errorMsg = '';
21156 CharacterSetChecks: function (type)
21159 this.fResult = false;
21162 isctype: function (character, type)
21165 case this.kCapitalLetter:
21166 if (character >= 'A' && character <= 'Z') {
21171 case this.kSmallLetter:
21172 if (character >= 'a' && character <= 'z') {
21178 if (character >= '0' && character <= '9') {
21183 case this.kPunctuation:
21184 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21195 IsLongEnough: function (pwd, size)
21197 return !(pwd == null || isNaN(size) || pwd.length < size);
21200 SpansEnoughCharacterSets: function (word, nb)
21202 if (!this.IsLongEnough(word, nb))
21207 var characterSetChecks = new Array(
21208 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21209 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21212 for (var index = 0; index < word.length; ++index) {
21213 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21214 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21215 characterSetChecks[nCharSet].fResult = true;
21222 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21223 if (characterSetChecks[nCharSet].fResult) {
21228 if (nCharSets < nb) {
21234 ClientSideStrongPassword: function (pwd)
21236 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21239 ClientSideMediumPassword: function (pwd)
21241 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21244 ClientSideWeakPassword: function (pwd)
21246 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21249 })//<script type="text/javascript">
21252 * Based Ext JS Library 1.1.1
21253 * Copyright(c) 2006-2007, Ext JS, LLC.
21259 * @class Roo.HtmlEditorCore
21260 * @extends Roo.Component
21261 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21263 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21266 Roo.HtmlEditorCore = function(config){
21269 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21274 * @event initialize
21275 * Fires when the editor is fully initialized (including the iframe)
21276 * @param {Roo.HtmlEditorCore} this
21281 * Fires when the editor is first receives the focus. Any insertion must wait
21282 * until after this event.
21283 * @param {Roo.HtmlEditorCore} this
21287 * @event beforesync
21288 * Fires before the textarea is updated with content from the editor iframe. Return false
21289 * to cancel the sync.
21290 * @param {Roo.HtmlEditorCore} this
21291 * @param {String} html
21295 * @event beforepush
21296 * Fires before the iframe editor is updated with content from the textarea. Return false
21297 * to cancel the push.
21298 * @param {Roo.HtmlEditorCore} this
21299 * @param {String} html
21304 * Fires when the textarea is updated with content from the editor iframe.
21305 * @param {Roo.HtmlEditorCore} this
21306 * @param {String} html
21311 * Fires when the iframe editor is updated with content from the textarea.
21312 * @param {Roo.HtmlEditorCore} this
21313 * @param {String} html
21318 * @event editorevent
21319 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21320 * @param {Roo.HtmlEditorCore} this
21326 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21328 // defaults : white / black...
21329 this.applyBlacklists();
21336 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21340 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21346 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21351 * @cfg {Number} height (in pixels)
21355 * @cfg {Number} width (in pixels)
21360 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21363 stylesheets: false,
21368 // private properties
21369 validationEvent : false,
21371 initialized : false,
21373 sourceEditMode : false,
21374 onFocus : Roo.emptyFn,
21376 hideMode:'offsets',
21380 // blacklist + whitelisted elements..
21387 * Protected method that will not generally be called directly. It
21388 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21389 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21391 getDocMarkup : function(){
21395 // inherit styels from page...??
21396 if (this.stylesheets === false) {
21398 Roo.get(document.head).select('style').each(function(node) {
21399 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21402 Roo.get(document.head).select('link').each(function(node) {
21403 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21406 } else if (!this.stylesheets.length) {
21408 st = '<style type="text/css">' +
21409 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21412 st = '<style type="text/css">' +
21417 st += '<style type="text/css">' +
21418 'IMG { cursor: pointer } ' +
21421 var cls = 'roo-htmleditor-body';
21423 if(this.bodyCls.length){
21424 cls += ' ' + this.bodyCls;
21427 return '<html><head>' + st +
21428 //<style type="text/css">' +
21429 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21431 ' </head><body class="' + cls + '"></body></html>';
21435 onRender : function(ct, position)
21438 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21439 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21442 this.el.dom.style.border = '0 none';
21443 this.el.dom.setAttribute('tabIndex', -1);
21444 this.el.addClass('x-hidden hide');
21448 if(Roo.isIE){ // fix IE 1px bogus margin
21449 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21453 this.frameId = Roo.id();
21457 var iframe = this.owner.wrap.createChild({
21459 cls: 'form-control', // bootstrap..
21461 name: this.frameId,
21462 frameBorder : 'no',
21463 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21468 this.iframe = iframe.dom;
21470 this.assignDocWin();
21472 this.doc.designMode = 'on';
21475 this.doc.write(this.getDocMarkup());
21479 var task = { // must defer to wait for browser to be ready
21481 //console.log("run task?" + this.doc.readyState);
21482 this.assignDocWin();
21483 if(this.doc.body || this.doc.readyState == 'complete'){
21485 this.doc.designMode="on";
21489 Roo.TaskMgr.stop(task);
21490 this.initEditor.defer(10, this);
21497 Roo.TaskMgr.start(task);
21502 onResize : function(w, h)
21504 Roo.log('resize: ' +w + ',' + h );
21505 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21509 if(typeof w == 'number'){
21511 this.iframe.style.width = w + 'px';
21513 if(typeof h == 'number'){
21515 this.iframe.style.height = h + 'px';
21517 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21524 * Toggles the editor between standard and source edit mode.
21525 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21527 toggleSourceEdit : function(sourceEditMode){
21529 this.sourceEditMode = sourceEditMode === true;
21531 if(this.sourceEditMode){
21533 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21536 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21537 //this.iframe.className = '';
21540 //this.setSize(this.owner.wrap.getSize());
21541 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21548 * Protected method that will not generally be called directly. If you need/want
21549 * custom HTML cleanup, this is the method you should override.
21550 * @param {String} html The HTML to be cleaned
21551 * return {String} The cleaned HTML
21553 cleanHtml : function(html){
21554 html = String(html);
21555 if(html.length > 5){
21556 if(Roo.isSafari){ // strip safari nonsense
21557 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21560 if(html == ' '){
21567 * HTML Editor -> Textarea
21568 * Protected method that will not generally be called directly. Syncs the contents
21569 * of the editor iframe with the textarea.
21571 syncValue : function(){
21572 if(this.initialized){
21573 var bd = (this.doc.body || this.doc.documentElement);
21574 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21575 var html = bd.innerHTML;
21577 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21578 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21580 html = '<div style="'+m[0]+'">' + html + '</div>';
21583 html = this.cleanHtml(html);
21584 // fix up the special chars.. normaly like back quotes in word...
21585 // however we do not want to do this with chinese..
21586 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21587 var cc = b.charCodeAt();
21589 (cc >= 0x4E00 && cc < 0xA000 ) ||
21590 (cc >= 0x3400 && cc < 0x4E00 ) ||
21591 (cc >= 0xf900 && cc < 0xfb00 )
21597 if(this.owner.fireEvent('beforesync', this, html) !== false){
21598 this.el.dom.value = html;
21599 this.owner.fireEvent('sync', this, html);
21605 * Protected method that will not generally be called directly. Pushes the value of the textarea
21606 * into the iframe editor.
21608 pushValue : function(){
21609 if(this.initialized){
21610 var v = this.el.dom.value.trim();
21612 // if(v.length < 1){
21616 if(this.owner.fireEvent('beforepush', this, v) !== false){
21617 var d = (this.doc.body || this.doc.documentElement);
21619 this.cleanUpPaste();
21620 this.el.dom.value = d.innerHTML;
21621 this.owner.fireEvent('push', this, v);
21627 deferFocus : function(){
21628 this.focus.defer(10, this);
21632 focus : function(){
21633 if(this.win && !this.sourceEditMode){
21640 assignDocWin: function()
21642 var iframe = this.iframe;
21645 this.doc = iframe.contentWindow.document;
21646 this.win = iframe.contentWindow;
21648 // if (!Roo.get(this.frameId)) {
21651 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21652 // this.win = Roo.get(this.frameId).dom.contentWindow;
21654 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21658 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21659 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21664 initEditor : function(){
21665 //console.log("INIT EDITOR");
21666 this.assignDocWin();
21670 this.doc.designMode="on";
21672 this.doc.write(this.getDocMarkup());
21675 var dbody = (this.doc.body || this.doc.documentElement);
21676 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21677 // this copies styles from the containing element into thsi one..
21678 // not sure why we need all of this..
21679 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21681 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21682 //ss['background-attachment'] = 'fixed'; // w3c
21683 dbody.bgProperties = 'fixed'; // ie
21684 //Roo.DomHelper.applyStyles(dbody, ss);
21685 Roo.EventManager.on(this.doc, {
21686 //'mousedown': this.onEditorEvent,
21687 'mouseup': this.onEditorEvent,
21688 'dblclick': this.onEditorEvent,
21689 'click': this.onEditorEvent,
21690 'keyup': this.onEditorEvent,
21695 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21697 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21698 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21700 this.initialized = true;
21702 this.owner.fireEvent('initialize', this);
21707 onDestroy : function(){
21713 //for (var i =0; i < this.toolbars.length;i++) {
21714 // // fixme - ask toolbars for heights?
21715 // this.toolbars[i].onDestroy();
21718 //this.wrap.dom.innerHTML = '';
21719 //this.wrap.remove();
21724 onFirstFocus : function(){
21726 this.assignDocWin();
21729 this.activated = true;
21732 if(Roo.isGecko){ // prevent silly gecko errors
21734 var s = this.win.getSelection();
21735 if(!s.focusNode || s.focusNode.nodeType != 3){
21736 var r = s.getRangeAt(0);
21737 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21742 this.execCmd('useCSS', true);
21743 this.execCmd('styleWithCSS', false);
21746 this.owner.fireEvent('activate', this);
21750 adjustFont: function(btn){
21751 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21752 //if(Roo.isSafari){ // safari
21755 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21756 if(Roo.isSafari){ // safari
21757 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21758 v = (v < 10) ? 10 : v;
21759 v = (v > 48) ? 48 : v;
21760 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21765 v = Math.max(1, v+adjust);
21767 this.execCmd('FontSize', v );
21770 onEditorEvent : function(e)
21772 this.owner.fireEvent('editorevent', this, e);
21773 // this.updateToolbar();
21774 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21777 insertTag : function(tg)
21779 // could be a bit smarter... -> wrap the current selected tRoo..
21780 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21782 range = this.createRange(this.getSelection());
21783 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21784 wrappingNode.appendChild(range.extractContents());
21785 range.insertNode(wrappingNode);
21792 this.execCmd("formatblock", tg);
21796 insertText : function(txt)
21800 var range = this.createRange();
21801 range.deleteContents();
21802 //alert(Sender.getAttribute('label'));
21804 range.insertNode(this.doc.createTextNode(txt));
21810 * Executes a Midas editor command on the editor document and performs necessary focus and
21811 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21812 * @param {String} cmd The Midas command
21813 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21815 relayCmd : function(cmd, value){
21817 this.execCmd(cmd, value);
21818 this.owner.fireEvent('editorevent', this);
21819 //this.updateToolbar();
21820 this.owner.deferFocus();
21824 * Executes a Midas editor command directly on the editor document.
21825 * For visual commands, you should use {@link #relayCmd} instead.
21826 * <b>This should only be called after the editor is initialized.</b>
21827 * @param {String} cmd The Midas command
21828 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21830 execCmd : function(cmd, value){
21831 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21838 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21840 * @param {String} text | dom node..
21842 insertAtCursor : function(text)
21845 if(!this.activated){
21851 var r = this.doc.selection.createRange();
21862 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21866 // from jquery ui (MIT licenced)
21868 var win = this.win;
21870 if (win.getSelection && win.getSelection().getRangeAt) {
21871 range = win.getSelection().getRangeAt(0);
21872 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21873 range.insertNode(node);
21874 } else if (win.document.selection && win.document.selection.createRange) {
21875 // no firefox support
21876 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21877 win.document.selection.createRange().pasteHTML(txt);
21879 // no firefox support
21880 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21881 this.execCmd('InsertHTML', txt);
21890 mozKeyPress : function(e){
21892 var c = e.getCharCode(), cmd;
21895 c = String.fromCharCode(c).toLowerCase();
21909 this.cleanUpPaste.defer(100, this);
21917 e.preventDefault();
21925 fixKeys : function(){ // load time branching for fastest keydown performance
21927 return function(e){
21928 var k = e.getKey(), r;
21931 r = this.doc.selection.createRange();
21934 r.pasteHTML('    ');
21941 r = this.doc.selection.createRange();
21943 var target = r.parentElement();
21944 if(!target || target.tagName.toLowerCase() != 'li'){
21946 r.pasteHTML('<br />');
21952 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21953 this.cleanUpPaste.defer(100, this);
21959 }else if(Roo.isOpera){
21960 return function(e){
21961 var k = e.getKey();
21965 this.execCmd('InsertHTML','    ');
21968 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21969 this.cleanUpPaste.defer(100, this);
21974 }else if(Roo.isSafari){
21975 return function(e){
21976 var k = e.getKey();
21980 this.execCmd('InsertText','\t');
21984 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21985 this.cleanUpPaste.defer(100, this);
21993 getAllAncestors: function()
21995 var p = this.getSelectedNode();
21998 a.push(p); // push blank onto stack..
21999 p = this.getParentElement();
22003 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22007 a.push(this.doc.body);
22011 lastSelNode : false,
22014 getSelection : function()
22016 this.assignDocWin();
22017 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22020 getSelectedNode: function()
22022 // this may only work on Gecko!!!
22024 // should we cache this!!!!
22029 var range = this.createRange(this.getSelection()).cloneRange();
22032 var parent = range.parentElement();
22034 var testRange = range.duplicate();
22035 testRange.moveToElementText(parent);
22036 if (testRange.inRange(range)) {
22039 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22042 parent = parent.parentElement;
22047 // is ancestor a text element.
22048 var ac = range.commonAncestorContainer;
22049 if (ac.nodeType == 3) {
22050 ac = ac.parentNode;
22053 var ar = ac.childNodes;
22056 var other_nodes = [];
22057 var has_other_nodes = false;
22058 for (var i=0;i<ar.length;i++) {
22059 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22062 // fullly contained node.
22064 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22069 // probably selected..
22070 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22071 other_nodes.push(ar[i]);
22075 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22080 has_other_nodes = true;
22082 if (!nodes.length && other_nodes.length) {
22083 nodes= other_nodes;
22085 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22091 createRange: function(sel)
22093 // this has strange effects when using with
22094 // top toolbar - not sure if it's a great idea.
22095 //this.editor.contentWindow.focus();
22096 if (typeof sel != "undefined") {
22098 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22100 return this.doc.createRange();
22103 return this.doc.createRange();
22106 getParentElement: function()
22109 this.assignDocWin();
22110 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22112 var range = this.createRange(sel);
22115 var p = range.commonAncestorContainer;
22116 while (p.nodeType == 3) { // text node
22127 * Range intersection.. the hard stuff...
22131 * [ -- selected range --- ]
22135 * if end is before start or hits it. fail.
22136 * if start is after end or hits it fail.
22138 * if either hits (but other is outside. - then it's not
22144 // @see http://www.thismuchiknow.co.uk/?p=64.
22145 rangeIntersectsNode : function(range, node)
22147 var nodeRange = node.ownerDocument.createRange();
22149 nodeRange.selectNode(node);
22151 nodeRange.selectNodeContents(node);
22154 var rangeStartRange = range.cloneRange();
22155 rangeStartRange.collapse(true);
22157 var rangeEndRange = range.cloneRange();
22158 rangeEndRange.collapse(false);
22160 var nodeStartRange = nodeRange.cloneRange();
22161 nodeStartRange.collapse(true);
22163 var nodeEndRange = nodeRange.cloneRange();
22164 nodeEndRange.collapse(false);
22166 return rangeStartRange.compareBoundaryPoints(
22167 Range.START_TO_START, nodeEndRange) == -1 &&
22168 rangeEndRange.compareBoundaryPoints(
22169 Range.START_TO_START, nodeStartRange) == 1;
22173 rangeCompareNode : function(range, node)
22175 var nodeRange = node.ownerDocument.createRange();
22177 nodeRange.selectNode(node);
22179 nodeRange.selectNodeContents(node);
22183 range.collapse(true);
22185 nodeRange.collapse(true);
22187 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22188 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22190 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22192 var nodeIsBefore = ss == 1;
22193 var nodeIsAfter = ee == -1;
22195 if (nodeIsBefore && nodeIsAfter) {
22198 if (!nodeIsBefore && nodeIsAfter) {
22199 return 1; //right trailed.
22202 if (nodeIsBefore && !nodeIsAfter) {
22203 return 2; // left trailed.
22209 // private? - in a new class?
22210 cleanUpPaste : function()
22212 // cleans up the whole document..
22213 Roo.log('cleanuppaste');
22215 this.cleanUpChildren(this.doc.body);
22216 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22217 if (clean != this.doc.body.innerHTML) {
22218 this.doc.body.innerHTML = clean;
22223 cleanWordChars : function(input) {// change the chars to hex code
22224 var he = Roo.HtmlEditorCore;
22226 var output = input;
22227 Roo.each(he.swapCodes, function(sw) {
22228 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22230 output = output.replace(swapper, sw[1]);
22237 cleanUpChildren : function (n)
22239 if (!n.childNodes.length) {
22242 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22243 this.cleanUpChild(n.childNodes[i]);
22250 cleanUpChild : function (node)
22253 //console.log(node);
22254 if (node.nodeName == "#text") {
22255 // clean up silly Windows -- stuff?
22258 if (node.nodeName == "#comment") {
22259 node.parentNode.removeChild(node);
22260 // clean up silly Windows -- stuff?
22263 var lcname = node.tagName.toLowerCase();
22264 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22265 // whitelist of tags..
22267 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22269 node.parentNode.removeChild(node);
22274 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22276 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22277 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22279 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22280 // remove_keep_children = true;
22283 if (remove_keep_children) {
22284 this.cleanUpChildren(node);
22285 // inserts everything just before this node...
22286 while (node.childNodes.length) {
22287 var cn = node.childNodes[0];
22288 node.removeChild(cn);
22289 node.parentNode.insertBefore(cn, node);
22291 node.parentNode.removeChild(node);
22295 if (!node.attributes || !node.attributes.length) {
22296 this.cleanUpChildren(node);
22300 function cleanAttr(n,v)
22303 if (v.match(/^\./) || v.match(/^\//)) {
22306 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22309 if (v.match(/^#/)) {
22312 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22313 node.removeAttribute(n);
22317 var cwhite = this.cwhite;
22318 var cblack = this.cblack;
22320 function cleanStyle(n,v)
22322 if (v.match(/expression/)) { //XSS?? should we even bother..
22323 node.removeAttribute(n);
22327 var parts = v.split(/;/);
22330 Roo.each(parts, function(p) {
22331 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22335 var l = p.split(':').shift().replace(/\s+/g,'');
22336 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22338 if ( cwhite.length && cblack.indexOf(l) > -1) {
22339 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22340 //node.removeAttribute(n);
22344 // only allow 'c whitelisted system attributes'
22345 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22346 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22347 //node.removeAttribute(n);
22357 if (clean.length) {
22358 node.setAttribute(n, clean.join(';'));
22360 node.removeAttribute(n);
22366 for (var i = node.attributes.length-1; i > -1 ; i--) {
22367 var a = node.attributes[i];
22370 if (a.name.toLowerCase().substr(0,2)=='on') {
22371 node.removeAttribute(a.name);
22374 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22375 node.removeAttribute(a.name);
22378 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22379 cleanAttr(a.name,a.value); // fixme..
22382 if (a.name == 'style') {
22383 cleanStyle(a.name,a.value);
22386 /// clean up MS crap..
22387 // tecnically this should be a list of valid class'es..
22390 if (a.name == 'class') {
22391 if (a.value.match(/^Mso/)) {
22392 node.className = '';
22395 if (a.value.match(/^body$/)) {
22396 node.className = '';
22407 this.cleanUpChildren(node);
22413 * Clean up MS wordisms...
22415 cleanWord : function(node)
22420 this.cleanWord(this.doc.body);
22423 if (node.nodeName == "#text") {
22424 // clean up silly Windows -- stuff?
22427 if (node.nodeName == "#comment") {
22428 node.parentNode.removeChild(node);
22429 // clean up silly Windows -- stuff?
22433 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22434 node.parentNode.removeChild(node);
22438 // remove - but keep children..
22439 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22440 while (node.childNodes.length) {
22441 var cn = node.childNodes[0];
22442 node.removeChild(cn);
22443 node.parentNode.insertBefore(cn, node);
22445 node.parentNode.removeChild(node);
22446 this.iterateChildren(node, this.cleanWord);
22450 if (node.className.length) {
22452 var cn = node.className.split(/\W+/);
22454 Roo.each(cn, function(cls) {
22455 if (cls.match(/Mso[a-zA-Z]+/)) {
22460 node.className = cna.length ? cna.join(' ') : '';
22462 node.removeAttribute("class");
22466 if (node.hasAttribute("lang")) {
22467 node.removeAttribute("lang");
22470 if (node.hasAttribute("style")) {
22472 var styles = node.getAttribute("style").split(";");
22474 Roo.each(styles, function(s) {
22475 if (!s.match(/:/)) {
22478 var kv = s.split(":");
22479 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22482 // what ever is left... we allow.
22485 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22486 if (!nstyle.length) {
22487 node.removeAttribute('style');
22490 this.iterateChildren(node, this.cleanWord);
22496 * iterateChildren of a Node, calling fn each time, using this as the scole..
22497 * @param {DomNode} node node to iterate children of.
22498 * @param {Function} fn method of this class to call on each item.
22500 iterateChildren : function(node, fn)
22502 if (!node.childNodes.length) {
22505 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22506 fn.call(this, node.childNodes[i])
22512 * cleanTableWidths.
22514 * Quite often pasting from word etc.. results in tables with column and widths.
22515 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22518 cleanTableWidths : function(node)
22523 this.cleanTableWidths(this.doc.body);
22528 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22531 Roo.log(node.tagName);
22532 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22533 this.iterateChildren(node, this.cleanTableWidths);
22536 if (node.hasAttribute('width')) {
22537 node.removeAttribute('width');
22541 if (node.hasAttribute("style")) {
22544 var styles = node.getAttribute("style").split(";");
22546 Roo.each(styles, function(s) {
22547 if (!s.match(/:/)) {
22550 var kv = s.split(":");
22551 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22554 // what ever is left... we allow.
22557 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22558 if (!nstyle.length) {
22559 node.removeAttribute('style');
22563 this.iterateChildren(node, this.cleanTableWidths);
22571 domToHTML : function(currentElement, depth, nopadtext) {
22573 depth = depth || 0;
22574 nopadtext = nopadtext || false;
22576 if (!currentElement) {
22577 return this.domToHTML(this.doc.body);
22580 //Roo.log(currentElement);
22582 var allText = false;
22583 var nodeName = currentElement.nodeName;
22584 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22586 if (nodeName == '#text') {
22588 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22593 if (nodeName != 'BODY') {
22596 // Prints the node tagName, such as <A>, <IMG>, etc
22599 for(i = 0; i < currentElement.attributes.length;i++) {
22601 var aname = currentElement.attributes.item(i).name;
22602 if (!currentElement.attributes.item(i).value.length) {
22605 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22608 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22617 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22620 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22625 // Traverse the tree
22627 var currentElementChild = currentElement.childNodes.item(i);
22628 var allText = true;
22629 var innerHTML = '';
22631 while (currentElementChild) {
22632 // Formatting code (indent the tree so it looks nice on the screen)
22633 var nopad = nopadtext;
22634 if (lastnode == 'SPAN') {
22638 if (currentElementChild.nodeName == '#text') {
22639 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22640 toadd = nopadtext ? toadd : toadd.trim();
22641 if (!nopad && toadd.length > 80) {
22642 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22644 innerHTML += toadd;
22647 currentElementChild = currentElement.childNodes.item(i);
22653 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22655 // Recursively traverse the tree structure of the child node
22656 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22657 lastnode = currentElementChild.nodeName;
22659 currentElementChild=currentElement.childNodes.item(i);
22665 // The remaining code is mostly for formatting the tree
22666 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22671 ret+= "</"+tagName+">";
22677 applyBlacklists : function()
22679 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22680 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22684 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22685 if (b.indexOf(tag) > -1) {
22688 this.white.push(tag);
22692 Roo.each(w, function(tag) {
22693 if (b.indexOf(tag) > -1) {
22696 if (this.white.indexOf(tag) > -1) {
22699 this.white.push(tag);
22704 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22705 if (w.indexOf(tag) > -1) {
22708 this.black.push(tag);
22712 Roo.each(b, function(tag) {
22713 if (w.indexOf(tag) > -1) {
22716 if (this.black.indexOf(tag) > -1) {
22719 this.black.push(tag);
22724 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22725 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22729 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22730 if (b.indexOf(tag) > -1) {
22733 this.cwhite.push(tag);
22737 Roo.each(w, function(tag) {
22738 if (b.indexOf(tag) > -1) {
22741 if (this.cwhite.indexOf(tag) > -1) {
22744 this.cwhite.push(tag);
22749 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22750 if (w.indexOf(tag) > -1) {
22753 this.cblack.push(tag);
22757 Roo.each(b, function(tag) {
22758 if (w.indexOf(tag) > -1) {
22761 if (this.cblack.indexOf(tag) > -1) {
22764 this.cblack.push(tag);
22769 setStylesheets : function(stylesheets)
22771 if(typeof(stylesheets) == 'string'){
22772 Roo.get(this.iframe.contentDocument.head).createChild({
22774 rel : 'stylesheet',
22783 Roo.each(stylesheets, function(s) {
22788 Roo.get(_this.iframe.contentDocument.head).createChild({
22790 rel : 'stylesheet',
22799 removeStylesheets : function()
22803 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22808 setStyle : function(style)
22810 Roo.get(this.iframe.contentDocument.head).createChild({
22819 // hide stuff that is not compatible
22833 * @event specialkey
22837 * @cfg {String} fieldClass @hide
22840 * @cfg {String} focusClass @hide
22843 * @cfg {String} autoCreate @hide
22846 * @cfg {String} inputType @hide
22849 * @cfg {String} invalidClass @hide
22852 * @cfg {String} invalidText @hide
22855 * @cfg {String} msgFx @hide
22858 * @cfg {String} validateOnBlur @hide
22862 Roo.HtmlEditorCore.white = [
22863 'area', 'br', 'img', 'input', 'hr', 'wbr',
22865 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22866 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22867 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22868 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22869 'table', 'ul', 'xmp',
22871 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22874 'dir', 'menu', 'ol', 'ul', 'dl',
22880 Roo.HtmlEditorCore.black = [
22881 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22883 'base', 'basefont', 'bgsound', 'blink', 'body',
22884 'frame', 'frameset', 'head', 'html', 'ilayer',
22885 'iframe', 'layer', 'link', 'meta', 'object',
22886 'script', 'style' ,'title', 'xml' // clean later..
22888 Roo.HtmlEditorCore.clean = [
22889 'script', 'style', 'title', 'xml'
22891 Roo.HtmlEditorCore.remove = [
22896 Roo.HtmlEditorCore.ablack = [
22900 Roo.HtmlEditorCore.aclean = [
22901 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22905 Roo.HtmlEditorCore.pwhite= [
22906 'http', 'https', 'mailto'
22909 // white listed style attributes.
22910 Roo.HtmlEditorCore.cwhite= [
22911 // 'text-align', /// default is to allow most things..
22917 // black listed style attributes.
22918 Roo.HtmlEditorCore.cblack= [
22919 // 'font-size' -- this can be set by the project
22923 Roo.HtmlEditorCore.swapCodes =[
22942 * @class Roo.bootstrap.HtmlEditor
22943 * @extends Roo.bootstrap.TextArea
22944 * Bootstrap HtmlEditor class
22947 * Create a new HtmlEditor
22948 * @param {Object} config The config object
22951 Roo.bootstrap.HtmlEditor = function(config){
22952 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22953 if (!this.toolbars) {
22954 this.toolbars = [];
22957 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22960 * @event initialize
22961 * Fires when the editor is fully initialized (including the iframe)
22962 * @param {HtmlEditor} this
22967 * Fires when the editor is first receives the focus. Any insertion must wait
22968 * until after this event.
22969 * @param {HtmlEditor} this
22973 * @event beforesync
22974 * Fires before the textarea is updated with content from the editor iframe. Return false
22975 * to cancel the sync.
22976 * @param {HtmlEditor} this
22977 * @param {String} html
22981 * @event beforepush
22982 * Fires before the iframe editor is updated with content from the textarea. Return false
22983 * to cancel the push.
22984 * @param {HtmlEditor} this
22985 * @param {String} html
22990 * Fires when the textarea is updated with content from the editor iframe.
22991 * @param {HtmlEditor} this
22992 * @param {String} html
22997 * Fires when the iframe editor is updated with content from the textarea.
22998 * @param {HtmlEditor} this
22999 * @param {String} html
23003 * @event editmodechange
23004 * Fires when the editor switches edit modes
23005 * @param {HtmlEditor} this
23006 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23008 editmodechange: true,
23010 * @event editorevent
23011 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23012 * @param {HtmlEditor} this
23016 * @event firstfocus
23017 * Fires when on first focus - needed by toolbars..
23018 * @param {HtmlEditor} this
23023 * Auto save the htmlEditor value as a file into Events
23024 * @param {HtmlEditor} this
23028 * @event savedpreview
23029 * preview the saved version of htmlEditor
23030 * @param {HtmlEditor} this
23037 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23041 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23046 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23051 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23056 * @cfg {Number} height (in pixels)
23060 * @cfg {Number} width (in pixels)
23065 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23068 stylesheets: false,
23073 // private properties
23074 validationEvent : false,
23076 initialized : false,
23079 onFocus : Roo.emptyFn,
23081 hideMode:'offsets',
23083 tbContainer : false,
23087 toolbarContainer :function() {
23088 return this.wrap.select('.x-html-editor-tb',true).first();
23092 * Protected method that will not generally be called directly. It
23093 * is called when the editor creates its toolbar. Override this method if you need to
23094 * add custom toolbar buttons.
23095 * @param {HtmlEditor} editor
23097 createToolbar : function(){
23098 Roo.log('renewing');
23099 Roo.log("create toolbars");
23101 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23102 this.toolbars[0].render(this.toolbarContainer());
23106 // if (!editor.toolbars || !editor.toolbars.length) {
23107 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23110 // for (var i =0 ; i < editor.toolbars.length;i++) {
23111 // editor.toolbars[i] = Roo.factory(
23112 // typeof(editor.toolbars[i]) == 'string' ?
23113 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23114 // Roo.bootstrap.HtmlEditor);
23115 // editor.toolbars[i].init(editor);
23121 onRender : function(ct, position)
23123 // Roo.log("Call onRender: " + this.xtype);
23125 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23127 this.wrap = this.inputEl().wrap({
23128 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23131 this.editorcore.onRender(ct, position);
23133 if (this.resizable) {
23134 this.resizeEl = new Roo.Resizable(this.wrap, {
23138 minHeight : this.height,
23139 height: this.height,
23140 handles : this.resizable,
23143 resize : function(r, w, h) {
23144 _t.onResize(w,h); // -something
23150 this.createToolbar(this);
23153 if(!this.width && this.resizable){
23154 this.setSize(this.wrap.getSize());
23156 if (this.resizeEl) {
23157 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23158 // should trigger onReize..
23164 onResize : function(w, h)
23166 Roo.log('resize: ' +w + ',' + h );
23167 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23171 if(this.inputEl() ){
23172 if(typeof w == 'number'){
23173 var aw = w - this.wrap.getFrameWidth('lr');
23174 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23177 if(typeof h == 'number'){
23178 var tbh = -11; // fixme it needs to tool bar size!
23179 for (var i =0; i < this.toolbars.length;i++) {
23180 // fixme - ask toolbars for heights?
23181 tbh += this.toolbars[i].el.getHeight();
23182 //if (this.toolbars[i].footer) {
23183 // tbh += this.toolbars[i].footer.el.getHeight();
23191 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23192 ah -= 5; // knock a few pixes off for look..
23193 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23197 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23198 this.editorcore.onResize(ew,eh);
23203 * Toggles the editor between standard and source edit mode.
23204 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23206 toggleSourceEdit : function(sourceEditMode)
23208 this.editorcore.toggleSourceEdit(sourceEditMode);
23210 if(this.editorcore.sourceEditMode){
23211 Roo.log('editor - showing textarea');
23214 // Roo.log(this.syncValue());
23216 this.inputEl().removeClass(['hide', 'x-hidden']);
23217 this.inputEl().dom.removeAttribute('tabIndex');
23218 this.inputEl().focus();
23220 Roo.log('editor - hiding textarea');
23222 // Roo.log(this.pushValue());
23225 this.inputEl().addClass(['hide', 'x-hidden']);
23226 this.inputEl().dom.setAttribute('tabIndex', -1);
23227 //this.deferFocus();
23230 if(this.resizable){
23231 this.setSize(this.wrap.getSize());
23234 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23237 // private (for BoxComponent)
23238 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23240 // private (for BoxComponent)
23241 getResizeEl : function(){
23245 // private (for BoxComponent)
23246 getPositionEl : function(){
23251 initEvents : function(){
23252 this.originalValue = this.getValue();
23256 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23259 // markInvalid : Roo.emptyFn,
23261 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23264 // clearInvalid : Roo.emptyFn,
23266 setValue : function(v){
23267 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23268 this.editorcore.pushValue();
23273 deferFocus : function(){
23274 this.focus.defer(10, this);
23278 focus : function(){
23279 this.editorcore.focus();
23285 onDestroy : function(){
23291 for (var i =0; i < this.toolbars.length;i++) {
23292 // fixme - ask toolbars for heights?
23293 this.toolbars[i].onDestroy();
23296 this.wrap.dom.innerHTML = '';
23297 this.wrap.remove();
23302 onFirstFocus : function(){
23303 //Roo.log("onFirstFocus");
23304 this.editorcore.onFirstFocus();
23305 for (var i =0; i < this.toolbars.length;i++) {
23306 this.toolbars[i].onFirstFocus();
23312 syncValue : function()
23314 this.editorcore.syncValue();
23317 pushValue : function()
23319 this.editorcore.pushValue();
23323 // hide stuff that is not compatible
23337 * @event specialkey
23341 * @cfg {String} fieldClass @hide
23344 * @cfg {String} focusClass @hide
23347 * @cfg {String} autoCreate @hide
23350 * @cfg {String} inputType @hide
23353 * @cfg {String} invalidClass @hide
23356 * @cfg {String} invalidText @hide
23359 * @cfg {String} msgFx @hide
23362 * @cfg {String} validateOnBlur @hide
23371 Roo.namespace('Roo.bootstrap.htmleditor');
23373 * @class Roo.bootstrap.HtmlEditorToolbar1
23378 new Roo.bootstrap.HtmlEditor({
23381 new Roo.bootstrap.HtmlEditorToolbar1({
23382 disable : { fonts: 1 , format: 1, ..., ... , ...],
23388 * @cfg {Object} disable List of elements to disable..
23389 * @cfg {Array} btns List of additional buttons.
23393 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23396 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23399 Roo.apply(this, config);
23401 // default disabled, based on 'good practice'..
23402 this.disable = this.disable || {};
23403 Roo.applyIf(this.disable, {
23406 specialElements : true
23408 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23410 this.editor = config.editor;
23411 this.editorcore = config.editor.editorcore;
23413 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23415 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23416 // dont call parent... till later.
23418 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23423 editorcore : false,
23428 "h1","h2","h3","h4","h5","h6",
23430 "abbr", "acronym", "address", "cite", "samp", "var",
23434 onRender : function(ct, position)
23436 // Roo.log("Call onRender: " + this.xtype);
23438 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23440 this.el.dom.style.marginBottom = '0';
23442 var editorcore = this.editorcore;
23443 var editor= this.editor;
23446 var btn = function(id,cmd , toggle, handler, html){
23448 var event = toggle ? 'toggle' : 'click';
23453 xns: Roo.bootstrap,
23456 enableToggle:toggle !== false,
23458 pressed : toggle ? false : null,
23461 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23462 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23468 // var cb_box = function...
23473 xns: Roo.bootstrap,
23474 glyphicon : 'font',
23478 xns: Roo.bootstrap,
23482 Roo.each(this.formats, function(f) {
23483 style.menu.items.push({
23485 xns: Roo.bootstrap,
23486 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23491 editorcore.insertTag(this.tagname);
23498 children.push(style);
23500 btn('bold',false,true);
23501 btn('italic',false,true);
23502 btn('align-left', 'justifyleft',true);
23503 btn('align-center', 'justifycenter',true);
23504 btn('align-right' , 'justifyright',true);
23505 btn('link', false, false, function(btn) {
23506 //Roo.log("create link?");
23507 var url = prompt(this.createLinkText, this.defaultLinkValue);
23508 if(url && url != 'http:/'+'/'){
23509 this.editorcore.relayCmd('createlink', url);
23512 btn('list','insertunorderedlist',true);
23513 btn('pencil', false,true, function(btn){
23515 this.toggleSourceEdit(btn.pressed);
23518 if (this.editor.btns.length > 0) {
23519 for (var i = 0; i<this.editor.btns.length; i++) {
23520 children.push(this.editor.btns[i]);
23528 xns: Roo.bootstrap,
23533 xns: Roo.bootstrap,
23538 cog.menu.items.push({
23540 xns: Roo.bootstrap,
23541 html : Clean styles,
23546 editorcore.insertTag(this.tagname);
23555 this.xtype = 'NavSimplebar';
23557 for(var i=0;i< children.length;i++) {
23559 this.buttons.add(this.addxtypeChild(children[i]));
23563 editor.on('editorevent', this.updateToolbar, this);
23565 onBtnClick : function(id)
23567 this.editorcore.relayCmd(id);
23568 this.editorcore.focus();
23572 * Protected method that will not generally be called directly. It triggers
23573 * a toolbar update by reading the markup state of the current selection in the editor.
23575 updateToolbar: function(){
23577 if(!this.editorcore.activated){
23578 this.editor.onFirstFocus(); // is this neeed?
23582 var btns = this.buttons;
23583 var doc = this.editorcore.doc;
23584 btns.get('bold').setActive(doc.queryCommandState('bold'));
23585 btns.get('italic').setActive(doc.queryCommandState('italic'));
23586 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23588 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23589 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23590 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23592 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23593 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23596 var ans = this.editorcore.getAllAncestors();
23597 if (this.formatCombo) {
23600 var store = this.formatCombo.store;
23601 this.formatCombo.setValue("");
23602 for (var i =0; i < ans.length;i++) {
23603 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23605 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23613 // hides menus... - so this cant be on a menu...
23614 Roo.bootstrap.MenuMgr.hideAll();
23616 Roo.bootstrap.MenuMgr.hideAll();
23617 //this.editorsyncValue();
23619 onFirstFocus: function() {
23620 this.buttons.each(function(item){
23624 toggleSourceEdit : function(sourceEditMode){
23627 if(sourceEditMode){
23628 Roo.log("disabling buttons");
23629 this.buttons.each( function(item){
23630 if(item.cmd != 'pencil'){
23636 Roo.log("enabling buttons");
23637 if(this.editorcore.initialized){
23638 this.buttons.each( function(item){
23644 Roo.log("calling toggole on editor");
23645 // tell the editor that it's been pressed..
23646 this.editor.toggleSourceEdit(sourceEditMode);
23656 * @class Roo.bootstrap.Table.AbstractSelectionModel
23657 * @extends Roo.util.Observable
23658 * Abstract base class for grid SelectionModels. It provides the interface that should be
23659 * implemented by descendant classes. This class should not be directly instantiated.
23662 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23663 this.locked = false;
23664 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23668 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23669 /** @ignore Called by the grid automatically. Do not call directly. */
23670 init : function(grid){
23676 * Locks the selections.
23679 this.locked = true;
23683 * Unlocks the selections.
23685 unlock : function(){
23686 this.locked = false;
23690 * Returns true if the selections are locked.
23691 * @return {Boolean}
23693 isLocked : function(){
23694 return this.locked;
23698 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23699 * @class Roo.bootstrap.Table.RowSelectionModel
23700 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23701 * It supports multiple selections and keyboard selection/navigation.
23703 * @param {Object} config
23706 Roo.bootstrap.Table.RowSelectionModel = function(config){
23707 Roo.apply(this, config);
23708 this.selections = new Roo.util.MixedCollection(false, function(o){
23713 this.lastActive = false;
23717 * @event selectionchange
23718 * Fires when the selection changes
23719 * @param {SelectionModel} this
23721 "selectionchange" : true,
23723 * @event afterselectionchange
23724 * Fires after the selection changes (eg. by key press or clicking)
23725 * @param {SelectionModel} this
23727 "afterselectionchange" : true,
23729 * @event beforerowselect
23730 * Fires when a row is selected being selected, return false to cancel.
23731 * @param {SelectionModel} this
23732 * @param {Number} rowIndex The selected index
23733 * @param {Boolean} keepExisting False if other selections will be cleared
23735 "beforerowselect" : true,
23738 * Fires when a row is selected.
23739 * @param {SelectionModel} this
23740 * @param {Number} rowIndex The selected index
23741 * @param {Roo.data.Record} r The record
23743 "rowselect" : true,
23745 * @event rowdeselect
23746 * Fires when a row is deselected.
23747 * @param {SelectionModel} this
23748 * @param {Number} rowIndex The selected index
23750 "rowdeselect" : true
23752 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23753 this.locked = false;
23756 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23758 * @cfg {Boolean} singleSelect
23759 * True to allow selection of only one row at a time (defaults to false)
23761 singleSelect : false,
23764 initEvents : function()
23767 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23768 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23769 //}else{ // allow click to work like normal
23770 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23772 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23773 this.grid.on("rowclick", this.handleMouseDown, this);
23775 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23776 "up" : function(e){
23778 this.selectPrevious(e.shiftKey);
23779 }else if(this.last !== false && this.lastActive !== false){
23780 var last = this.last;
23781 this.selectRange(this.last, this.lastActive-1);
23782 this.grid.getView().focusRow(this.lastActive);
23783 if(last !== false){
23787 this.selectFirstRow();
23789 this.fireEvent("afterselectionchange", this);
23791 "down" : function(e){
23793 this.selectNext(e.shiftKey);
23794 }else if(this.last !== false && this.lastActive !== false){
23795 var last = this.last;
23796 this.selectRange(this.last, this.lastActive+1);
23797 this.grid.getView().focusRow(this.lastActive);
23798 if(last !== false){
23802 this.selectFirstRow();
23804 this.fireEvent("afterselectionchange", this);
23808 this.grid.store.on('load', function(){
23809 this.selections.clear();
23812 var view = this.grid.view;
23813 view.on("refresh", this.onRefresh, this);
23814 view.on("rowupdated", this.onRowUpdated, this);
23815 view.on("rowremoved", this.onRemove, this);
23820 onRefresh : function()
23822 var ds = this.grid.store, i, v = this.grid.view;
23823 var s = this.selections;
23824 s.each(function(r){
23825 if((i = ds.indexOfId(r.id)) != -1){
23834 onRemove : function(v, index, r){
23835 this.selections.remove(r);
23839 onRowUpdated : function(v, index, r){
23840 if(this.isSelected(r)){
23841 v.onRowSelect(index);
23847 * @param {Array} records The records to select
23848 * @param {Boolean} keepExisting (optional) True to keep existing selections
23850 selectRecords : function(records, keepExisting)
23853 this.clearSelections();
23855 var ds = this.grid.store;
23856 for(var i = 0, len = records.length; i < len; i++){
23857 this.selectRow(ds.indexOf(records[i]), true);
23862 * Gets the number of selected rows.
23865 getCount : function(){
23866 return this.selections.length;
23870 * Selects the first row in the grid.
23872 selectFirstRow : function(){
23877 * Select the last row.
23878 * @param {Boolean} keepExisting (optional) True to keep existing selections
23880 selectLastRow : function(keepExisting){
23881 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23882 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23886 * Selects the row immediately following the last selected row.
23887 * @param {Boolean} keepExisting (optional) True to keep existing selections
23889 selectNext : function(keepExisting)
23891 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23892 this.selectRow(this.last+1, keepExisting);
23893 this.grid.getView().focusRow(this.last);
23898 * Selects the row that precedes the last selected row.
23899 * @param {Boolean} keepExisting (optional) True to keep existing selections
23901 selectPrevious : function(keepExisting){
23903 this.selectRow(this.last-1, keepExisting);
23904 this.grid.getView().focusRow(this.last);
23909 * Returns the selected records
23910 * @return {Array} Array of selected records
23912 getSelections : function(){
23913 return [].concat(this.selections.items);
23917 * Returns the first selected record.
23920 getSelected : function(){
23921 return this.selections.itemAt(0);
23926 * Clears all selections.
23928 clearSelections : function(fast)
23934 var ds = this.grid.store;
23935 var s = this.selections;
23936 s.each(function(r){
23937 this.deselectRow(ds.indexOfId(r.id));
23941 this.selections.clear();
23948 * Selects all rows.
23950 selectAll : function(){
23954 this.selections.clear();
23955 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23956 this.selectRow(i, true);
23961 * Returns True if there is a selection.
23962 * @return {Boolean}
23964 hasSelection : function(){
23965 return this.selections.length > 0;
23969 * Returns True if the specified row is selected.
23970 * @param {Number/Record} record The record or index of the record to check
23971 * @return {Boolean}
23973 isSelected : function(index){
23974 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23975 return (r && this.selections.key(r.id) ? true : false);
23979 * Returns True if the specified record id is selected.
23980 * @param {String} id The id of record to check
23981 * @return {Boolean}
23983 isIdSelected : function(id){
23984 return (this.selections.key(id) ? true : false);
23989 handleMouseDBClick : function(e, t){
23993 handleMouseDown : function(e, t)
23995 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23996 if(this.isLocked() || rowIndex < 0 ){
23999 if(e.shiftKey && this.last !== false){
24000 var last = this.last;
24001 this.selectRange(last, rowIndex, e.ctrlKey);
24002 this.last = last; // reset the last
24006 var isSelected = this.isSelected(rowIndex);
24007 //Roo.log("select row:" + rowIndex);
24009 this.deselectRow(rowIndex);
24011 this.selectRow(rowIndex, true);
24015 if(e.button !== 0 && isSelected){
24016 alert('rowIndex 2: ' + rowIndex);
24017 view.focusRow(rowIndex);
24018 }else if(e.ctrlKey && isSelected){
24019 this.deselectRow(rowIndex);
24020 }else if(!isSelected){
24021 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24022 view.focusRow(rowIndex);
24026 this.fireEvent("afterselectionchange", this);
24029 handleDragableRowClick : function(grid, rowIndex, e)
24031 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24032 this.selectRow(rowIndex, false);
24033 grid.view.focusRow(rowIndex);
24034 this.fireEvent("afterselectionchange", this);
24039 * Selects multiple rows.
24040 * @param {Array} rows Array of the indexes of the row to select
24041 * @param {Boolean} keepExisting (optional) True to keep existing selections
24043 selectRows : function(rows, keepExisting){
24045 this.clearSelections();
24047 for(var i = 0, len = rows.length; i < len; i++){
24048 this.selectRow(rows[i], true);
24053 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24054 * @param {Number} startRow The index of the first row in the range
24055 * @param {Number} endRow The index of the last row in the range
24056 * @param {Boolean} keepExisting (optional) True to retain existing selections
24058 selectRange : function(startRow, endRow, keepExisting){
24063 this.clearSelections();
24065 if(startRow <= endRow){
24066 for(var i = startRow; i <= endRow; i++){
24067 this.selectRow(i, true);
24070 for(var i = startRow; i >= endRow; i--){
24071 this.selectRow(i, true);
24077 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24078 * @param {Number} startRow The index of the first row in the range
24079 * @param {Number} endRow The index of the last row in the range
24081 deselectRange : function(startRow, endRow, preventViewNotify){
24085 for(var i = startRow; i <= endRow; i++){
24086 this.deselectRow(i, preventViewNotify);
24092 * @param {Number} row The index of the row to select
24093 * @param {Boolean} keepExisting (optional) True to keep existing selections
24095 selectRow : function(index, keepExisting, preventViewNotify)
24097 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24100 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24101 if(!keepExisting || this.singleSelect){
24102 this.clearSelections();
24105 var r = this.grid.store.getAt(index);
24106 //console.log('selectRow - record id :' + r.id);
24108 this.selections.add(r);
24109 this.last = this.lastActive = index;
24110 if(!preventViewNotify){
24111 var proxy = new Roo.Element(
24112 this.grid.getRowDom(index)
24114 proxy.addClass('bg-info info');
24116 this.fireEvent("rowselect", this, index, r);
24117 this.fireEvent("selectionchange", this);
24123 * @param {Number} row The index of the row to deselect
24125 deselectRow : function(index, preventViewNotify)
24130 if(this.last == index){
24133 if(this.lastActive == index){
24134 this.lastActive = false;
24137 var r = this.grid.store.getAt(index);
24142 this.selections.remove(r);
24143 //.console.log('deselectRow - record id :' + r.id);
24144 if(!preventViewNotify){
24146 var proxy = new Roo.Element(
24147 this.grid.getRowDom(index)
24149 proxy.removeClass('bg-info info');
24151 this.fireEvent("rowdeselect", this, index);
24152 this.fireEvent("selectionchange", this);
24156 restoreLast : function(){
24158 this.last = this._last;
24163 acceptsNav : function(row, col, cm){
24164 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24168 onEditorKey : function(field, e){
24169 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24174 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24176 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24178 }else if(k == e.ENTER && !e.ctrlKey){
24182 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24184 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24186 }else if(k == e.ESC){
24190 g.startEditing(newCell[0], newCell[1]);
24196 * Ext JS Library 1.1.1
24197 * Copyright(c) 2006-2007, Ext JS, LLC.
24199 * Originally Released Under LGPL - original licence link has changed is not relivant.
24202 * <script type="text/javascript">
24206 * @class Roo.bootstrap.PagingToolbar
24207 * @extends Roo.bootstrap.NavSimplebar
24208 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24210 * Create a new PagingToolbar
24211 * @param {Object} config The config object
24212 * @param {Roo.data.Store} store
24214 Roo.bootstrap.PagingToolbar = function(config)
24216 // old args format still supported... - xtype is prefered..
24217 // created from xtype...
24219 this.ds = config.dataSource;
24221 if (config.store && !this.ds) {
24222 this.store= Roo.factory(config.store, Roo.data);
24223 this.ds = this.store;
24224 this.ds.xmodule = this.xmodule || false;
24227 this.toolbarItems = [];
24228 if (config.items) {
24229 this.toolbarItems = config.items;
24232 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24237 this.bind(this.ds);
24240 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24244 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24246 * @cfg {Roo.data.Store} dataSource
24247 * The underlying data store providing the paged data
24250 * @cfg {String/HTMLElement/Element} container
24251 * container The id or element that will contain the toolbar
24254 * @cfg {Boolean} displayInfo
24255 * True to display the displayMsg (defaults to false)
24258 * @cfg {Number} pageSize
24259 * The number of records to display per page (defaults to 20)
24263 * @cfg {String} displayMsg
24264 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24266 displayMsg : 'Displaying {0} - {1} of {2}',
24268 * @cfg {String} emptyMsg
24269 * The message to display when no records are found (defaults to "No data to display")
24271 emptyMsg : 'No data to display',
24273 * Customizable piece of the default paging text (defaults to "Page")
24276 beforePageText : "Page",
24278 * Customizable piece of the default paging text (defaults to "of %0")
24281 afterPageText : "of {0}",
24283 * Customizable piece of the default paging text (defaults to "First Page")
24286 firstText : "First Page",
24288 * Customizable piece of the default paging text (defaults to "Previous Page")
24291 prevText : "Previous Page",
24293 * Customizable piece of the default paging text (defaults to "Next Page")
24296 nextText : "Next Page",
24298 * Customizable piece of the default paging text (defaults to "Last Page")
24301 lastText : "Last Page",
24303 * Customizable piece of the default paging text (defaults to "Refresh")
24306 refreshText : "Refresh",
24310 onRender : function(ct, position)
24312 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24313 this.navgroup.parentId = this.id;
24314 this.navgroup.onRender(this.el, null);
24315 // add the buttons to the navgroup
24317 if(this.displayInfo){
24318 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24319 this.displayEl = this.el.select('.x-paging-info', true).first();
24320 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24321 // this.displayEl = navel.el.select('span',true).first();
24327 Roo.each(_this.buttons, function(e){ // this might need to use render????
24328 Roo.factory(e).onRender(_this.el, null);
24332 Roo.each(_this.toolbarItems, function(e) {
24333 _this.navgroup.addItem(e);
24337 this.first = this.navgroup.addItem({
24338 tooltip: this.firstText,
24340 icon : 'fa fa-backward',
24342 preventDefault: true,
24343 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24346 this.prev = this.navgroup.addItem({
24347 tooltip: this.prevText,
24349 icon : 'fa fa-step-backward',
24351 preventDefault: true,
24352 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24354 //this.addSeparator();
24357 var field = this.navgroup.addItem( {
24359 cls : 'x-paging-position',
24361 html : this.beforePageText +
24362 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24363 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24366 this.field = field.el.select('input', true).first();
24367 this.field.on("keydown", this.onPagingKeydown, this);
24368 this.field.on("focus", function(){this.dom.select();});
24371 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24372 //this.field.setHeight(18);
24373 //this.addSeparator();
24374 this.next = this.navgroup.addItem({
24375 tooltip: this.nextText,
24377 html : ' <i class="fa fa-step-forward">',
24379 preventDefault: true,
24380 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24382 this.last = this.navgroup.addItem({
24383 tooltip: this.lastText,
24384 icon : 'fa fa-forward',
24387 preventDefault: true,
24388 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24390 //this.addSeparator();
24391 this.loading = this.navgroup.addItem({
24392 tooltip: this.refreshText,
24393 icon: 'fa fa-refresh',
24394 preventDefault: true,
24395 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24401 updateInfo : function(){
24402 if(this.displayEl){
24403 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24404 var msg = count == 0 ?
24408 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24410 this.displayEl.update(msg);
24415 onLoad : function(ds, r, o)
24417 this.cursor = o.params ? o.params.start : 0;
24418 var d = this.getPageData(),
24423 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24424 this.field.dom.value = ap;
24425 this.first.setDisabled(ap == 1);
24426 this.prev.setDisabled(ap == 1);
24427 this.next.setDisabled(ap == ps);
24428 this.last.setDisabled(ap == ps);
24429 this.loading.enable();
24434 getPageData : function(){
24435 var total = this.ds.getTotalCount();
24438 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24439 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24444 onLoadError : function(){
24445 this.loading.enable();
24449 onPagingKeydown : function(e){
24450 var k = e.getKey();
24451 var d = this.getPageData();
24453 var v = this.field.dom.value, pageNum;
24454 if(!v || isNaN(pageNum = parseInt(v, 10))){
24455 this.field.dom.value = d.activePage;
24458 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24459 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24462 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))
24464 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24465 this.field.dom.value = pageNum;
24466 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24469 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24471 var v = this.field.dom.value, pageNum;
24472 var increment = (e.shiftKey) ? 10 : 1;
24473 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24476 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24477 this.field.dom.value = d.activePage;
24480 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24482 this.field.dom.value = parseInt(v, 10) + increment;
24483 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24484 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24491 beforeLoad : function(){
24493 this.loading.disable();
24498 onClick : function(which){
24507 ds.load({params:{start: 0, limit: this.pageSize}});
24510 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24513 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24516 var total = ds.getTotalCount();
24517 var extra = total % this.pageSize;
24518 var lastStart = extra ? (total - extra) : total-this.pageSize;
24519 ds.load({params:{start: lastStart, limit: this.pageSize}});
24522 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24528 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24529 * @param {Roo.data.Store} store The data store to unbind
24531 unbind : function(ds){
24532 ds.un("beforeload", this.beforeLoad, this);
24533 ds.un("load", this.onLoad, this);
24534 ds.un("loadexception", this.onLoadError, this);
24535 ds.un("remove", this.updateInfo, this);
24536 ds.un("add", this.updateInfo, this);
24537 this.ds = undefined;
24541 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24542 * @param {Roo.data.Store} store The data store to bind
24544 bind : function(ds){
24545 ds.on("beforeload", this.beforeLoad, this);
24546 ds.on("load", this.onLoad, this);
24547 ds.on("loadexception", this.onLoadError, this);
24548 ds.on("remove", this.updateInfo, this);
24549 ds.on("add", this.updateInfo, this);
24560 * @class Roo.bootstrap.MessageBar
24561 * @extends Roo.bootstrap.Component
24562 * Bootstrap MessageBar class
24563 * @cfg {String} html contents of the MessageBar
24564 * @cfg {String} weight (info | success | warning | danger) default info
24565 * @cfg {String} beforeClass insert the bar before the given class
24566 * @cfg {Boolean} closable (true | false) default false
24567 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24570 * Create a new Element
24571 * @param {Object} config The config object
24574 Roo.bootstrap.MessageBar = function(config){
24575 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24578 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24584 beforeClass: 'bootstrap-sticky-wrap',
24586 getAutoCreate : function(){
24590 cls: 'alert alert-dismissable alert-' + this.weight,
24595 html: this.html || ''
24601 cfg.cls += ' alert-messages-fixed';
24615 onRender : function(ct, position)
24617 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24620 var cfg = Roo.apply({}, this.getAutoCreate());
24624 cfg.cls += ' ' + this.cls;
24627 cfg.style = this.style;
24629 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24631 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24634 this.el.select('>button.close').on('click', this.hide, this);
24640 if (!this.rendered) {
24646 this.fireEvent('show', this);
24652 if (!this.rendered) {
24658 this.fireEvent('hide', this);
24661 update : function()
24663 // var e = this.el.dom.firstChild;
24665 // if(this.closable){
24666 // e = e.nextSibling;
24669 // e.data = this.html || '';
24671 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24687 * @class Roo.bootstrap.Graph
24688 * @extends Roo.bootstrap.Component
24689 * Bootstrap Graph class
24693 @cfg {String} graphtype bar | vbar | pie
24694 @cfg {number} g_x coodinator | centre x (pie)
24695 @cfg {number} g_y coodinator | centre y (pie)
24696 @cfg {number} g_r radius (pie)
24697 @cfg {number} g_height height of the chart (respected by all elements in the set)
24698 @cfg {number} g_width width of the chart (respected by all elements in the set)
24699 @cfg {Object} title The title of the chart
24702 -opts (object) options for the chart
24704 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24705 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24707 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.
24708 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24710 o stretch (boolean)
24712 -opts (object) options for the pie
24715 o startAngle (number)
24716 o endAngle (number)
24720 * Create a new Input
24721 * @param {Object} config The config object
24724 Roo.bootstrap.Graph = function(config){
24725 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24731 * The img click event for the img.
24732 * @param {Roo.EventObject} e
24738 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24749 //g_colors: this.colors,
24756 getAutoCreate : function(){
24767 onRender : function(ct,position){
24770 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24772 if (typeof(Raphael) == 'undefined') {
24773 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24777 this.raphael = Raphael(this.el.dom);
24779 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24780 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24781 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24782 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24784 r.text(160, 10, "Single Series Chart").attr(txtattr);
24785 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24786 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24787 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24789 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24790 r.barchart(330, 10, 300, 220, data1);
24791 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24792 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24795 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24796 // r.barchart(30, 30, 560, 250, xdata, {
24797 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24798 // axis : "0 0 1 1",
24799 // axisxlabels : xdata
24800 // //yvalues : cols,
24803 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24805 // this.load(null,xdata,{
24806 // axis : "0 0 1 1",
24807 // axisxlabels : xdata
24812 load : function(graphtype,xdata,opts)
24814 this.raphael.clear();
24816 graphtype = this.graphtype;
24821 var r = this.raphael,
24822 fin = function () {
24823 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24825 fout = function () {
24826 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24828 pfin = function() {
24829 this.sector.stop();
24830 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24833 this.label[0].stop();
24834 this.label[0].attr({ r: 7.5 });
24835 this.label[1].attr({ "font-weight": 800 });
24838 pfout = function() {
24839 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24842 this.label[0].animate({ r: 5 }, 500, "bounce");
24843 this.label[1].attr({ "font-weight": 400 });
24849 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24852 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24855 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24856 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24858 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24865 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24870 setTitle: function(o)
24875 initEvents: function() {
24878 this.el.on('click', this.onClick, this);
24882 onClick : function(e)
24884 Roo.log('img onclick');
24885 this.fireEvent('click', this, e);
24897 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24900 * @class Roo.bootstrap.dash.NumberBox
24901 * @extends Roo.bootstrap.Component
24902 * Bootstrap NumberBox class
24903 * @cfg {String} headline Box headline
24904 * @cfg {String} content Box content
24905 * @cfg {String} icon Box icon
24906 * @cfg {String} footer Footer text
24907 * @cfg {String} fhref Footer href
24910 * Create a new NumberBox
24911 * @param {Object} config The config object
24915 Roo.bootstrap.dash.NumberBox = function(config){
24916 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24920 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24929 getAutoCreate : function(){
24933 cls : 'small-box ',
24941 cls : 'roo-headline',
24942 html : this.headline
24946 cls : 'roo-content',
24947 html : this.content
24961 cls : 'ion ' + this.icon
24970 cls : 'small-box-footer',
24971 href : this.fhref || '#',
24975 cfg.cn.push(footer);
24982 onRender : function(ct,position){
24983 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24990 setHeadline: function (value)
24992 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24995 setFooter: function (value, href)
24997 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25000 this.el.select('a.small-box-footer',true).first().attr('href', href);
25005 setContent: function (value)
25007 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25010 initEvents: function()
25024 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25027 * @class Roo.bootstrap.dash.TabBox
25028 * @extends Roo.bootstrap.Component
25029 * Bootstrap TabBox class
25030 * @cfg {String} title Title of the TabBox
25031 * @cfg {String} icon Icon of the TabBox
25032 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25033 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25036 * Create a new TabBox
25037 * @param {Object} config The config object
25041 Roo.bootstrap.dash.TabBox = function(config){
25042 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25047 * When a pane is added
25048 * @param {Roo.bootstrap.dash.TabPane} pane
25052 * @event activatepane
25053 * When a pane is activated
25054 * @param {Roo.bootstrap.dash.TabPane} pane
25056 "activatepane" : true
25064 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25069 tabScrollable : false,
25071 getChildContainer : function()
25073 return this.el.select('.tab-content', true).first();
25076 getAutoCreate : function(){
25080 cls: 'pull-left header',
25088 cls: 'fa ' + this.icon
25094 cls: 'nav nav-tabs pull-right',
25100 if(this.tabScrollable){
25107 cls: 'nav nav-tabs pull-right',
25118 cls: 'nav-tabs-custom',
25123 cls: 'tab-content no-padding',
25131 initEvents : function()
25133 //Roo.log('add add pane handler');
25134 this.on('addpane', this.onAddPane, this);
25137 * Updates the box title
25138 * @param {String} html to set the title to.
25140 setTitle : function(value)
25142 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25144 onAddPane : function(pane)
25146 this.panes.push(pane);
25147 //Roo.log('addpane');
25149 // tabs are rendere left to right..
25150 if(!this.showtabs){
25154 var ctr = this.el.select('.nav-tabs', true).first();
25157 var existing = ctr.select('.nav-tab',true);
25158 var qty = existing.getCount();;
25161 var tab = ctr.createChild({
25163 cls : 'nav-tab' + (qty ? '' : ' active'),
25171 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25174 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25176 pane.el.addClass('active');
25181 onTabClick : function(ev,un,ob,pane)
25183 //Roo.log('tab - prev default');
25184 ev.preventDefault();
25187 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25188 pane.tab.addClass('active');
25189 //Roo.log(pane.title);
25190 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25191 // technically we should have a deactivate event.. but maybe add later.
25192 // and it should not de-activate the selected tab...
25193 this.fireEvent('activatepane', pane);
25194 pane.el.addClass('active');
25195 pane.fireEvent('activate');
25200 getActivePane : function()
25203 Roo.each(this.panes, function(p) {
25204 if(p.el.hasClass('active')){
25225 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25227 * @class Roo.bootstrap.TabPane
25228 * @extends Roo.bootstrap.Component
25229 * Bootstrap TabPane class
25230 * @cfg {Boolean} active (false | true) Default false
25231 * @cfg {String} title title of panel
25235 * Create a new TabPane
25236 * @param {Object} config The config object
25239 Roo.bootstrap.dash.TabPane = function(config){
25240 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25246 * When a pane is activated
25247 * @param {Roo.bootstrap.dash.TabPane} pane
25254 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25259 // the tabBox that this is attached to.
25262 getAutoCreate : function()
25270 cfg.cls += ' active';
25275 initEvents : function()
25277 //Roo.log('trigger add pane handler');
25278 this.parent().fireEvent('addpane', this)
25282 * Updates the tab title
25283 * @param {String} html to set the title to.
25285 setTitle: function(str)
25291 this.tab.select('a', true).first().dom.innerHTML = str;
25308 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25311 * @class Roo.bootstrap.menu.Menu
25312 * @extends Roo.bootstrap.Component
25313 * Bootstrap Menu class - container for Menu
25314 * @cfg {String} html Text of the menu
25315 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25316 * @cfg {String} icon Font awesome icon
25317 * @cfg {String} pos Menu align to (top | bottom) default bottom
25321 * Create a new Menu
25322 * @param {Object} config The config object
25326 Roo.bootstrap.menu.Menu = function(config){
25327 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25331 * @event beforeshow
25332 * Fires before this menu is displayed
25333 * @param {Roo.bootstrap.menu.Menu} this
25337 * @event beforehide
25338 * Fires before this menu is hidden
25339 * @param {Roo.bootstrap.menu.Menu} this
25344 * Fires after this menu is displayed
25345 * @param {Roo.bootstrap.menu.Menu} this
25350 * Fires after this menu is hidden
25351 * @param {Roo.bootstrap.menu.Menu} this
25356 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25357 * @param {Roo.bootstrap.menu.Menu} this
25358 * @param {Roo.EventObject} e
25365 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25369 weight : 'default',
25374 getChildContainer : function() {
25375 if(this.isSubMenu){
25379 return this.el.select('ul.dropdown-menu', true).first();
25382 getAutoCreate : function()
25387 cls : 'roo-menu-text',
25395 cls : 'fa ' + this.icon
25406 cls : 'dropdown-button btn btn-' + this.weight,
25411 cls : 'dropdown-toggle btn btn-' + this.weight,
25421 cls : 'dropdown-menu'
25427 if(this.pos == 'top'){
25428 cfg.cls += ' dropup';
25431 if(this.isSubMenu){
25434 cls : 'dropdown-menu'
25441 onRender : function(ct, position)
25443 this.isSubMenu = ct.hasClass('dropdown-submenu');
25445 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25448 initEvents : function()
25450 if(this.isSubMenu){
25454 this.hidden = true;
25456 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25457 this.triggerEl.on('click', this.onTriggerPress, this);
25459 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25460 this.buttonEl.on('click', this.onClick, this);
25466 if(this.isSubMenu){
25470 return this.el.select('ul.dropdown-menu', true).first();
25473 onClick : function(e)
25475 this.fireEvent("click", this, e);
25478 onTriggerPress : function(e)
25480 if (this.isVisible()) {
25487 isVisible : function(){
25488 return !this.hidden;
25493 this.fireEvent("beforeshow", this);
25495 this.hidden = false;
25496 this.el.addClass('open');
25498 Roo.get(document).on("mouseup", this.onMouseUp, this);
25500 this.fireEvent("show", this);
25507 this.fireEvent("beforehide", this);
25509 this.hidden = true;
25510 this.el.removeClass('open');
25512 Roo.get(document).un("mouseup", this.onMouseUp);
25514 this.fireEvent("hide", this);
25517 onMouseUp : function()
25531 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25534 * @class Roo.bootstrap.menu.Item
25535 * @extends Roo.bootstrap.Component
25536 * Bootstrap MenuItem class
25537 * @cfg {Boolean} submenu (true | false) default false
25538 * @cfg {String} html text of the item
25539 * @cfg {String} href the link
25540 * @cfg {Boolean} disable (true | false) default false
25541 * @cfg {Boolean} preventDefault (true | false) default true
25542 * @cfg {String} icon Font awesome icon
25543 * @cfg {String} pos Submenu align to (left | right) default right
25547 * Create a new Item
25548 * @param {Object} config The config object
25552 Roo.bootstrap.menu.Item = function(config){
25553 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25557 * Fires when the mouse is hovering over this menu
25558 * @param {Roo.bootstrap.menu.Item} this
25559 * @param {Roo.EventObject} e
25564 * Fires when the mouse exits this menu
25565 * @param {Roo.bootstrap.menu.Item} this
25566 * @param {Roo.EventObject} e
25572 * The raw click event for the entire grid.
25573 * @param {Roo.EventObject} e
25579 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25584 preventDefault: true,
25589 getAutoCreate : function()
25594 cls : 'roo-menu-item-text',
25602 cls : 'fa ' + this.icon
25611 href : this.href || '#',
25618 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25622 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25624 if(this.pos == 'left'){
25625 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25632 initEvents : function()
25634 this.el.on('mouseover', this.onMouseOver, this);
25635 this.el.on('mouseout', this.onMouseOut, this);
25637 this.el.select('a', true).first().on('click', this.onClick, this);
25641 onClick : function(e)
25643 if(this.preventDefault){
25644 e.preventDefault();
25647 this.fireEvent("click", this, e);
25650 onMouseOver : function(e)
25652 if(this.submenu && this.pos == 'left'){
25653 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25656 this.fireEvent("mouseover", this, e);
25659 onMouseOut : function(e)
25661 this.fireEvent("mouseout", this, e);
25673 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25676 * @class Roo.bootstrap.menu.Separator
25677 * @extends Roo.bootstrap.Component
25678 * Bootstrap Separator class
25681 * Create a new Separator
25682 * @param {Object} config The config object
25686 Roo.bootstrap.menu.Separator = function(config){
25687 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25690 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25692 getAutoCreate : function(){
25713 * @class Roo.bootstrap.Tooltip
25714 * Bootstrap Tooltip class
25715 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25716 * to determine which dom element triggers the tooltip.
25718 * It needs to add support for additional attributes like tooltip-position
25721 * Create a new Toolti
25722 * @param {Object} config The config object
25725 Roo.bootstrap.Tooltip = function(config){
25726 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25728 this.alignment = Roo.bootstrap.Tooltip.alignment;
25730 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25731 this.alignment = config.alignment;
25736 Roo.apply(Roo.bootstrap.Tooltip, {
25738 * @function init initialize tooltip monitoring.
25742 currentTip : false,
25743 currentRegion : false,
25749 Roo.get(document).on('mouseover', this.enter ,this);
25750 Roo.get(document).on('mouseout', this.leave, this);
25753 this.currentTip = new Roo.bootstrap.Tooltip();
25756 enter : function(ev)
25758 var dom = ev.getTarget();
25760 //Roo.log(['enter',dom]);
25761 var el = Roo.fly(dom);
25762 if (this.currentEl) {
25764 //Roo.log(this.currentEl);
25765 //Roo.log(this.currentEl.contains(dom));
25766 if (this.currentEl == el) {
25769 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25775 if (this.currentTip.el) {
25776 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25780 if(!el || el.dom == document){
25786 // you can not look for children, as if el is the body.. then everythign is the child..
25787 if (!el.attr('tooltip')) { //
25788 if (!el.select("[tooltip]").elements.length) {
25791 // is the mouse over this child...?
25792 bindEl = el.select("[tooltip]").first();
25793 var xy = ev.getXY();
25794 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25795 //Roo.log("not in region.");
25798 //Roo.log("child element over..");
25801 this.currentEl = bindEl;
25802 this.currentTip.bind(bindEl);
25803 this.currentRegion = Roo.lib.Region.getRegion(dom);
25804 this.currentTip.enter();
25807 leave : function(ev)
25809 var dom = ev.getTarget();
25810 //Roo.log(['leave',dom]);
25811 if (!this.currentEl) {
25816 if (dom != this.currentEl.dom) {
25819 var xy = ev.getXY();
25820 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25823 // only activate leave if mouse cursor is outside... bounding box..
25828 if (this.currentTip) {
25829 this.currentTip.leave();
25831 //Roo.log('clear currentEl');
25832 this.currentEl = false;
25837 'left' : ['r-l', [-2,0], 'right'],
25838 'right' : ['l-r', [2,0], 'left'],
25839 'bottom' : ['t-b', [0,2], 'top'],
25840 'top' : [ 'b-t', [0,-2], 'bottom']
25846 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25851 delay : null, // can be { show : 300 , hide: 500}
25855 hoverState : null, //???
25857 placement : 'bottom',
25861 getAutoCreate : function(){
25868 cls : 'tooltip-arrow'
25871 cls : 'tooltip-inner'
25878 bind : function(el)
25884 enter : function () {
25886 if (this.timeout != null) {
25887 clearTimeout(this.timeout);
25890 this.hoverState = 'in';
25891 //Roo.log("enter - show");
25892 if (!this.delay || !this.delay.show) {
25897 this.timeout = setTimeout(function () {
25898 if (_t.hoverState == 'in') {
25901 }, this.delay.show);
25905 clearTimeout(this.timeout);
25907 this.hoverState = 'out';
25908 if (!this.delay || !this.delay.hide) {
25914 this.timeout = setTimeout(function () {
25915 //Roo.log("leave - timeout");
25917 if (_t.hoverState == 'out') {
25919 Roo.bootstrap.Tooltip.currentEl = false;
25924 show : function (msg)
25927 this.render(document.body);
25930 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25932 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25934 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25936 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25938 var placement = typeof this.placement == 'function' ?
25939 this.placement.call(this, this.el, on_el) :
25942 var autoToken = /\s?auto?\s?/i;
25943 var autoPlace = autoToken.test(placement);
25945 placement = placement.replace(autoToken, '') || 'top';
25949 //this.el.setXY([0,0]);
25951 //this.el.dom.style.display='block';
25953 //this.el.appendTo(on_el);
25955 var p = this.getPosition();
25956 var box = this.el.getBox();
25962 var align = this.alignment[placement];
25964 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25966 if(placement == 'top' || placement == 'bottom'){
25968 placement = 'right';
25971 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25972 placement = 'left';
25975 var scroll = Roo.select('body', true).first().getScroll();
25977 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25983 this.el.alignTo(this.bindEl, align[0],align[1]);
25984 //var arrow = this.el.select('.arrow',true).first();
25985 //arrow.set(align[2],
25987 this.el.addClass(placement);
25989 this.el.addClass('in fade');
25991 this.hoverState = null;
25993 if (this.el.hasClass('fade')) {
26004 //this.el.setXY([0,0]);
26005 this.el.removeClass('in');
26021 * @class Roo.bootstrap.LocationPicker
26022 * @extends Roo.bootstrap.Component
26023 * Bootstrap LocationPicker class
26024 * @cfg {Number} latitude Position when init default 0
26025 * @cfg {Number} longitude Position when init default 0
26026 * @cfg {Number} zoom default 15
26027 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26028 * @cfg {Boolean} mapTypeControl default false
26029 * @cfg {Boolean} disableDoubleClickZoom default false
26030 * @cfg {Boolean} scrollwheel default true
26031 * @cfg {Boolean} streetViewControl default false
26032 * @cfg {Number} radius default 0
26033 * @cfg {String} locationName
26034 * @cfg {Boolean} draggable default true
26035 * @cfg {Boolean} enableAutocomplete default false
26036 * @cfg {Boolean} enableReverseGeocode default true
26037 * @cfg {String} markerTitle
26040 * Create a new LocationPicker
26041 * @param {Object} config The config object
26045 Roo.bootstrap.LocationPicker = function(config){
26047 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26052 * Fires when the picker initialized.
26053 * @param {Roo.bootstrap.LocationPicker} this
26054 * @param {Google Location} location
26058 * @event positionchanged
26059 * Fires when the picker position changed.
26060 * @param {Roo.bootstrap.LocationPicker} this
26061 * @param {Google Location} location
26063 positionchanged : true,
26066 * Fires when the map resize.
26067 * @param {Roo.bootstrap.LocationPicker} this
26072 * Fires when the map show.
26073 * @param {Roo.bootstrap.LocationPicker} this
26078 * Fires when the map hide.
26079 * @param {Roo.bootstrap.LocationPicker} this
26084 * Fires when click the map.
26085 * @param {Roo.bootstrap.LocationPicker} this
26086 * @param {Map event} e
26090 * @event mapRightClick
26091 * Fires when right click the map.
26092 * @param {Roo.bootstrap.LocationPicker} this
26093 * @param {Map event} e
26095 mapRightClick : true,
26097 * @event markerClick
26098 * Fires when click the marker.
26099 * @param {Roo.bootstrap.LocationPicker} this
26100 * @param {Map event} e
26102 markerClick : true,
26104 * @event markerRightClick
26105 * Fires when right click the marker.
26106 * @param {Roo.bootstrap.LocationPicker} this
26107 * @param {Map event} e
26109 markerRightClick : true,
26111 * @event OverlayViewDraw
26112 * Fires when OverlayView Draw
26113 * @param {Roo.bootstrap.LocationPicker} this
26115 OverlayViewDraw : true,
26117 * @event OverlayViewOnAdd
26118 * Fires when OverlayView Draw
26119 * @param {Roo.bootstrap.LocationPicker} this
26121 OverlayViewOnAdd : true,
26123 * @event OverlayViewOnRemove
26124 * Fires when OverlayView Draw
26125 * @param {Roo.bootstrap.LocationPicker} this
26127 OverlayViewOnRemove : true,
26129 * @event OverlayViewShow
26130 * Fires when OverlayView Draw
26131 * @param {Roo.bootstrap.LocationPicker} this
26132 * @param {Pixel} cpx
26134 OverlayViewShow : true,
26136 * @event OverlayViewHide
26137 * Fires when OverlayView Draw
26138 * @param {Roo.bootstrap.LocationPicker} this
26140 OverlayViewHide : true,
26142 * @event loadexception
26143 * Fires when load google lib failed.
26144 * @param {Roo.bootstrap.LocationPicker} this
26146 loadexception : true
26151 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26153 gMapContext: false,
26159 mapTypeControl: false,
26160 disableDoubleClickZoom: false,
26162 streetViewControl: false,
26166 enableAutocomplete: false,
26167 enableReverseGeocode: true,
26170 getAutoCreate: function()
26175 cls: 'roo-location-picker'
26181 initEvents: function(ct, position)
26183 if(!this.el.getWidth() || this.isApplied()){
26187 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26192 initial: function()
26194 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26195 this.fireEvent('loadexception', this);
26199 if(!this.mapTypeId){
26200 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26203 this.gMapContext = this.GMapContext();
26205 this.initOverlayView();
26207 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26211 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26212 _this.setPosition(_this.gMapContext.marker.position);
26215 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26216 _this.fireEvent('mapClick', this, event);
26220 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26221 _this.fireEvent('mapRightClick', this, event);
26225 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26226 _this.fireEvent('markerClick', this, event);
26230 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26231 _this.fireEvent('markerRightClick', this, event);
26235 this.setPosition(this.gMapContext.location);
26237 this.fireEvent('initial', this, this.gMapContext.location);
26240 initOverlayView: function()
26244 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26248 _this.fireEvent('OverlayViewDraw', _this);
26253 _this.fireEvent('OverlayViewOnAdd', _this);
26256 onRemove: function()
26258 _this.fireEvent('OverlayViewOnRemove', _this);
26261 show: function(cpx)
26263 _this.fireEvent('OverlayViewShow', _this, cpx);
26268 _this.fireEvent('OverlayViewHide', _this);
26274 fromLatLngToContainerPixel: function(event)
26276 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26279 isApplied: function()
26281 return this.getGmapContext() == false ? false : true;
26284 getGmapContext: function()
26286 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26289 GMapContext: function()
26291 var position = new google.maps.LatLng(this.latitude, this.longitude);
26293 var _map = new google.maps.Map(this.el.dom, {
26296 mapTypeId: this.mapTypeId,
26297 mapTypeControl: this.mapTypeControl,
26298 disableDoubleClickZoom: this.disableDoubleClickZoom,
26299 scrollwheel: this.scrollwheel,
26300 streetViewControl: this.streetViewControl,
26301 locationName: this.locationName,
26302 draggable: this.draggable,
26303 enableAutocomplete: this.enableAutocomplete,
26304 enableReverseGeocode: this.enableReverseGeocode
26307 var _marker = new google.maps.Marker({
26308 position: position,
26310 title: this.markerTitle,
26311 draggable: this.draggable
26318 location: position,
26319 radius: this.radius,
26320 locationName: this.locationName,
26321 addressComponents: {
26322 formatted_address: null,
26323 addressLine1: null,
26324 addressLine2: null,
26326 streetNumber: null,
26330 stateOrProvince: null
26333 domContainer: this.el.dom,
26334 geodecoder: new google.maps.Geocoder()
26338 drawCircle: function(center, radius, options)
26340 if (this.gMapContext.circle != null) {
26341 this.gMapContext.circle.setMap(null);
26345 options = Roo.apply({}, options, {
26346 strokeColor: "#0000FF",
26347 strokeOpacity: .35,
26349 fillColor: "#0000FF",
26353 options.map = this.gMapContext.map;
26354 options.radius = radius;
26355 options.center = center;
26356 this.gMapContext.circle = new google.maps.Circle(options);
26357 return this.gMapContext.circle;
26363 setPosition: function(location)
26365 this.gMapContext.location = location;
26366 this.gMapContext.marker.setPosition(location);
26367 this.gMapContext.map.panTo(location);
26368 this.drawCircle(location, this.gMapContext.radius, {});
26372 if (this.gMapContext.settings.enableReverseGeocode) {
26373 this.gMapContext.geodecoder.geocode({
26374 latLng: this.gMapContext.location
26375 }, function(results, status) {
26377 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26378 _this.gMapContext.locationName = results[0].formatted_address;
26379 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26381 _this.fireEvent('positionchanged', this, location);
26388 this.fireEvent('positionchanged', this, location);
26393 google.maps.event.trigger(this.gMapContext.map, "resize");
26395 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26397 this.fireEvent('resize', this);
26400 setPositionByLatLng: function(latitude, longitude)
26402 this.setPosition(new google.maps.LatLng(latitude, longitude));
26405 getCurrentPosition: function()
26408 latitude: this.gMapContext.location.lat(),
26409 longitude: this.gMapContext.location.lng()
26413 getAddressName: function()
26415 return this.gMapContext.locationName;
26418 getAddressComponents: function()
26420 return this.gMapContext.addressComponents;
26423 address_component_from_google_geocode: function(address_components)
26427 for (var i = 0; i < address_components.length; i++) {
26428 var component = address_components[i];
26429 if (component.types.indexOf("postal_code") >= 0) {
26430 result.postalCode = component.short_name;
26431 } else if (component.types.indexOf("street_number") >= 0) {
26432 result.streetNumber = component.short_name;
26433 } else if (component.types.indexOf("route") >= 0) {
26434 result.streetName = component.short_name;
26435 } else if (component.types.indexOf("neighborhood") >= 0) {
26436 result.city = component.short_name;
26437 } else if (component.types.indexOf("locality") >= 0) {
26438 result.city = component.short_name;
26439 } else if (component.types.indexOf("sublocality") >= 0) {
26440 result.district = component.short_name;
26441 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26442 result.stateOrProvince = component.short_name;
26443 } else if (component.types.indexOf("country") >= 0) {
26444 result.country = component.short_name;
26448 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26449 result.addressLine2 = "";
26453 setZoomLevel: function(zoom)
26455 this.gMapContext.map.setZoom(zoom);
26468 this.fireEvent('show', this);
26479 this.fireEvent('hide', this);
26484 Roo.apply(Roo.bootstrap.LocationPicker, {
26486 OverlayView : function(map, options)
26488 options = options || {};
26502 * @class Roo.bootstrap.Alert
26503 * @extends Roo.bootstrap.Component
26504 * Bootstrap Alert class
26505 * @cfg {String} title The title of alert
26506 * @cfg {String} html The content of alert
26507 * @cfg {String} weight ( success | info | warning | danger )
26508 * @cfg {String} faicon font-awesomeicon
26511 * Create a new alert
26512 * @param {Object} config The config object
26516 Roo.bootstrap.Alert = function(config){
26517 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26521 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26528 getAutoCreate : function()
26537 cls : 'roo-alert-icon'
26542 cls : 'roo-alert-title',
26547 cls : 'roo-alert-text',
26554 cfg.cn[0].cls += ' fa ' + this.faicon;
26558 cfg.cls += ' alert-' + this.weight;
26564 initEvents: function()
26566 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26569 setTitle : function(str)
26571 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26574 setText : function(str)
26576 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26579 setWeight : function(weight)
26582 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26585 this.weight = weight;
26587 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26590 setIcon : function(icon)
26593 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26596 this.faicon = icon;
26598 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26619 * @class Roo.bootstrap.UploadCropbox
26620 * @extends Roo.bootstrap.Component
26621 * Bootstrap UploadCropbox class
26622 * @cfg {String} emptyText show when image has been loaded
26623 * @cfg {String} rotateNotify show when image too small to rotate
26624 * @cfg {Number} errorTimeout default 3000
26625 * @cfg {Number} minWidth default 300
26626 * @cfg {Number} minHeight default 300
26627 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26628 * @cfg {Boolean} isDocument (true|false) default false
26629 * @cfg {String} url action url
26630 * @cfg {String} paramName default 'imageUpload'
26631 * @cfg {String} method default POST
26632 * @cfg {Boolean} loadMask (true|false) default true
26633 * @cfg {Boolean} loadingText default 'Loading...'
26636 * Create a new UploadCropbox
26637 * @param {Object} config The config object
26640 Roo.bootstrap.UploadCropbox = function(config){
26641 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26645 * @event beforeselectfile
26646 * Fire before select file
26647 * @param {Roo.bootstrap.UploadCropbox} this
26649 "beforeselectfile" : true,
26652 * Fire after initEvent
26653 * @param {Roo.bootstrap.UploadCropbox} this
26658 * Fire after initEvent
26659 * @param {Roo.bootstrap.UploadCropbox} this
26660 * @param {String} data
26665 * Fire when preparing the file data
26666 * @param {Roo.bootstrap.UploadCropbox} this
26667 * @param {Object} file
26672 * Fire when get exception
26673 * @param {Roo.bootstrap.UploadCropbox} this
26674 * @param {XMLHttpRequest} xhr
26676 "exception" : true,
26678 * @event beforeloadcanvas
26679 * Fire before load the canvas
26680 * @param {Roo.bootstrap.UploadCropbox} this
26681 * @param {String} src
26683 "beforeloadcanvas" : true,
26686 * Fire when trash image
26687 * @param {Roo.bootstrap.UploadCropbox} this
26692 * Fire when download the image
26693 * @param {Roo.bootstrap.UploadCropbox} this
26697 * @event footerbuttonclick
26698 * Fire when footerbuttonclick
26699 * @param {Roo.bootstrap.UploadCropbox} this
26700 * @param {String} type
26702 "footerbuttonclick" : true,
26706 * @param {Roo.bootstrap.UploadCropbox} this
26711 * Fire when rotate the image
26712 * @param {Roo.bootstrap.UploadCropbox} this
26713 * @param {String} pos
26718 * Fire when inspect the file
26719 * @param {Roo.bootstrap.UploadCropbox} this
26720 * @param {Object} file
26725 * Fire when xhr upload the file
26726 * @param {Roo.bootstrap.UploadCropbox} this
26727 * @param {Object} data
26732 * Fire when arrange the file data
26733 * @param {Roo.bootstrap.UploadCropbox} this
26734 * @param {Object} formData
26739 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26742 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26744 emptyText : 'Click to upload image',
26745 rotateNotify : 'Image is too small to rotate',
26746 errorTimeout : 3000,
26760 cropType : 'image/jpeg',
26762 canvasLoaded : false,
26763 isDocument : false,
26765 paramName : 'imageUpload',
26767 loadingText : 'Loading...',
26770 getAutoCreate : function()
26774 cls : 'roo-upload-cropbox',
26778 cls : 'roo-upload-cropbox-selector',
26783 cls : 'roo-upload-cropbox-body',
26784 style : 'cursor:pointer',
26788 cls : 'roo-upload-cropbox-preview'
26792 cls : 'roo-upload-cropbox-thumb'
26796 cls : 'roo-upload-cropbox-empty-notify',
26797 html : this.emptyText
26801 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26802 html : this.rotateNotify
26808 cls : 'roo-upload-cropbox-footer',
26811 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26821 onRender : function(ct, position)
26823 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26825 if (this.buttons.length) {
26827 Roo.each(this.buttons, function(bb) {
26829 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26831 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26837 this.maskEl = this.el;
26841 initEvents : function()
26843 this.urlAPI = (window.createObjectURL && window) ||
26844 (window.URL && URL.revokeObjectURL && URL) ||
26845 (window.webkitURL && webkitURL);
26847 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26848 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26850 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26851 this.selectorEl.hide();
26853 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26854 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26856 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26857 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26858 this.thumbEl.hide();
26860 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26861 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26863 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26864 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26865 this.errorEl.hide();
26867 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26868 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26869 this.footerEl.hide();
26871 this.setThumbBoxSize();
26877 this.fireEvent('initial', this);
26884 window.addEventListener("resize", function() { _this.resize(); } );
26886 this.bodyEl.on('click', this.beforeSelectFile, this);
26889 this.bodyEl.on('touchstart', this.onTouchStart, this);
26890 this.bodyEl.on('touchmove', this.onTouchMove, this);
26891 this.bodyEl.on('touchend', this.onTouchEnd, this);
26895 this.bodyEl.on('mousedown', this.onMouseDown, this);
26896 this.bodyEl.on('mousemove', this.onMouseMove, this);
26897 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26898 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26899 Roo.get(document).on('mouseup', this.onMouseUp, this);
26902 this.selectorEl.on('change', this.onFileSelected, this);
26908 this.baseScale = 1;
26910 this.baseRotate = 1;
26911 this.dragable = false;
26912 this.pinching = false;
26915 this.cropData = false;
26916 this.notifyEl.dom.innerHTML = this.emptyText;
26918 this.selectorEl.dom.value = '';
26922 resize : function()
26924 if(this.fireEvent('resize', this) != false){
26925 this.setThumbBoxPosition();
26926 this.setCanvasPosition();
26930 onFooterButtonClick : function(e, el, o, type)
26933 case 'rotate-left' :
26934 this.onRotateLeft(e);
26936 case 'rotate-right' :
26937 this.onRotateRight(e);
26940 this.beforeSelectFile(e);
26955 this.fireEvent('footerbuttonclick', this, type);
26958 beforeSelectFile : function(e)
26960 e.preventDefault();
26962 if(this.fireEvent('beforeselectfile', this) != false){
26963 this.selectorEl.dom.click();
26967 onFileSelected : function(e)
26969 e.preventDefault();
26971 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26975 var file = this.selectorEl.dom.files[0];
26977 if(this.fireEvent('inspect', this, file) != false){
26978 this.prepare(file);
26983 trash : function(e)
26985 this.fireEvent('trash', this);
26988 download : function(e)
26990 this.fireEvent('download', this);
26993 loadCanvas : function(src)
26995 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26999 this.imageEl = document.createElement('img');
27003 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27005 this.imageEl.src = src;
27009 onLoadCanvas : function()
27011 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27012 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27014 this.bodyEl.un('click', this.beforeSelectFile, this);
27016 this.notifyEl.hide();
27017 this.thumbEl.show();
27018 this.footerEl.show();
27020 this.baseRotateLevel();
27022 if(this.isDocument){
27023 this.setThumbBoxSize();
27026 this.setThumbBoxPosition();
27028 this.baseScaleLevel();
27034 this.canvasLoaded = true;
27037 this.maskEl.unmask();
27042 setCanvasPosition : function()
27044 if(!this.canvasEl){
27048 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27049 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27051 this.previewEl.setLeft(pw);
27052 this.previewEl.setTop(ph);
27056 onMouseDown : function(e)
27060 this.dragable = true;
27061 this.pinching = false;
27063 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27064 this.dragable = false;
27068 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27069 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27073 onMouseMove : function(e)
27077 if(!this.canvasLoaded){
27081 if (!this.dragable){
27085 var minX = Math.ceil(this.thumbEl.getLeft(true));
27086 var minY = Math.ceil(this.thumbEl.getTop(true));
27088 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27089 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27091 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27092 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27094 x = x - this.mouseX;
27095 y = y - this.mouseY;
27097 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27098 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27100 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27101 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27103 this.previewEl.setLeft(bgX);
27104 this.previewEl.setTop(bgY);
27106 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27107 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27110 onMouseUp : function(e)
27114 this.dragable = false;
27117 onMouseWheel : function(e)
27121 this.startScale = this.scale;
27123 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27125 if(!this.zoomable()){
27126 this.scale = this.startScale;
27135 zoomable : function()
27137 var minScale = this.thumbEl.getWidth() / this.minWidth;
27139 if(this.minWidth < this.minHeight){
27140 minScale = this.thumbEl.getHeight() / this.minHeight;
27143 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27144 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27148 (this.rotate == 0 || this.rotate == 180) &&
27150 width > this.imageEl.OriginWidth ||
27151 height > this.imageEl.OriginHeight ||
27152 (width < this.minWidth && height < this.minHeight)
27160 (this.rotate == 90 || this.rotate == 270) &&
27162 width > this.imageEl.OriginWidth ||
27163 height > this.imageEl.OriginHeight ||
27164 (width < this.minHeight && height < this.minWidth)
27171 !this.isDocument &&
27172 (this.rotate == 0 || this.rotate == 180) &&
27174 width < this.minWidth ||
27175 width > this.imageEl.OriginWidth ||
27176 height < this.minHeight ||
27177 height > this.imageEl.OriginHeight
27184 !this.isDocument &&
27185 (this.rotate == 90 || this.rotate == 270) &&
27187 width < this.minHeight ||
27188 width > this.imageEl.OriginWidth ||
27189 height < this.minWidth ||
27190 height > this.imageEl.OriginHeight
27200 onRotateLeft : function(e)
27202 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27204 var minScale = this.thumbEl.getWidth() / this.minWidth;
27206 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27207 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27209 this.startScale = this.scale;
27211 while (this.getScaleLevel() < minScale){
27213 this.scale = this.scale + 1;
27215 if(!this.zoomable()){
27220 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27221 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27226 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27233 this.scale = this.startScale;
27235 this.onRotateFail();
27240 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27242 if(this.isDocument){
27243 this.setThumbBoxSize();
27244 this.setThumbBoxPosition();
27245 this.setCanvasPosition();
27250 this.fireEvent('rotate', this, 'left');
27254 onRotateRight : function(e)
27256 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27258 var minScale = this.thumbEl.getWidth() / this.minWidth;
27260 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27261 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27263 this.startScale = this.scale;
27265 while (this.getScaleLevel() < minScale){
27267 this.scale = this.scale + 1;
27269 if(!this.zoomable()){
27274 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27275 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27280 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27287 this.scale = this.startScale;
27289 this.onRotateFail();
27294 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27296 if(this.isDocument){
27297 this.setThumbBoxSize();
27298 this.setThumbBoxPosition();
27299 this.setCanvasPosition();
27304 this.fireEvent('rotate', this, 'right');
27307 onRotateFail : function()
27309 this.errorEl.show(true);
27313 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27318 this.previewEl.dom.innerHTML = '';
27320 var canvasEl = document.createElement("canvas");
27322 var contextEl = canvasEl.getContext("2d");
27324 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27325 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27326 var center = this.imageEl.OriginWidth / 2;
27328 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27329 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27330 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27331 center = this.imageEl.OriginHeight / 2;
27334 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27336 contextEl.translate(center, center);
27337 contextEl.rotate(this.rotate * Math.PI / 180);
27339 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27341 this.canvasEl = document.createElement("canvas");
27343 this.contextEl = this.canvasEl.getContext("2d");
27345 switch (this.rotate) {
27348 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27349 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27351 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27356 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27357 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27359 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27360 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);
27364 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27369 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27370 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27372 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27373 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);
27377 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);
27382 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27383 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27385 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27386 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27390 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);
27397 this.previewEl.appendChild(this.canvasEl);
27399 this.setCanvasPosition();
27404 if(!this.canvasLoaded){
27408 var imageCanvas = document.createElement("canvas");
27410 var imageContext = imageCanvas.getContext("2d");
27412 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27413 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27415 var center = imageCanvas.width / 2;
27417 imageContext.translate(center, center);
27419 imageContext.rotate(this.rotate * Math.PI / 180);
27421 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27423 var canvas = document.createElement("canvas");
27425 var context = canvas.getContext("2d");
27427 canvas.width = this.minWidth;
27428 canvas.height = this.minHeight;
27430 switch (this.rotate) {
27433 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27434 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27436 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27437 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27439 var targetWidth = this.minWidth - 2 * x;
27440 var targetHeight = this.minHeight - 2 * y;
27444 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27445 scale = targetWidth / width;
27448 if(x > 0 && y == 0){
27449 scale = targetHeight / height;
27452 if(x > 0 && y > 0){
27453 scale = targetWidth / width;
27455 if(width < height){
27456 scale = targetHeight / height;
27460 context.scale(scale, scale);
27462 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27463 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27465 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27466 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27468 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27473 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27474 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27476 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27477 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27479 var targetWidth = this.minWidth - 2 * x;
27480 var targetHeight = this.minHeight - 2 * y;
27484 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27485 scale = targetWidth / width;
27488 if(x > 0 && y == 0){
27489 scale = targetHeight / height;
27492 if(x > 0 && y > 0){
27493 scale = targetWidth / width;
27495 if(width < height){
27496 scale = targetHeight / height;
27500 context.scale(scale, scale);
27502 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27503 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27505 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27506 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27508 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27510 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27515 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27516 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27518 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27519 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27521 var targetWidth = this.minWidth - 2 * x;
27522 var targetHeight = this.minHeight - 2 * y;
27526 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27527 scale = targetWidth / width;
27530 if(x > 0 && y == 0){
27531 scale = targetHeight / height;
27534 if(x > 0 && y > 0){
27535 scale = targetWidth / width;
27537 if(width < height){
27538 scale = targetHeight / height;
27542 context.scale(scale, scale);
27544 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27545 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27547 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27548 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27550 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27551 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27553 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27558 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27559 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27561 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27562 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27564 var targetWidth = this.minWidth - 2 * x;
27565 var targetHeight = this.minHeight - 2 * y;
27569 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27570 scale = targetWidth / width;
27573 if(x > 0 && y == 0){
27574 scale = targetHeight / height;
27577 if(x > 0 && y > 0){
27578 scale = targetWidth / width;
27580 if(width < height){
27581 scale = targetHeight / height;
27585 context.scale(scale, scale);
27587 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27588 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27590 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27591 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27593 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27595 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27602 this.cropData = canvas.toDataURL(this.cropType);
27604 if(this.fireEvent('crop', this, this.cropData) !== false){
27605 this.process(this.file, this.cropData);
27612 setThumbBoxSize : function()
27616 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27617 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27618 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27620 this.minWidth = width;
27621 this.minHeight = height;
27623 if(this.rotate == 90 || this.rotate == 270){
27624 this.minWidth = height;
27625 this.minHeight = width;
27630 width = Math.ceil(this.minWidth * height / this.minHeight);
27632 if(this.minWidth > this.minHeight){
27634 height = Math.ceil(this.minHeight * width / this.minWidth);
27637 this.thumbEl.setStyle({
27638 width : width + 'px',
27639 height : height + 'px'
27646 setThumbBoxPosition : function()
27648 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27649 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27651 this.thumbEl.setLeft(x);
27652 this.thumbEl.setTop(y);
27656 baseRotateLevel : function()
27658 this.baseRotate = 1;
27661 typeof(this.exif) != 'undefined' &&
27662 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27663 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27665 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27668 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27672 baseScaleLevel : function()
27676 if(this.isDocument){
27678 if(this.baseRotate == 6 || this.baseRotate == 8){
27680 height = this.thumbEl.getHeight();
27681 this.baseScale = height / this.imageEl.OriginWidth;
27683 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27684 width = this.thumbEl.getWidth();
27685 this.baseScale = width / this.imageEl.OriginHeight;
27691 height = this.thumbEl.getHeight();
27692 this.baseScale = height / this.imageEl.OriginHeight;
27694 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27695 width = this.thumbEl.getWidth();
27696 this.baseScale = width / this.imageEl.OriginWidth;
27702 if(this.baseRotate == 6 || this.baseRotate == 8){
27704 width = this.thumbEl.getHeight();
27705 this.baseScale = width / this.imageEl.OriginHeight;
27707 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27708 height = this.thumbEl.getWidth();
27709 this.baseScale = height / this.imageEl.OriginHeight;
27712 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27713 height = this.thumbEl.getWidth();
27714 this.baseScale = height / this.imageEl.OriginHeight;
27716 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27717 width = this.thumbEl.getHeight();
27718 this.baseScale = width / this.imageEl.OriginWidth;
27725 width = this.thumbEl.getWidth();
27726 this.baseScale = width / this.imageEl.OriginWidth;
27728 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27729 height = this.thumbEl.getHeight();
27730 this.baseScale = height / this.imageEl.OriginHeight;
27733 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27735 height = this.thumbEl.getHeight();
27736 this.baseScale = height / this.imageEl.OriginHeight;
27738 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27739 width = this.thumbEl.getWidth();
27740 this.baseScale = width / this.imageEl.OriginWidth;
27748 getScaleLevel : function()
27750 return this.baseScale * Math.pow(1.1, this.scale);
27753 onTouchStart : function(e)
27755 if(!this.canvasLoaded){
27756 this.beforeSelectFile(e);
27760 var touches = e.browserEvent.touches;
27766 if(touches.length == 1){
27767 this.onMouseDown(e);
27771 if(touches.length != 2){
27777 for(var i = 0, finger; finger = touches[i]; i++){
27778 coords.push(finger.pageX, finger.pageY);
27781 var x = Math.pow(coords[0] - coords[2], 2);
27782 var y = Math.pow(coords[1] - coords[3], 2);
27784 this.startDistance = Math.sqrt(x + y);
27786 this.startScale = this.scale;
27788 this.pinching = true;
27789 this.dragable = false;
27793 onTouchMove : function(e)
27795 if(!this.pinching && !this.dragable){
27799 var touches = e.browserEvent.touches;
27806 this.onMouseMove(e);
27812 for(var i = 0, finger; finger = touches[i]; i++){
27813 coords.push(finger.pageX, finger.pageY);
27816 var x = Math.pow(coords[0] - coords[2], 2);
27817 var y = Math.pow(coords[1] - coords[3], 2);
27819 this.endDistance = Math.sqrt(x + y);
27821 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27823 if(!this.zoomable()){
27824 this.scale = this.startScale;
27832 onTouchEnd : function(e)
27834 this.pinching = false;
27835 this.dragable = false;
27839 process : function(file, crop)
27842 this.maskEl.mask(this.loadingText);
27845 this.xhr = new XMLHttpRequest();
27847 file.xhr = this.xhr;
27849 this.xhr.open(this.method, this.url, true);
27852 "Accept": "application/json",
27853 "Cache-Control": "no-cache",
27854 "X-Requested-With": "XMLHttpRequest"
27857 for (var headerName in headers) {
27858 var headerValue = headers[headerName];
27860 this.xhr.setRequestHeader(headerName, headerValue);
27866 this.xhr.onload = function()
27868 _this.xhrOnLoad(_this.xhr);
27871 this.xhr.onerror = function()
27873 _this.xhrOnError(_this.xhr);
27876 var formData = new FormData();
27878 formData.append('returnHTML', 'NO');
27881 formData.append('crop', crop);
27884 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27885 formData.append(this.paramName, file, file.name);
27888 if(typeof(file.filename) != 'undefined'){
27889 formData.append('filename', file.filename);
27892 if(typeof(file.mimetype) != 'undefined'){
27893 formData.append('mimetype', file.mimetype);
27896 if(this.fireEvent('arrange', this, formData) != false){
27897 this.xhr.send(formData);
27901 xhrOnLoad : function(xhr)
27904 this.maskEl.unmask();
27907 if (xhr.readyState !== 4) {
27908 this.fireEvent('exception', this, xhr);
27912 var response = Roo.decode(xhr.responseText);
27914 if(!response.success){
27915 this.fireEvent('exception', this, xhr);
27919 var response = Roo.decode(xhr.responseText);
27921 this.fireEvent('upload', this, response);
27925 xhrOnError : function()
27928 this.maskEl.unmask();
27931 Roo.log('xhr on error');
27933 var response = Roo.decode(xhr.responseText);
27939 prepare : function(file)
27942 this.maskEl.mask(this.loadingText);
27948 if(typeof(file) === 'string'){
27949 this.loadCanvas(file);
27953 if(!file || !this.urlAPI){
27958 this.cropType = file.type;
27962 if(this.fireEvent('prepare', this, this.file) != false){
27964 var reader = new FileReader();
27966 reader.onload = function (e) {
27967 if (e.target.error) {
27968 Roo.log(e.target.error);
27972 var buffer = e.target.result,
27973 dataView = new DataView(buffer),
27975 maxOffset = dataView.byteLength - 4,
27979 if (dataView.getUint16(0) === 0xffd8) {
27980 while (offset < maxOffset) {
27981 markerBytes = dataView.getUint16(offset);
27983 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27984 markerLength = dataView.getUint16(offset + 2) + 2;
27985 if (offset + markerLength > dataView.byteLength) {
27986 Roo.log('Invalid meta data: Invalid segment size.');
27990 if(markerBytes == 0xffe1){
27991 _this.parseExifData(
27998 offset += markerLength;
28008 var url = _this.urlAPI.createObjectURL(_this.file);
28010 _this.loadCanvas(url);
28015 reader.readAsArrayBuffer(this.file);
28021 parseExifData : function(dataView, offset, length)
28023 var tiffOffset = offset + 10,
28027 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28028 // No Exif data, might be XMP data instead
28032 // Check for the ASCII code for "Exif" (0x45786966):
28033 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28034 // No Exif data, might be XMP data instead
28037 if (tiffOffset + 8 > dataView.byteLength) {
28038 Roo.log('Invalid Exif data: Invalid segment size.');
28041 // Check for the two null bytes:
28042 if (dataView.getUint16(offset + 8) !== 0x0000) {
28043 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28046 // Check the byte alignment:
28047 switch (dataView.getUint16(tiffOffset)) {
28049 littleEndian = true;
28052 littleEndian = false;
28055 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28058 // Check for the TIFF tag marker (0x002A):
28059 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28060 Roo.log('Invalid Exif data: Missing TIFF marker.');
28063 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28064 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28066 this.parseExifTags(
28069 tiffOffset + dirOffset,
28074 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28079 if (dirOffset + 6 > dataView.byteLength) {
28080 Roo.log('Invalid Exif data: Invalid directory offset.');
28083 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28084 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28085 if (dirEndOffset + 4 > dataView.byteLength) {
28086 Roo.log('Invalid Exif data: Invalid directory size.');
28089 for (i = 0; i < tagsNumber; i += 1) {
28093 dirOffset + 2 + 12 * i, // tag offset
28097 // Return the offset to the next directory:
28098 return dataView.getUint32(dirEndOffset, littleEndian);
28101 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28103 var tag = dataView.getUint16(offset, littleEndian);
28105 this.exif[tag] = this.getExifValue(
28109 dataView.getUint16(offset + 2, littleEndian), // tag type
28110 dataView.getUint32(offset + 4, littleEndian), // tag length
28115 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28117 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28126 Roo.log('Invalid Exif data: Invalid tag type.');
28130 tagSize = tagType.size * length;
28131 // Determine if the value is contained in the dataOffset bytes,
28132 // or if the value at the dataOffset is a pointer to the actual data:
28133 dataOffset = tagSize > 4 ?
28134 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28135 if (dataOffset + tagSize > dataView.byteLength) {
28136 Roo.log('Invalid Exif data: Invalid data offset.');
28139 if (length === 1) {
28140 return tagType.getValue(dataView, dataOffset, littleEndian);
28143 for (i = 0; i < length; i += 1) {
28144 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28147 if (tagType.ascii) {
28149 // Concatenate the chars:
28150 for (i = 0; i < values.length; i += 1) {
28152 // Ignore the terminating NULL byte(s):
28153 if (c === '\u0000') {
28165 Roo.apply(Roo.bootstrap.UploadCropbox, {
28167 'Orientation': 0x0112
28171 1: 0, //'top-left',
28173 3: 180, //'bottom-right',
28174 // 4: 'bottom-left',
28176 6: 90, //'right-top',
28177 // 7: 'right-bottom',
28178 8: 270 //'left-bottom'
28182 // byte, 8-bit unsigned int:
28184 getValue: function (dataView, dataOffset) {
28185 return dataView.getUint8(dataOffset);
28189 // ascii, 8-bit byte:
28191 getValue: function (dataView, dataOffset) {
28192 return String.fromCharCode(dataView.getUint8(dataOffset));
28197 // short, 16 bit int:
28199 getValue: function (dataView, dataOffset, littleEndian) {
28200 return dataView.getUint16(dataOffset, littleEndian);
28204 // long, 32 bit int:
28206 getValue: function (dataView, dataOffset, littleEndian) {
28207 return dataView.getUint32(dataOffset, littleEndian);
28211 // rational = two long values, first is numerator, second is denominator:
28213 getValue: function (dataView, dataOffset, littleEndian) {
28214 return dataView.getUint32(dataOffset, littleEndian) /
28215 dataView.getUint32(dataOffset + 4, littleEndian);
28219 // slong, 32 bit signed int:
28221 getValue: function (dataView, dataOffset, littleEndian) {
28222 return dataView.getInt32(dataOffset, littleEndian);
28226 // srational, two slongs, first is numerator, second is denominator:
28228 getValue: function (dataView, dataOffset, littleEndian) {
28229 return dataView.getInt32(dataOffset, littleEndian) /
28230 dataView.getInt32(dataOffset + 4, littleEndian);
28240 cls : 'btn-group roo-upload-cropbox-rotate-left',
28241 action : 'rotate-left',
28245 cls : 'btn btn-default',
28246 html : '<i class="fa fa-undo"></i>'
28252 cls : 'btn-group roo-upload-cropbox-picture',
28253 action : 'picture',
28257 cls : 'btn btn-default',
28258 html : '<i class="fa fa-picture-o"></i>'
28264 cls : 'btn-group roo-upload-cropbox-rotate-right',
28265 action : 'rotate-right',
28269 cls : 'btn btn-default',
28270 html : '<i class="fa fa-repeat"></i>'
28278 cls : 'btn-group roo-upload-cropbox-rotate-left',
28279 action : 'rotate-left',
28283 cls : 'btn btn-default',
28284 html : '<i class="fa fa-undo"></i>'
28290 cls : 'btn-group roo-upload-cropbox-download',
28291 action : 'download',
28295 cls : 'btn btn-default',
28296 html : '<i class="fa fa-download"></i>'
28302 cls : 'btn-group roo-upload-cropbox-crop',
28307 cls : 'btn btn-default',
28308 html : '<i class="fa fa-crop"></i>'
28314 cls : 'btn-group roo-upload-cropbox-trash',
28319 cls : 'btn btn-default',
28320 html : '<i class="fa fa-trash"></i>'
28326 cls : 'btn-group roo-upload-cropbox-rotate-right',
28327 action : 'rotate-right',
28331 cls : 'btn btn-default',
28332 html : '<i class="fa fa-repeat"></i>'
28340 cls : 'btn-group roo-upload-cropbox-rotate-left',
28341 action : 'rotate-left',
28345 cls : 'btn btn-default',
28346 html : '<i class="fa fa-undo"></i>'
28352 cls : 'btn-group roo-upload-cropbox-rotate-right',
28353 action : 'rotate-right',
28357 cls : 'btn btn-default',
28358 html : '<i class="fa fa-repeat"></i>'
28371 * @class Roo.bootstrap.DocumentManager
28372 * @extends Roo.bootstrap.Component
28373 * Bootstrap DocumentManager class
28374 * @cfg {String} paramName default 'imageUpload'
28375 * @cfg {String} toolTipName default 'filename'
28376 * @cfg {String} method default POST
28377 * @cfg {String} url action url
28378 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28379 * @cfg {Boolean} multiple multiple upload default true
28380 * @cfg {Number} thumbSize default 300
28381 * @cfg {String} fieldLabel
28382 * @cfg {Number} labelWidth default 4
28383 * @cfg {String} labelAlign (left|top) default left
28384 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28385 * @cfg {Number} labellg set the width of label (1-12)
28386 * @cfg {Number} labelmd set the width of label (1-12)
28387 * @cfg {Number} labelsm set the width of label (1-12)
28388 * @cfg {Number} labelxs set the width of label (1-12)
28391 * Create a new DocumentManager
28392 * @param {Object} config The config object
28395 Roo.bootstrap.DocumentManager = function(config){
28396 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28399 this.delegates = [];
28404 * Fire when initial the DocumentManager
28405 * @param {Roo.bootstrap.DocumentManager} this
28410 * inspect selected file
28411 * @param {Roo.bootstrap.DocumentManager} this
28412 * @param {File} file
28417 * Fire when xhr load exception
28418 * @param {Roo.bootstrap.DocumentManager} this
28419 * @param {XMLHttpRequest} xhr
28421 "exception" : true,
28423 * @event afterupload
28424 * Fire when xhr load exception
28425 * @param {Roo.bootstrap.DocumentManager} this
28426 * @param {XMLHttpRequest} xhr
28428 "afterupload" : true,
28431 * prepare the form data
28432 * @param {Roo.bootstrap.DocumentManager} this
28433 * @param {Object} formData
28438 * Fire when remove the file
28439 * @param {Roo.bootstrap.DocumentManager} this
28440 * @param {Object} file
28445 * Fire after refresh the file
28446 * @param {Roo.bootstrap.DocumentManager} this
28451 * Fire after click the image
28452 * @param {Roo.bootstrap.DocumentManager} this
28453 * @param {Object} file
28458 * Fire when upload a image and editable set to true
28459 * @param {Roo.bootstrap.DocumentManager} this
28460 * @param {Object} file
28464 * @event beforeselectfile
28465 * Fire before select file
28466 * @param {Roo.bootstrap.DocumentManager} this
28468 "beforeselectfile" : true,
28471 * Fire before process file
28472 * @param {Roo.bootstrap.DocumentManager} this
28473 * @param {Object} file
28477 * @event previewrendered
28478 * Fire when preview rendered
28479 * @param {Roo.bootstrap.DocumentManager} this
28480 * @param {Object} file
28482 "previewrendered" : true
28487 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28496 paramName : 'imageUpload',
28497 toolTipName : 'filename',
28500 labelAlign : 'left',
28510 getAutoCreate : function()
28512 var managerWidget = {
28514 cls : 'roo-document-manager',
28518 cls : 'roo-document-manager-selector',
28523 cls : 'roo-document-manager-uploader',
28527 cls : 'roo-document-manager-upload-btn',
28528 html : '<i class="fa fa-plus"></i>'
28539 cls : 'column col-md-12',
28544 if(this.fieldLabel.length){
28549 cls : 'column col-md-12',
28550 html : this.fieldLabel
28554 cls : 'column col-md-12',
28559 if(this.labelAlign == 'left'){
28564 html : this.fieldLabel
28573 if(this.labelWidth > 12){
28574 content[0].style = "width: " + this.labelWidth + 'px';
28577 if(this.labelWidth < 13 && this.labelmd == 0){
28578 this.labelmd = this.labelWidth;
28581 if(this.labellg > 0){
28582 content[0].cls += ' col-lg-' + this.labellg;
28583 content[1].cls += ' col-lg-' + (12 - this.labellg);
28586 if(this.labelmd > 0){
28587 content[0].cls += ' col-md-' + this.labelmd;
28588 content[1].cls += ' col-md-' + (12 - this.labelmd);
28591 if(this.labelsm > 0){
28592 content[0].cls += ' col-sm-' + this.labelsm;
28593 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28596 if(this.labelxs > 0){
28597 content[0].cls += ' col-xs-' + this.labelxs;
28598 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28606 cls : 'row clearfix',
28614 initEvents : function()
28616 this.managerEl = this.el.select('.roo-document-manager', true).first();
28617 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28619 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28620 this.selectorEl.hide();
28623 this.selectorEl.attr('multiple', 'multiple');
28626 this.selectorEl.on('change', this.onFileSelected, this);
28628 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28629 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28631 this.uploader.on('click', this.onUploaderClick, this);
28633 this.renderProgressDialog();
28637 window.addEventListener("resize", function() { _this.refresh(); } );
28639 this.fireEvent('initial', this);
28642 renderProgressDialog : function()
28646 this.progressDialog = new Roo.bootstrap.Modal({
28647 cls : 'roo-document-manager-progress-dialog',
28648 allow_close : false,
28658 btnclick : function() {
28659 _this.uploadCancel();
28665 this.progressDialog.render(Roo.get(document.body));
28667 this.progress = new Roo.bootstrap.Progress({
28668 cls : 'roo-document-manager-progress',
28673 this.progress.render(this.progressDialog.getChildContainer());
28675 this.progressBar = new Roo.bootstrap.ProgressBar({
28676 cls : 'roo-document-manager-progress-bar',
28679 aria_valuemax : 12,
28683 this.progressBar.render(this.progress.getChildContainer());
28686 onUploaderClick : function(e)
28688 e.preventDefault();
28690 if(this.fireEvent('beforeselectfile', this) != false){
28691 this.selectorEl.dom.click();
28696 onFileSelected : function(e)
28698 e.preventDefault();
28700 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28704 Roo.each(this.selectorEl.dom.files, function(file){
28705 if(this.fireEvent('inspect', this, file) != false){
28706 this.files.push(file);
28716 this.selectorEl.dom.value = '';
28718 if(!this.files || !this.files.length){
28722 if(this.boxes > 0 && this.files.length > this.boxes){
28723 this.files = this.files.slice(0, this.boxes);
28726 this.uploader.show();
28728 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28729 this.uploader.hide();
28738 Roo.each(this.files, function(file){
28740 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28741 var f = this.renderPreview(file);
28746 if(file.type.indexOf('image') != -1){
28747 this.delegates.push(
28749 _this.process(file);
28750 }).createDelegate(this)
28758 _this.process(file);
28759 }).createDelegate(this)
28764 this.files = files;
28766 this.delegates = this.delegates.concat(docs);
28768 if(!this.delegates.length){
28773 this.progressBar.aria_valuemax = this.delegates.length;
28780 arrange : function()
28782 if(!this.delegates.length){
28783 this.progressDialog.hide();
28788 var delegate = this.delegates.shift();
28790 this.progressDialog.show();
28792 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28794 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28799 refresh : function()
28801 this.uploader.show();
28803 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28804 this.uploader.hide();
28807 Roo.isTouch ? this.closable(false) : this.closable(true);
28809 this.fireEvent('refresh', this);
28812 onRemove : function(e, el, o)
28814 e.preventDefault();
28816 this.fireEvent('remove', this, o);
28820 remove : function(o)
28824 Roo.each(this.files, function(file){
28825 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28834 this.files = files;
28841 Roo.each(this.files, function(file){
28846 file.target.remove();
28855 onClick : function(e, el, o)
28857 e.preventDefault();
28859 this.fireEvent('click', this, o);
28863 closable : function(closable)
28865 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28867 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28879 xhrOnLoad : function(xhr)
28881 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28885 if (xhr.readyState !== 4) {
28887 this.fireEvent('exception', this, xhr);
28891 var response = Roo.decode(xhr.responseText);
28893 if(!response.success){
28895 this.fireEvent('exception', this, xhr);
28899 var file = this.renderPreview(response.data);
28901 this.files.push(file);
28905 this.fireEvent('afterupload', this, xhr);
28909 xhrOnError : function(xhr)
28911 Roo.log('xhr on error');
28913 var response = Roo.decode(xhr.responseText);
28920 process : function(file)
28922 if(this.fireEvent('process', this, file) !== false){
28923 if(this.editable && file.type.indexOf('image') != -1){
28924 this.fireEvent('edit', this, file);
28928 this.uploadStart(file, false);
28935 uploadStart : function(file, crop)
28937 this.xhr = new XMLHttpRequest();
28939 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28944 file.xhr = this.xhr;
28946 this.managerEl.createChild({
28948 cls : 'roo-document-manager-loading',
28952 tooltip : file.name,
28953 cls : 'roo-document-manager-thumb',
28954 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28960 this.xhr.open(this.method, this.url, true);
28963 "Accept": "application/json",
28964 "Cache-Control": "no-cache",
28965 "X-Requested-With": "XMLHttpRequest"
28968 for (var headerName in headers) {
28969 var headerValue = headers[headerName];
28971 this.xhr.setRequestHeader(headerName, headerValue);
28977 this.xhr.onload = function()
28979 _this.xhrOnLoad(_this.xhr);
28982 this.xhr.onerror = function()
28984 _this.xhrOnError(_this.xhr);
28987 var formData = new FormData();
28989 formData.append('returnHTML', 'NO');
28992 formData.append('crop', crop);
28995 formData.append(this.paramName, file, file.name);
29002 if(this.fireEvent('prepare', this, formData, options) != false){
29004 if(options.manually){
29008 this.xhr.send(formData);
29012 this.uploadCancel();
29015 uploadCancel : function()
29021 this.delegates = [];
29023 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29030 renderPreview : function(file)
29032 if(typeof(file.target) != 'undefined' && file.target){
29036 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29038 var previewEl = this.managerEl.createChild({
29040 cls : 'roo-document-manager-preview',
29044 tooltip : file[this.toolTipName],
29045 cls : 'roo-document-manager-thumb',
29046 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29051 html : '<i class="fa fa-times-circle"></i>'
29056 var close = previewEl.select('button.close', true).first();
29058 close.on('click', this.onRemove, this, file);
29060 file.target = previewEl;
29062 var image = previewEl.select('img', true).first();
29066 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29068 image.on('click', this.onClick, this, file);
29070 this.fireEvent('previewrendered', this, file);
29076 onPreviewLoad : function(file, image)
29078 if(typeof(file.target) == 'undefined' || !file.target){
29082 var width = image.dom.naturalWidth || image.dom.width;
29083 var height = image.dom.naturalHeight || image.dom.height;
29085 if(width > height){
29086 file.target.addClass('wide');
29090 file.target.addClass('tall');
29095 uploadFromSource : function(file, crop)
29097 this.xhr = new XMLHttpRequest();
29099 this.managerEl.createChild({
29101 cls : 'roo-document-manager-loading',
29105 tooltip : file.name,
29106 cls : 'roo-document-manager-thumb',
29107 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29113 this.xhr.open(this.method, this.url, true);
29116 "Accept": "application/json",
29117 "Cache-Control": "no-cache",
29118 "X-Requested-With": "XMLHttpRequest"
29121 for (var headerName in headers) {
29122 var headerValue = headers[headerName];
29124 this.xhr.setRequestHeader(headerName, headerValue);
29130 this.xhr.onload = function()
29132 _this.xhrOnLoad(_this.xhr);
29135 this.xhr.onerror = function()
29137 _this.xhrOnError(_this.xhr);
29140 var formData = new FormData();
29142 formData.append('returnHTML', 'NO');
29144 formData.append('crop', crop);
29146 if(typeof(file.filename) != 'undefined'){
29147 formData.append('filename', file.filename);
29150 if(typeof(file.mimetype) != 'undefined'){
29151 formData.append('mimetype', file.mimetype);
29156 if(this.fireEvent('prepare', this, formData) != false){
29157 this.xhr.send(formData);
29167 * @class Roo.bootstrap.DocumentViewer
29168 * @extends Roo.bootstrap.Component
29169 * Bootstrap DocumentViewer class
29170 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29171 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29174 * Create a new DocumentViewer
29175 * @param {Object} config The config object
29178 Roo.bootstrap.DocumentViewer = function(config){
29179 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29184 * Fire after initEvent
29185 * @param {Roo.bootstrap.DocumentViewer} this
29191 * @param {Roo.bootstrap.DocumentViewer} this
29196 * Fire after download button
29197 * @param {Roo.bootstrap.DocumentViewer} this
29202 * Fire after trash button
29203 * @param {Roo.bootstrap.DocumentViewer} this
29210 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29212 showDownload : true,
29216 getAutoCreate : function()
29220 cls : 'roo-document-viewer',
29224 cls : 'roo-document-viewer-body',
29228 cls : 'roo-document-viewer-thumb',
29232 cls : 'roo-document-viewer-image'
29240 cls : 'roo-document-viewer-footer',
29243 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29247 cls : 'btn-group roo-document-viewer-download',
29251 cls : 'btn btn-default',
29252 html : '<i class="fa fa-download"></i>'
29258 cls : 'btn-group roo-document-viewer-trash',
29262 cls : 'btn btn-default',
29263 html : '<i class="fa fa-trash"></i>'
29276 initEvents : function()
29278 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29279 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29281 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29282 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29284 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29285 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29287 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29288 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29290 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29291 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29293 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29294 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29296 this.bodyEl.on('click', this.onClick, this);
29297 this.downloadBtn.on('click', this.onDownload, this);
29298 this.trashBtn.on('click', this.onTrash, this);
29300 this.downloadBtn.hide();
29301 this.trashBtn.hide();
29303 if(this.showDownload){
29304 this.downloadBtn.show();
29307 if(this.showTrash){
29308 this.trashBtn.show();
29311 if(!this.showDownload && !this.showTrash) {
29312 this.footerEl.hide();
29317 initial : function()
29319 this.fireEvent('initial', this);
29323 onClick : function(e)
29325 e.preventDefault();
29327 this.fireEvent('click', this);
29330 onDownload : function(e)
29332 e.preventDefault();
29334 this.fireEvent('download', this);
29337 onTrash : function(e)
29339 e.preventDefault();
29341 this.fireEvent('trash', this);
29353 * @class Roo.bootstrap.NavProgressBar
29354 * @extends Roo.bootstrap.Component
29355 * Bootstrap NavProgressBar class
29358 * Create a new nav progress bar
29359 * @param {Object} config The config object
29362 Roo.bootstrap.NavProgressBar = function(config){
29363 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29365 this.bullets = this.bullets || [];
29367 // Roo.bootstrap.NavProgressBar.register(this);
29371 * Fires when the active item changes
29372 * @param {Roo.bootstrap.NavProgressBar} this
29373 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29374 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29381 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29386 getAutoCreate : function()
29388 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29392 cls : 'roo-navigation-bar-group',
29396 cls : 'roo-navigation-top-bar'
29400 cls : 'roo-navigation-bullets-bar',
29404 cls : 'roo-navigation-bar'
29411 cls : 'roo-navigation-bottom-bar'
29421 initEvents: function()
29426 onRender : function(ct, position)
29428 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29430 if(this.bullets.length){
29431 Roo.each(this.bullets, function(b){
29440 addItem : function(cfg)
29442 var item = new Roo.bootstrap.NavProgressItem(cfg);
29444 item.parentId = this.id;
29445 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29448 var top = new Roo.bootstrap.Element({
29450 cls : 'roo-navigation-bar-text'
29453 var bottom = new Roo.bootstrap.Element({
29455 cls : 'roo-navigation-bar-text'
29458 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29459 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29461 var topText = new Roo.bootstrap.Element({
29463 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29466 var bottomText = new Roo.bootstrap.Element({
29468 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29471 topText.onRender(top.el, null);
29472 bottomText.onRender(bottom.el, null);
29475 item.bottomEl = bottom;
29478 this.barItems.push(item);
29483 getActive : function()
29485 var active = false;
29487 Roo.each(this.barItems, function(v){
29489 if (!v.isActive()) {
29501 setActiveItem : function(item)
29505 Roo.each(this.barItems, function(v){
29506 if (v.rid == item.rid) {
29510 if (v.isActive()) {
29511 v.setActive(false);
29516 item.setActive(true);
29518 this.fireEvent('changed', this, item, prev);
29521 getBarItem: function(rid)
29525 Roo.each(this.barItems, function(e) {
29526 if (e.rid != rid) {
29537 indexOfItem : function(item)
29541 Roo.each(this.barItems, function(v, i){
29543 if (v.rid != item.rid) {
29554 setActiveNext : function()
29556 var i = this.indexOfItem(this.getActive());
29558 if (i > this.barItems.length) {
29562 this.setActiveItem(this.barItems[i+1]);
29565 setActivePrev : function()
29567 var i = this.indexOfItem(this.getActive());
29573 this.setActiveItem(this.barItems[i-1]);
29576 format : function()
29578 if(!this.barItems.length){
29582 var width = 100 / this.barItems.length;
29584 Roo.each(this.barItems, function(i){
29585 i.el.setStyle('width', width + '%');
29586 i.topEl.el.setStyle('width', width + '%');
29587 i.bottomEl.el.setStyle('width', width + '%');
29596 * Nav Progress Item
29601 * @class Roo.bootstrap.NavProgressItem
29602 * @extends Roo.bootstrap.Component
29603 * Bootstrap NavProgressItem class
29604 * @cfg {String} rid the reference id
29605 * @cfg {Boolean} active (true|false) Is item active default false
29606 * @cfg {Boolean} disabled (true|false) Is item active default false
29607 * @cfg {String} html
29608 * @cfg {String} position (top|bottom) text position default bottom
29609 * @cfg {String} icon show icon instead of number
29612 * Create a new NavProgressItem
29613 * @param {Object} config The config object
29615 Roo.bootstrap.NavProgressItem = function(config){
29616 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29621 * The raw click event for the entire grid.
29622 * @param {Roo.bootstrap.NavProgressItem} this
29623 * @param {Roo.EventObject} e
29630 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29636 position : 'bottom',
29639 getAutoCreate : function()
29641 var iconCls = 'roo-navigation-bar-item-icon';
29643 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29647 cls: 'roo-navigation-bar-item',
29657 cfg.cls += ' active';
29660 cfg.cls += ' disabled';
29666 disable : function()
29668 this.setDisabled(true);
29671 enable : function()
29673 this.setDisabled(false);
29676 initEvents: function()
29678 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29680 this.iconEl.on('click', this.onClick, this);
29683 onClick : function(e)
29685 e.preventDefault();
29691 if(this.fireEvent('click', this, e) === false){
29695 this.parent().setActiveItem(this);
29698 isActive: function ()
29700 return this.active;
29703 setActive : function(state)
29705 if(this.active == state){
29709 this.active = state;
29712 this.el.addClass('active');
29716 this.el.removeClass('active');
29721 setDisabled : function(state)
29723 if(this.disabled == state){
29727 this.disabled = state;
29730 this.el.addClass('disabled');
29734 this.el.removeClass('disabled');
29737 tooltipEl : function()
29739 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29752 * @class Roo.bootstrap.FieldLabel
29753 * @extends Roo.bootstrap.Component
29754 * Bootstrap FieldLabel class
29755 * @cfg {String} html contents of the element
29756 * @cfg {String} tag tag of the element default label
29757 * @cfg {String} cls class of the element
29758 * @cfg {String} target label target
29759 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29760 * @cfg {String} invalidClass default "text-warning"
29761 * @cfg {String} validClass default "text-success"
29762 * @cfg {String} iconTooltip default "This field is required"
29763 * @cfg {String} indicatorpos (left|right) default left
29766 * Create a new FieldLabel
29767 * @param {Object} config The config object
29770 Roo.bootstrap.FieldLabel = function(config){
29771 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29776 * Fires after the field has been marked as invalid.
29777 * @param {Roo.form.FieldLabel} this
29778 * @param {String} msg The validation message
29783 * Fires after the field has been validated with no errors.
29784 * @param {Roo.form.FieldLabel} this
29790 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29797 invalidClass : 'has-warning',
29798 validClass : 'has-success',
29799 iconTooltip : 'This field is required',
29800 indicatorpos : 'left',
29802 getAutoCreate : function(){
29806 cls : 'roo-bootstrap-field-label ' + this.cls,
29811 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29812 tooltip : this.iconTooltip
29821 if(this.indicatorpos == 'right'){
29824 cls : 'roo-bootstrap-field-label ' + this.cls,
29833 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29834 tooltip : this.iconTooltip
29843 initEvents: function()
29845 Roo.bootstrap.Element.superclass.initEvents.call(this);
29847 this.indicator = this.indicatorEl();
29849 if(this.indicator){
29850 this.indicator.removeClass('visible');
29851 this.indicator.addClass('invisible');
29854 Roo.bootstrap.FieldLabel.register(this);
29857 indicatorEl : function()
29859 var indicator = this.el.select('i.roo-required-indicator',true).first();
29870 * Mark this field as valid
29872 markValid : function()
29874 if(this.indicator){
29875 this.indicator.removeClass('visible');
29876 this.indicator.addClass('invisible');
29879 this.el.removeClass(this.invalidClass);
29881 this.el.addClass(this.validClass);
29883 this.fireEvent('valid', this);
29887 * Mark this field as invalid
29888 * @param {String} msg The validation message
29890 markInvalid : function(msg)
29892 if(this.indicator){
29893 this.indicator.removeClass('invisible');
29894 this.indicator.addClass('visible');
29897 this.el.removeClass(this.validClass);
29899 this.el.addClass(this.invalidClass);
29901 this.fireEvent('invalid', this, msg);
29907 Roo.apply(Roo.bootstrap.FieldLabel, {
29912 * register a FieldLabel Group
29913 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29915 register : function(label)
29917 if(this.groups.hasOwnProperty(label.target)){
29921 this.groups[label.target] = label;
29925 * fetch a FieldLabel Group based on the target
29926 * @param {string} target
29927 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29929 get: function(target) {
29930 if (typeof(this.groups[target]) == 'undefined') {
29934 return this.groups[target] ;
29943 * page DateSplitField.
29949 * @class Roo.bootstrap.DateSplitField
29950 * @extends Roo.bootstrap.Component
29951 * Bootstrap DateSplitField class
29952 * @cfg {string} fieldLabel - the label associated
29953 * @cfg {Number} labelWidth set the width of label (0-12)
29954 * @cfg {String} labelAlign (top|left)
29955 * @cfg {Boolean} dayAllowBlank (true|false) default false
29956 * @cfg {Boolean} monthAllowBlank (true|false) default false
29957 * @cfg {Boolean} yearAllowBlank (true|false) default false
29958 * @cfg {string} dayPlaceholder
29959 * @cfg {string} monthPlaceholder
29960 * @cfg {string} yearPlaceholder
29961 * @cfg {string} dayFormat default 'd'
29962 * @cfg {string} monthFormat default 'm'
29963 * @cfg {string} yearFormat default 'Y'
29964 * @cfg {Number} labellg set the width of label (1-12)
29965 * @cfg {Number} labelmd set the width of label (1-12)
29966 * @cfg {Number} labelsm set the width of label (1-12)
29967 * @cfg {Number} labelxs set the width of label (1-12)
29971 * Create a new DateSplitField
29972 * @param {Object} config The config object
29975 Roo.bootstrap.DateSplitField = function(config){
29976 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29982 * getting the data of years
29983 * @param {Roo.bootstrap.DateSplitField} this
29984 * @param {Object} years
29989 * getting the data of days
29990 * @param {Roo.bootstrap.DateSplitField} this
29991 * @param {Object} days
29996 * Fires after the field has been marked as invalid.
29997 * @param {Roo.form.Field} this
29998 * @param {String} msg The validation message
30003 * Fires after the field has been validated with no errors.
30004 * @param {Roo.form.Field} this
30010 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30013 labelAlign : 'top',
30015 dayAllowBlank : false,
30016 monthAllowBlank : false,
30017 yearAllowBlank : false,
30018 dayPlaceholder : '',
30019 monthPlaceholder : '',
30020 yearPlaceholder : '',
30024 isFormField : true,
30030 getAutoCreate : function()
30034 cls : 'row roo-date-split-field-group',
30039 cls : 'form-hidden-field roo-date-split-field-group-value',
30045 var labelCls = 'col-md-12';
30046 var contentCls = 'col-md-4';
30048 if(this.fieldLabel){
30052 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30056 html : this.fieldLabel
30061 if(this.labelAlign == 'left'){
30063 if(this.labelWidth > 12){
30064 label.style = "width: " + this.labelWidth + 'px';
30067 if(this.labelWidth < 13 && this.labelmd == 0){
30068 this.labelmd = this.labelWidth;
30071 if(this.labellg > 0){
30072 labelCls = ' col-lg-' + this.labellg;
30073 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30076 if(this.labelmd > 0){
30077 labelCls = ' col-md-' + this.labelmd;
30078 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30081 if(this.labelsm > 0){
30082 labelCls = ' col-sm-' + this.labelsm;
30083 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30086 if(this.labelxs > 0){
30087 labelCls = ' col-xs-' + this.labelxs;
30088 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30092 label.cls += ' ' + labelCls;
30094 cfg.cn.push(label);
30097 Roo.each(['day', 'month', 'year'], function(t){
30100 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30107 inputEl: function ()
30109 return this.el.select('.roo-date-split-field-group-value', true).first();
30112 onRender : function(ct, position)
30116 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30118 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30120 this.dayField = new Roo.bootstrap.ComboBox({
30121 allowBlank : this.dayAllowBlank,
30122 alwaysQuery : true,
30123 displayField : 'value',
30126 forceSelection : true,
30128 placeholder : this.dayPlaceholder,
30129 selectOnFocus : true,
30130 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30131 triggerAction : 'all',
30133 valueField : 'value',
30134 store : new Roo.data.SimpleStore({
30135 data : (function() {
30137 _this.fireEvent('days', _this, days);
30140 fields : [ 'value' ]
30143 select : function (_self, record, index)
30145 _this.setValue(_this.getValue());
30150 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30152 this.monthField = new Roo.bootstrap.MonthField({
30153 after : '<i class=\"fa fa-calendar\"></i>',
30154 allowBlank : this.monthAllowBlank,
30155 placeholder : this.monthPlaceholder,
30158 render : function (_self)
30160 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30161 e.preventDefault();
30165 select : function (_self, oldvalue, newvalue)
30167 _this.setValue(_this.getValue());
30172 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30174 this.yearField = new Roo.bootstrap.ComboBox({
30175 allowBlank : this.yearAllowBlank,
30176 alwaysQuery : true,
30177 displayField : 'value',
30180 forceSelection : true,
30182 placeholder : this.yearPlaceholder,
30183 selectOnFocus : true,
30184 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30185 triggerAction : 'all',
30187 valueField : 'value',
30188 store : new Roo.data.SimpleStore({
30189 data : (function() {
30191 _this.fireEvent('years', _this, years);
30194 fields : [ 'value' ]
30197 select : function (_self, record, index)
30199 _this.setValue(_this.getValue());
30204 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30207 setValue : function(v, format)
30209 this.inputEl.dom.value = v;
30211 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30213 var d = Date.parseDate(v, f);
30220 this.setDay(d.format(this.dayFormat));
30221 this.setMonth(d.format(this.monthFormat));
30222 this.setYear(d.format(this.yearFormat));
30229 setDay : function(v)
30231 this.dayField.setValue(v);
30232 this.inputEl.dom.value = this.getValue();
30237 setMonth : function(v)
30239 this.monthField.setValue(v, true);
30240 this.inputEl.dom.value = this.getValue();
30245 setYear : function(v)
30247 this.yearField.setValue(v);
30248 this.inputEl.dom.value = this.getValue();
30253 getDay : function()
30255 return this.dayField.getValue();
30258 getMonth : function()
30260 return this.monthField.getValue();
30263 getYear : function()
30265 return this.yearField.getValue();
30268 getValue : function()
30270 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30272 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30282 this.inputEl.dom.value = '';
30287 validate : function()
30289 var d = this.dayField.validate();
30290 var m = this.monthField.validate();
30291 var y = this.yearField.validate();
30296 (!this.dayAllowBlank && !d) ||
30297 (!this.monthAllowBlank && !m) ||
30298 (!this.yearAllowBlank && !y)
30303 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30312 this.markInvalid();
30317 markValid : function()
30320 var label = this.el.select('label', true).first();
30321 var icon = this.el.select('i.fa-star', true).first();
30327 this.fireEvent('valid', this);
30331 * Mark this field as invalid
30332 * @param {String} msg The validation message
30334 markInvalid : function(msg)
30337 var label = this.el.select('label', true).first();
30338 var icon = this.el.select('i.fa-star', true).first();
30340 if(label && !icon){
30341 this.el.select('.roo-date-split-field-label', true).createChild({
30343 cls : 'text-danger fa fa-lg fa-star',
30344 tooltip : 'This field is required',
30345 style : 'margin-right:5px;'
30349 this.fireEvent('invalid', this, msg);
30352 clearInvalid : function()
30354 var label = this.el.select('label', true).first();
30355 var icon = this.el.select('i.fa-star', true).first();
30361 this.fireEvent('valid', this);
30364 getName: function()
30374 * http://masonry.desandro.com
30376 * The idea is to render all the bricks based on vertical width...
30378 * The original code extends 'outlayer' - we might need to use that....
30384 * @class Roo.bootstrap.LayoutMasonry
30385 * @extends Roo.bootstrap.Component
30386 * Bootstrap Layout Masonry class
30389 * Create a new Element
30390 * @param {Object} config The config object
30393 Roo.bootstrap.LayoutMasonry = function(config){
30395 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30399 Roo.bootstrap.LayoutMasonry.register(this);
30405 * Fire after layout the items
30406 * @param {Roo.bootstrap.LayoutMasonry} this
30407 * @param {Roo.EventObject} e
30414 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30417 * @cfg {Boolean} isLayoutInstant = no animation?
30419 isLayoutInstant : false, // needed?
30422 * @cfg {Number} boxWidth width of the columns
30427 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30432 * @cfg {Number} padWidth padding below box..
30437 * @cfg {Number} gutter gutter width..
30442 * @cfg {Number} maxCols maximum number of columns
30448 * @cfg {Boolean} isAutoInitial defalut true
30450 isAutoInitial : true,
30455 * @cfg {Boolean} isHorizontal defalut false
30457 isHorizontal : false,
30459 currentSize : null,
30465 bricks: null, //CompositeElement
30469 _isLayoutInited : false,
30471 // isAlternative : false, // only use for vertical layout...
30474 * @cfg {Number} alternativePadWidth padding below box..
30476 alternativePadWidth : 50,
30478 selectedBrick : [],
30480 getAutoCreate : function(){
30482 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30486 cls: 'blog-masonary-wrapper ' + this.cls,
30488 cls : 'mas-boxes masonary'
30495 getChildContainer: function( )
30497 if (this.boxesEl) {
30498 return this.boxesEl;
30501 this.boxesEl = this.el.select('.mas-boxes').first();
30503 return this.boxesEl;
30507 initEvents : function()
30511 if(this.isAutoInitial){
30512 Roo.log('hook children rendered');
30513 this.on('childrenrendered', function() {
30514 Roo.log('children rendered');
30520 initial : function()
30522 this.selectedBrick = [];
30524 this.currentSize = this.el.getBox(true);
30526 Roo.EventManager.onWindowResize(this.resize, this);
30528 if(!this.isAutoInitial){
30536 //this.layout.defer(500,this);
30540 resize : function()
30542 var cs = this.el.getBox(true);
30545 this.currentSize.width == cs.width &&
30546 this.currentSize.x == cs.x &&
30547 this.currentSize.height == cs.height &&
30548 this.currentSize.y == cs.y
30550 Roo.log("no change in with or X or Y");
30554 this.currentSize = cs;
30560 layout : function()
30562 this._resetLayout();
30564 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30566 this.layoutItems( isInstant );
30568 this._isLayoutInited = true;
30570 this.fireEvent('layout', this);
30574 _resetLayout : function()
30576 if(this.isHorizontal){
30577 this.horizontalMeasureColumns();
30581 this.verticalMeasureColumns();
30585 verticalMeasureColumns : function()
30587 this.getContainerWidth();
30589 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30590 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30594 var boxWidth = this.boxWidth + this.padWidth;
30596 if(this.containerWidth < this.boxWidth){
30597 boxWidth = this.containerWidth
30600 var containerWidth = this.containerWidth;
30602 var cols = Math.floor(containerWidth / boxWidth);
30604 this.cols = Math.max( cols, 1 );
30606 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30608 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30610 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30612 this.colWidth = boxWidth + avail - this.padWidth;
30614 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30615 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30618 horizontalMeasureColumns : function()
30620 this.getContainerWidth();
30622 var boxWidth = this.boxWidth;
30624 if(this.containerWidth < boxWidth){
30625 boxWidth = this.containerWidth;
30628 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30630 this.el.setHeight(boxWidth);
30634 getContainerWidth : function()
30636 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30639 layoutItems : function( isInstant )
30641 Roo.log(this.bricks);
30643 var items = Roo.apply([], this.bricks);
30645 if(this.isHorizontal){
30646 this._horizontalLayoutItems( items , isInstant );
30650 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30651 // this._verticalAlternativeLayoutItems( items , isInstant );
30655 this._verticalLayoutItems( items , isInstant );
30659 _verticalLayoutItems : function ( items , isInstant)
30661 if ( !items || !items.length ) {
30666 ['xs', 'xs', 'xs', 'tall'],
30667 ['xs', 'xs', 'tall'],
30668 ['xs', 'xs', 'sm'],
30669 ['xs', 'xs', 'xs'],
30675 ['sm', 'xs', 'xs'],
30679 ['tall', 'xs', 'xs', 'xs'],
30680 ['tall', 'xs', 'xs'],
30692 Roo.each(items, function(item, k){
30694 switch (item.size) {
30695 // these layouts take up a full box,
30706 boxes.push([item]);
30729 var filterPattern = function(box, length)
30737 var pattern = box.slice(0, length);
30741 Roo.each(pattern, function(i){
30742 format.push(i.size);
30745 Roo.each(standard, function(s){
30747 if(String(s) != String(format)){
30756 if(!match && length == 1){
30761 filterPattern(box, length - 1);
30765 queue.push(pattern);
30767 box = box.slice(length, box.length);
30769 filterPattern(box, 4);
30775 Roo.each(boxes, function(box, k){
30781 if(box.length == 1){
30786 filterPattern(box, 4);
30790 this._processVerticalLayoutQueue( queue, isInstant );
30794 // _verticalAlternativeLayoutItems : function( items , isInstant )
30796 // if ( !items || !items.length ) {
30800 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30804 _horizontalLayoutItems : function ( items , isInstant)
30806 if ( !items || !items.length || items.length < 3) {
30812 var eItems = items.slice(0, 3);
30814 items = items.slice(3, items.length);
30817 ['xs', 'xs', 'xs', 'wide'],
30818 ['xs', 'xs', 'wide'],
30819 ['xs', 'xs', 'sm'],
30820 ['xs', 'xs', 'xs'],
30826 ['sm', 'xs', 'xs'],
30830 ['wide', 'xs', 'xs', 'xs'],
30831 ['wide', 'xs', 'xs'],
30844 Roo.each(items, function(item, k){
30846 switch (item.size) {
30857 boxes.push([item]);
30881 var filterPattern = function(box, length)
30889 var pattern = box.slice(0, length);
30893 Roo.each(pattern, function(i){
30894 format.push(i.size);
30897 Roo.each(standard, function(s){
30899 if(String(s) != String(format)){
30908 if(!match && length == 1){
30913 filterPattern(box, length - 1);
30917 queue.push(pattern);
30919 box = box.slice(length, box.length);
30921 filterPattern(box, 4);
30927 Roo.each(boxes, function(box, k){
30933 if(box.length == 1){
30938 filterPattern(box, 4);
30945 var pos = this.el.getBox(true);
30949 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30951 var hit_end = false;
30953 Roo.each(queue, function(box){
30957 Roo.each(box, function(b){
30959 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30969 Roo.each(box, function(b){
30971 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30974 mx = Math.max(mx, b.x);
30978 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30982 Roo.each(box, function(b){
30984 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30998 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31001 /** Sets position of item in DOM
31002 * @param {Element} item
31003 * @param {Number} x - horizontal position
31004 * @param {Number} y - vertical position
31005 * @param {Boolean} isInstant - disables transitions
31007 _processVerticalLayoutQueue : function( queue, isInstant )
31009 var pos = this.el.getBox(true);
31014 for (var i = 0; i < this.cols; i++){
31018 Roo.each(queue, function(box, k){
31020 var col = k % this.cols;
31022 Roo.each(box, function(b,kk){
31024 b.el.position('absolute');
31026 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31027 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31029 if(b.size == 'md-left' || b.size == 'md-right'){
31030 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31031 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31034 b.el.setWidth(width);
31035 b.el.setHeight(height);
31037 b.el.select('iframe',true).setSize(width,height);
31041 for (var i = 0; i < this.cols; i++){
31043 if(maxY[i] < maxY[col]){
31048 col = Math.min(col, i);
31052 x = pos.x + col * (this.colWidth + this.padWidth);
31056 var positions = [];
31058 switch (box.length){
31060 positions = this.getVerticalOneBoxColPositions(x, y, box);
31063 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31066 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31069 positions = this.getVerticalFourBoxColPositions(x, y, box);
31075 Roo.each(box, function(b,kk){
31077 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31079 var sz = b.el.getSize();
31081 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31089 for (var i = 0; i < this.cols; i++){
31090 mY = Math.max(mY, maxY[i]);
31093 this.el.setHeight(mY - pos.y);
31097 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31099 // var pos = this.el.getBox(true);
31102 // var maxX = pos.right;
31104 // var maxHeight = 0;
31106 // Roo.each(items, function(item, k){
31110 // item.el.position('absolute');
31112 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31114 // item.el.setWidth(width);
31116 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31118 // item.el.setHeight(height);
31121 // item.el.setXY([x, y], isInstant ? false : true);
31123 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31126 // y = y + height + this.alternativePadWidth;
31128 // maxHeight = maxHeight + height + this.alternativePadWidth;
31132 // this.el.setHeight(maxHeight);
31136 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31138 var pos = this.el.getBox(true);
31143 var maxX = pos.right;
31145 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31147 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31149 Roo.each(queue, function(box, k){
31151 Roo.each(box, function(b, kk){
31153 b.el.position('absolute');
31155 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31156 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31158 if(b.size == 'md-left' || b.size == 'md-right'){
31159 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31160 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31163 b.el.setWidth(width);
31164 b.el.setHeight(height);
31172 var positions = [];
31174 switch (box.length){
31176 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31179 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31182 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31185 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31191 Roo.each(box, function(b,kk){
31193 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31195 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31203 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31205 Roo.each(eItems, function(b,k){
31207 b.size = (k == 0) ? 'sm' : 'xs';
31208 b.x = (k == 0) ? 2 : 1;
31209 b.y = (k == 0) ? 2 : 1;
31211 b.el.position('absolute');
31213 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31215 b.el.setWidth(width);
31217 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31219 b.el.setHeight(height);
31223 var positions = [];
31226 x : maxX - this.unitWidth * 2 - this.gutter,
31231 x : maxX - this.unitWidth,
31232 y : minY + (this.unitWidth + this.gutter) * 2
31236 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31240 Roo.each(eItems, function(b,k){
31242 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31248 getVerticalOneBoxColPositions : function(x, y, box)
31252 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31254 if(box[0].size == 'md-left'){
31258 if(box[0].size == 'md-right'){
31263 x : x + (this.unitWidth + this.gutter) * rand,
31270 getVerticalTwoBoxColPositions : function(x, y, box)
31274 if(box[0].size == 'xs'){
31278 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31282 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31296 x : x + (this.unitWidth + this.gutter) * 2,
31297 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31304 getVerticalThreeBoxColPositions : function(x, y, box)
31308 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31316 x : x + (this.unitWidth + this.gutter) * 1,
31321 x : x + (this.unitWidth + this.gutter) * 2,
31329 if(box[0].size == 'xs' && box[1].size == 'xs'){
31338 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31342 x : x + (this.unitWidth + this.gutter) * 1,
31356 x : x + (this.unitWidth + this.gutter) * 2,
31361 x : x + (this.unitWidth + this.gutter) * 2,
31362 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31369 getVerticalFourBoxColPositions : function(x, y, box)
31373 if(box[0].size == 'xs'){
31382 y : y + (this.unitHeight + this.gutter) * 1
31387 y : y + (this.unitHeight + this.gutter) * 2
31391 x : x + (this.unitWidth + this.gutter) * 1,
31405 x : x + (this.unitWidth + this.gutter) * 2,
31410 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31411 y : y + (this.unitHeight + this.gutter) * 1
31415 x : x + (this.unitWidth + this.gutter) * 2,
31416 y : y + (this.unitWidth + this.gutter) * 2
31423 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31427 if(box[0].size == 'md-left'){
31429 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31436 if(box[0].size == 'md-right'){
31438 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31439 y : minY + (this.unitWidth + this.gutter) * 1
31445 var rand = Math.floor(Math.random() * (4 - box[0].y));
31448 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31449 y : minY + (this.unitWidth + this.gutter) * rand
31456 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31460 if(box[0].size == 'xs'){
31463 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31468 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31469 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31477 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31482 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31483 y : minY + (this.unitWidth + this.gutter) * 2
31490 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31494 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31497 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31502 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31503 y : minY + (this.unitWidth + this.gutter) * 1
31507 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31508 y : minY + (this.unitWidth + this.gutter) * 2
31515 if(box[0].size == 'xs' && box[1].size == 'xs'){
31518 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31523 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31528 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31529 y : minY + (this.unitWidth + this.gutter) * 1
31537 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31542 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31543 y : minY + (this.unitWidth + this.gutter) * 2
31547 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31548 y : minY + (this.unitWidth + this.gutter) * 2
31555 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31559 if(box[0].size == 'xs'){
31562 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31567 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31572 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),
31577 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31578 y : minY + (this.unitWidth + this.gutter) * 1
31586 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31591 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31592 y : minY + (this.unitWidth + this.gutter) * 2
31596 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31597 y : minY + (this.unitWidth + this.gutter) * 2
31601 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),
31602 y : minY + (this.unitWidth + this.gutter) * 2
31610 * remove a Masonry Brick
31611 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31613 removeBrick : function(brick_id)
31619 for (var i = 0; i<this.bricks.length; i++) {
31620 if (this.bricks[i].id == brick_id) {
31621 this.bricks.splice(i,1);
31622 this.el.dom.removeChild(Roo.get(brick_id).dom);
31629 * adds a Masonry Brick
31630 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31632 addBrick : function(cfg)
31634 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31635 //this.register(cn);
31636 cn.parentId = this.id;
31637 cn.onRender(this.el, null);
31642 * register a Masonry Brick
31643 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31646 register : function(brick)
31648 this.bricks.push(brick);
31649 brick.masonryId = this.id;
31653 * clear all the Masonry Brick
31655 clearAll : function()
31658 //this.getChildContainer().dom.innerHTML = "";
31659 this.el.dom.innerHTML = '';
31662 getSelected : function()
31664 if (!this.selectedBrick) {
31668 return this.selectedBrick;
31672 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31676 * register a Masonry Layout
31677 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31680 register : function(layout)
31682 this.groups[layout.id] = layout;
31685 * fetch a Masonry Layout based on the masonry layout ID
31686 * @param {string} the masonry layout to add
31687 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31690 get: function(layout_id) {
31691 if (typeof(this.groups[layout_id]) == 'undefined') {
31694 return this.groups[layout_id] ;
31706 * http://masonry.desandro.com
31708 * The idea is to render all the bricks based on vertical width...
31710 * The original code extends 'outlayer' - we might need to use that....
31716 * @class Roo.bootstrap.LayoutMasonryAuto
31717 * @extends Roo.bootstrap.Component
31718 * Bootstrap Layout Masonry class
31721 * Create a new Element
31722 * @param {Object} config The config object
31725 Roo.bootstrap.LayoutMasonryAuto = function(config){
31726 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31729 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31732 * @cfg {Boolean} isFitWidth - resize the width..
31734 isFitWidth : false, // options..
31736 * @cfg {Boolean} isOriginLeft = left align?
31738 isOriginLeft : true,
31740 * @cfg {Boolean} isOriginTop = top align?
31742 isOriginTop : false,
31744 * @cfg {Boolean} isLayoutInstant = no animation?
31746 isLayoutInstant : false, // needed?
31748 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31750 isResizingContainer : true,
31752 * @cfg {Number} columnWidth width of the columns
31758 * @cfg {Number} maxCols maximum number of columns
31763 * @cfg {Number} padHeight padding below box..
31769 * @cfg {Boolean} isAutoInitial defalut true
31772 isAutoInitial : true,
31778 initialColumnWidth : 0,
31779 currentSize : null,
31781 colYs : null, // array.
31788 bricks: null, //CompositeElement
31789 cols : 0, // array?
31790 // element : null, // wrapped now this.el
31791 _isLayoutInited : null,
31794 getAutoCreate : function(){
31798 cls: 'blog-masonary-wrapper ' + this.cls,
31800 cls : 'mas-boxes masonary'
31807 getChildContainer: function( )
31809 if (this.boxesEl) {
31810 return this.boxesEl;
31813 this.boxesEl = this.el.select('.mas-boxes').first();
31815 return this.boxesEl;
31819 initEvents : function()
31823 if(this.isAutoInitial){
31824 Roo.log('hook children rendered');
31825 this.on('childrenrendered', function() {
31826 Roo.log('children rendered');
31833 initial : function()
31835 this.reloadItems();
31837 this.currentSize = this.el.getBox(true);
31839 /// was window resize... - let's see if this works..
31840 Roo.EventManager.onWindowResize(this.resize, this);
31842 if(!this.isAutoInitial){
31847 this.layout.defer(500,this);
31850 reloadItems: function()
31852 this.bricks = this.el.select('.masonry-brick', true);
31854 this.bricks.each(function(b) {
31855 //Roo.log(b.getSize());
31856 if (!b.attr('originalwidth')) {
31857 b.attr('originalwidth', b.getSize().width);
31862 Roo.log(this.bricks.elements.length);
31865 resize : function()
31868 var cs = this.el.getBox(true);
31870 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31871 Roo.log("no change in with or X");
31874 this.currentSize = cs;
31878 layout : function()
31881 this._resetLayout();
31882 //this._manageStamps();
31884 // don't animate first layout
31885 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31886 this.layoutItems( isInstant );
31888 // flag for initalized
31889 this._isLayoutInited = true;
31892 layoutItems : function( isInstant )
31894 //var items = this._getItemsForLayout( this.items );
31895 // original code supports filtering layout items.. we just ignore it..
31897 this._layoutItems( this.bricks , isInstant );
31899 this._postLayout();
31901 _layoutItems : function ( items , isInstant)
31903 //this.fireEvent( 'layout', this, items );
31906 if ( !items || !items.elements.length ) {
31907 // no items, emit event with empty array
31912 items.each(function(item) {
31913 Roo.log("layout item");
31915 // get x/y object from method
31916 var position = this._getItemLayoutPosition( item );
31918 position.item = item;
31919 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31920 queue.push( position );
31923 this._processLayoutQueue( queue );
31925 /** Sets position of item in DOM
31926 * @param {Element} item
31927 * @param {Number} x - horizontal position
31928 * @param {Number} y - vertical position
31929 * @param {Boolean} isInstant - disables transitions
31931 _processLayoutQueue : function( queue )
31933 for ( var i=0, len = queue.length; i < len; i++ ) {
31934 var obj = queue[i];
31935 obj.item.position('absolute');
31936 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31942 * Any logic you want to do after each layout,
31943 * i.e. size the container
31945 _postLayout : function()
31947 this.resizeContainer();
31950 resizeContainer : function()
31952 if ( !this.isResizingContainer ) {
31955 var size = this._getContainerSize();
31957 this.el.setSize(size.width,size.height);
31958 this.boxesEl.setSize(size.width,size.height);
31964 _resetLayout : function()
31966 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31967 this.colWidth = this.el.getWidth();
31968 //this.gutter = this.el.getWidth();
31970 this.measureColumns();
31976 this.colYs.push( 0 );
31982 measureColumns : function()
31984 this.getContainerWidth();
31985 // if columnWidth is 0, default to outerWidth of first item
31986 if ( !this.columnWidth ) {
31987 var firstItem = this.bricks.first();
31988 Roo.log(firstItem);
31989 this.columnWidth = this.containerWidth;
31990 if (firstItem && firstItem.attr('originalwidth') ) {
31991 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31993 // columnWidth fall back to item of first element
31994 Roo.log("set column width?");
31995 this.initialColumnWidth = this.columnWidth ;
31997 // if first elem has no width, default to size of container
32002 if (this.initialColumnWidth) {
32003 this.columnWidth = this.initialColumnWidth;
32008 // column width is fixed at the top - however if container width get's smaller we should
32011 // this bit calcs how man columns..
32013 var columnWidth = this.columnWidth += this.gutter;
32015 // calculate columns
32016 var containerWidth = this.containerWidth + this.gutter;
32018 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32019 // fix rounding errors, typically with gutters
32020 var excess = columnWidth - containerWidth % columnWidth;
32023 // if overshoot is less than a pixel, round up, otherwise floor it
32024 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32025 cols = Math[ mathMethod ]( cols );
32026 this.cols = Math.max( cols, 1 );
32027 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32029 // padding positioning..
32030 var totalColWidth = this.cols * this.columnWidth;
32031 var padavail = this.containerWidth - totalColWidth;
32032 // so for 2 columns - we need 3 'pads'
32034 var padNeeded = (1+this.cols) * this.padWidth;
32036 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32038 this.columnWidth += padExtra
32039 //this.padWidth = Math.floor(padavail / ( this.cols));
32041 // adjust colum width so that padding is fixed??
32043 // we have 3 columns ... total = width * 3
32044 // we have X left over... that should be used by
32046 //if (this.expandC) {
32054 getContainerWidth : function()
32056 /* // container is parent if fit width
32057 var container = this.isFitWidth ? this.element.parentNode : this.element;
32058 // check that this.size and size are there
32059 // IE8 triggers resize on body size change, so they might not be
32061 var size = getSize( container ); //FIXME
32062 this.containerWidth = size && size.innerWidth; //FIXME
32065 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32069 _getItemLayoutPosition : function( item ) // what is item?
32071 // we resize the item to our columnWidth..
32073 item.setWidth(this.columnWidth);
32074 item.autoBoxAdjust = false;
32076 var sz = item.getSize();
32078 // how many columns does this brick span
32079 var remainder = this.containerWidth % this.columnWidth;
32081 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32082 // round if off by 1 pixel, otherwise use ceil
32083 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32084 colSpan = Math.min( colSpan, this.cols );
32086 // normally this should be '1' as we dont' currently allow multi width columns..
32088 var colGroup = this._getColGroup( colSpan );
32089 // get the minimum Y value from the columns
32090 var minimumY = Math.min.apply( Math, colGroup );
32091 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32093 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32095 // position the brick
32097 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32098 y: this.currentSize.y + minimumY + this.padHeight
32102 // apply setHeight to necessary columns
32103 var setHeight = minimumY + sz.height + this.padHeight;
32104 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32106 var setSpan = this.cols + 1 - colGroup.length;
32107 for ( var i = 0; i < setSpan; i++ ) {
32108 this.colYs[ shortColIndex + i ] = setHeight ;
32115 * @param {Number} colSpan - number of columns the element spans
32116 * @returns {Array} colGroup
32118 _getColGroup : function( colSpan )
32120 if ( colSpan < 2 ) {
32121 // if brick spans only one column, use all the column Ys
32126 // how many different places could this brick fit horizontally
32127 var groupCount = this.cols + 1 - colSpan;
32128 // for each group potential horizontal position
32129 for ( var i = 0; i < groupCount; i++ ) {
32130 // make an array of colY values for that one group
32131 var groupColYs = this.colYs.slice( i, i + colSpan );
32132 // and get the max value of the array
32133 colGroup[i] = Math.max.apply( Math, groupColYs );
32138 _manageStamp : function( stamp )
32140 var stampSize = stamp.getSize();
32141 var offset = stamp.getBox();
32142 // get the columns that this stamp affects
32143 var firstX = this.isOriginLeft ? offset.x : offset.right;
32144 var lastX = firstX + stampSize.width;
32145 var firstCol = Math.floor( firstX / this.columnWidth );
32146 firstCol = Math.max( 0, firstCol );
32148 var lastCol = Math.floor( lastX / this.columnWidth );
32149 // lastCol should not go over if multiple of columnWidth #425
32150 lastCol -= lastX % this.columnWidth ? 0 : 1;
32151 lastCol = Math.min( this.cols - 1, lastCol );
32153 // set colYs to bottom of the stamp
32154 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32157 for ( var i = firstCol; i <= lastCol; i++ ) {
32158 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32163 _getContainerSize : function()
32165 this.maxY = Math.max.apply( Math, this.colYs );
32170 if ( this.isFitWidth ) {
32171 size.width = this._getContainerFitWidth();
32177 _getContainerFitWidth : function()
32179 var unusedCols = 0;
32180 // count unused columns
32183 if ( this.colYs[i] !== 0 ) {
32188 // fit container to columns that have been used
32189 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32192 needsResizeLayout : function()
32194 var previousWidth = this.containerWidth;
32195 this.getContainerWidth();
32196 return previousWidth !== this.containerWidth;
32211 * @class Roo.bootstrap.MasonryBrick
32212 * @extends Roo.bootstrap.Component
32213 * Bootstrap MasonryBrick class
32216 * Create a new MasonryBrick
32217 * @param {Object} config The config object
32220 Roo.bootstrap.MasonryBrick = function(config){
32222 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32224 Roo.bootstrap.MasonryBrick.register(this);
32230 * When a MasonryBrick is clcik
32231 * @param {Roo.bootstrap.MasonryBrick} this
32232 * @param {Roo.EventObject} e
32238 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32241 * @cfg {String} title
32245 * @cfg {String} html
32249 * @cfg {String} bgimage
32253 * @cfg {String} videourl
32257 * @cfg {String} cls
32261 * @cfg {String} href
32265 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32270 * @cfg {String} placetitle (center|bottom)
32275 * @cfg {Boolean} isFitContainer defalut true
32277 isFitContainer : true,
32280 * @cfg {Boolean} preventDefault defalut false
32282 preventDefault : false,
32285 * @cfg {Boolean} inverse defalut false
32287 maskInverse : false,
32289 getAutoCreate : function()
32291 if(!this.isFitContainer){
32292 return this.getSplitAutoCreate();
32295 var cls = 'masonry-brick masonry-brick-full';
32297 if(this.href.length){
32298 cls += ' masonry-brick-link';
32301 if(this.bgimage.length){
32302 cls += ' masonry-brick-image';
32305 if(this.maskInverse){
32306 cls += ' mask-inverse';
32309 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32310 cls += ' enable-mask';
32314 cls += ' masonry-' + this.size + '-brick';
32317 if(this.placetitle.length){
32319 switch (this.placetitle) {
32321 cls += ' masonry-center-title';
32324 cls += ' masonry-bottom-title';
32331 if(!this.html.length && !this.bgimage.length){
32332 cls += ' masonry-center-title';
32335 if(!this.html.length && this.bgimage.length){
32336 cls += ' masonry-bottom-title';
32341 cls += ' ' + this.cls;
32345 tag: (this.href.length) ? 'a' : 'div',
32350 cls: 'masonry-brick-mask'
32354 cls: 'masonry-brick-paragraph',
32360 if(this.href.length){
32361 cfg.href = this.href;
32364 var cn = cfg.cn[1].cn;
32366 if(this.title.length){
32369 cls: 'masonry-brick-title',
32374 if(this.html.length){
32377 cls: 'masonry-brick-text',
32382 if (!this.title.length && !this.html.length) {
32383 cfg.cn[1].cls += ' hide';
32386 if(this.bgimage.length){
32389 cls: 'masonry-brick-image-view',
32394 if(this.videourl.length){
32395 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32396 // youtube support only?
32399 cls: 'masonry-brick-image-view',
32402 allowfullscreen : true
32410 getSplitAutoCreate : function()
32412 var cls = 'masonry-brick masonry-brick-split';
32414 if(this.href.length){
32415 cls += ' masonry-brick-link';
32418 if(this.bgimage.length){
32419 cls += ' masonry-brick-image';
32423 cls += ' masonry-' + this.size + '-brick';
32426 switch (this.placetitle) {
32428 cls += ' masonry-center-title';
32431 cls += ' masonry-bottom-title';
32434 if(!this.bgimage.length){
32435 cls += ' masonry-center-title';
32438 if(this.bgimage.length){
32439 cls += ' masonry-bottom-title';
32445 cls += ' ' + this.cls;
32449 tag: (this.href.length) ? 'a' : 'div',
32454 cls: 'masonry-brick-split-head',
32458 cls: 'masonry-brick-paragraph',
32465 cls: 'masonry-brick-split-body',
32471 if(this.href.length){
32472 cfg.href = this.href;
32475 if(this.title.length){
32476 cfg.cn[0].cn[0].cn.push({
32478 cls: 'masonry-brick-title',
32483 if(this.html.length){
32484 cfg.cn[1].cn.push({
32486 cls: 'masonry-brick-text',
32491 if(this.bgimage.length){
32492 cfg.cn[0].cn.push({
32494 cls: 'masonry-brick-image-view',
32499 if(this.videourl.length){
32500 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32501 // youtube support only?
32502 cfg.cn[0].cn.cn.push({
32504 cls: 'masonry-brick-image-view',
32507 allowfullscreen : true
32514 initEvents: function()
32516 switch (this.size) {
32549 this.el.on('touchstart', this.onTouchStart, this);
32550 this.el.on('touchmove', this.onTouchMove, this);
32551 this.el.on('touchend', this.onTouchEnd, this);
32552 this.el.on('contextmenu', this.onContextMenu, this);
32554 this.el.on('mouseenter' ,this.enter, this);
32555 this.el.on('mouseleave', this.leave, this);
32556 this.el.on('click', this.onClick, this);
32559 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32560 this.parent().bricks.push(this);
32565 onClick: function(e, el)
32567 var time = this.endTimer - this.startTimer;
32568 // Roo.log(e.preventDefault());
32571 e.preventDefault();
32576 if(!this.preventDefault){
32580 e.preventDefault();
32582 if (this.activcClass != '') {
32583 this.selectBrick();
32586 this.fireEvent('click', this);
32589 enter: function(e, el)
32591 e.preventDefault();
32593 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32597 if(this.bgimage.length && this.html.length){
32598 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32602 leave: function(e, el)
32604 e.preventDefault();
32606 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32610 if(this.bgimage.length && this.html.length){
32611 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32615 onTouchStart: function(e, el)
32617 // e.preventDefault();
32619 this.touchmoved = false;
32621 if(!this.isFitContainer){
32625 if(!this.bgimage.length || !this.html.length){
32629 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32631 this.timer = new Date().getTime();
32635 onTouchMove: function(e, el)
32637 this.touchmoved = true;
32640 onContextMenu : function(e,el)
32642 e.preventDefault();
32643 e.stopPropagation();
32647 onTouchEnd: function(e, el)
32649 // e.preventDefault();
32651 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32658 if(!this.bgimage.length || !this.html.length){
32660 if(this.href.length){
32661 window.location.href = this.href;
32667 if(!this.isFitContainer){
32671 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32673 window.location.href = this.href;
32676 //selection on single brick only
32677 selectBrick : function() {
32679 if (!this.parentId) {
32683 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32684 var index = m.selectedBrick.indexOf(this.id);
32687 m.selectedBrick.splice(index,1);
32688 this.el.removeClass(this.activeClass);
32692 for(var i = 0; i < m.selectedBrick.length; i++) {
32693 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32694 b.el.removeClass(b.activeClass);
32697 m.selectedBrick = [];
32699 m.selectedBrick.push(this.id);
32700 this.el.addClass(this.activeClass);
32706 Roo.apply(Roo.bootstrap.MasonryBrick, {
32709 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32711 * register a Masonry Brick
32712 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32715 register : function(brick)
32717 //this.groups[brick.id] = brick;
32718 this.groups.add(brick.id, brick);
32721 * fetch a masonry brick based on the masonry brick ID
32722 * @param {string} the masonry brick to add
32723 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32726 get: function(brick_id)
32728 // if (typeof(this.groups[brick_id]) == 'undefined') {
32731 // return this.groups[brick_id] ;
32733 if(this.groups.key(brick_id)) {
32734 return this.groups.key(brick_id);
32752 * @class Roo.bootstrap.Brick
32753 * @extends Roo.bootstrap.Component
32754 * Bootstrap Brick class
32757 * Create a new Brick
32758 * @param {Object} config The config object
32761 Roo.bootstrap.Brick = function(config){
32762 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32768 * When a Brick is click
32769 * @param {Roo.bootstrap.Brick} this
32770 * @param {Roo.EventObject} e
32776 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32779 * @cfg {String} title
32783 * @cfg {String} html
32787 * @cfg {String} bgimage
32791 * @cfg {String} cls
32795 * @cfg {String} href
32799 * @cfg {String} video
32803 * @cfg {Boolean} square
32807 getAutoCreate : function()
32809 var cls = 'roo-brick';
32811 if(this.href.length){
32812 cls += ' roo-brick-link';
32815 if(this.bgimage.length){
32816 cls += ' roo-brick-image';
32819 if(!this.html.length && !this.bgimage.length){
32820 cls += ' roo-brick-center-title';
32823 if(!this.html.length && this.bgimage.length){
32824 cls += ' roo-brick-bottom-title';
32828 cls += ' ' + this.cls;
32832 tag: (this.href.length) ? 'a' : 'div',
32837 cls: 'roo-brick-paragraph',
32843 if(this.href.length){
32844 cfg.href = this.href;
32847 var cn = cfg.cn[0].cn;
32849 if(this.title.length){
32852 cls: 'roo-brick-title',
32857 if(this.html.length){
32860 cls: 'roo-brick-text',
32867 if(this.bgimage.length){
32870 cls: 'roo-brick-image-view',
32878 initEvents: function()
32880 if(this.title.length || this.html.length){
32881 this.el.on('mouseenter' ,this.enter, this);
32882 this.el.on('mouseleave', this.leave, this);
32885 Roo.EventManager.onWindowResize(this.resize, this);
32887 if(this.bgimage.length){
32888 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32889 this.imageEl.on('load', this.onImageLoad, this);
32896 onImageLoad : function()
32901 resize : function()
32903 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32905 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32907 if(this.bgimage.length){
32908 var image = this.el.select('.roo-brick-image-view', true).first();
32910 image.setWidth(paragraph.getWidth());
32913 image.setHeight(paragraph.getWidth());
32916 this.el.setHeight(image.getHeight());
32917 paragraph.setHeight(image.getHeight());
32923 enter: function(e, el)
32925 e.preventDefault();
32927 if(this.bgimage.length){
32928 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32929 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32933 leave: function(e, el)
32935 e.preventDefault();
32937 if(this.bgimage.length){
32938 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32939 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32955 * @class Roo.bootstrap.NumberField
32956 * @extends Roo.bootstrap.Input
32957 * Bootstrap NumberField class
32963 * Create a new NumberField
32964 * @param {Object} config The config object
32967 Roo.bootstrap.NumberField = function(config){
32968 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32971 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32974 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32976 allowDecimals : true,
32978 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32980 decimalSeparator : ".",
32982 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32984 decimalPrecision : 2,
32986 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32988 allowNegative : true,
32990 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32992 minValue : Number.NEGATIVE_INFINITY,
32994 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32996 maxValue : Number.MAX_VALUE,
32998 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33000 minText : "The minimum value for this field is {0}",
33002 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33004 maxText : "The maximum value for this field is {0}",
33006 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33007 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33009 nanText : "{0} is not a valid number",
33011 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33016 initEvents : function()
33018 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33020 var allowed = "0123456789";
33022 if(this.allowDecimals){
33023 allowed += this.decimalSeparator;
33026 if(this.allowNegative){
33030 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33032 var keyPress = function(e){
33034 var k = e.getKey();
33036 var c = e.getCharCode();
33039 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33040 allowed.indexOf(String.fromCharCode(c)) === -1
33046 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33050 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33055 this.el.on("keypress", keyPress, this);
33058 validateValue : function(value)
33061 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33065 var num = this.parseValue(value);
33068 this.markInvalid(String.format(this.nanText, value));
33072 if(num < this.minValue){
33073 this.markInvalid(String.format(this.minText, this.minValue));
33077 if(num > this.maxValue){
33078 this.markInvalid(String.format(this.maxText, this.maxValue));
33085 getValue : function()
33087 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33090 parseValue : function(value)
33092 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33093 return isNaN(value) ? '' : value;
33096 fixPrecision : function(value)
33098 var nan = isNaN(value);
33100 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33101 return nan ? '' : value;
33103 return parseFloat(value).toFixed(this.decimalPrecision);
33106 setValue : function(v)
33108 v = this.fixPrecision(v);
33109 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33112 decimalPrecisionFcn : function(v)
33114 return Math.floor(v);
33117 beforeBlur : function()
33123 var v = this.parseValue(this.getRawValue());
33138 * @class Roo.bootstrap.DocumentSlider
33139 * @extends Roo.bootstrap.Component
33140 * Bootstrap DocumentSlider class
33143 * Create a new DocumentViewer
33144 * @param {Object} config The config object
33147 Roo.bootstrap.DocumentSlider = function(config){
33148 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33155 * Fire after initEvent
33156 * @param {Roo.bootstrap.DocumentSlider} this
33161 * Fire after update
33162 * @param {Roo.bootstrap.DocumentSlider} this
33168 * @param {Roo.bootstrap.DocumentSlider} this
33174 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33180 getAutoCreate : function()
33184 cls : 'roo-document-slider',
33188 cls : 'roo-document-slider-header',
33192 cls : 'roo-document-slider-header-title'
33198 cls : 'roo-document-slider-body',
33202 cls : 'roo-document-slider-prev',
33206 cls : 'fa fa-chevron-left'
33212 cls : 'roo-document-slider-thumb',
33216 cls : 'roo-document-slider-image'
33222 cls : 'roo-document-slider-next',
33226 cls : 'fa fa-chevron-right'
33238 initEvents : function()
33240 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33241 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33243 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33244 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33246 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33247 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33249 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33250 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33252 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33253 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33255 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33256 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33258 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33259 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33261 this.thumbEl.on('click', this.onClick, this);
33263 this.prevIndicator.on('click', this.prev, this);
33265 this.nextIndicator.on('click', this.next, this);
33269 initial : function()
33271 if(this.files.length){
33272 this.indicator = 1;
33276 this.fireEvent('initial', this);
33279 update : function()
33281 this.imageEl.attr('src', this.files[this.indicator - 1]);
33283 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33285 this.prevIndicator.show();
33287 if(this.indicator == 1){
33288 this.prevIndicator.hide();
33291 this.nextIndicator.show();
33293 if(this.indicator == this.files.length){
33294 this.nextIndicator.hide();
33297 this.thumbEl.scrollTo('top');
33299 this.fireEvent('update', this);
33302 onClick : function(e)
33304 e.preventDefault();
33306 this.fireEvent('click', this);
33311 e.preventDefault();
33313 this.indicator = Math.max(1, this.indicator - 1);
33320 e.preventDefault();
33322 this.indicator = Math.min(this.files.length, this.indicator + 1);
33336 * @class Roo.bootstrap.RadioSet
33337 * @extends Roo.bootstrap.Input
33338 * Bootstrap RadioSet class
33339 * @cfg {String} indicatorpos (left|right) default left
33340 * @cfg {Boolean} inline (true|false) inline the element (default true)
33341 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33343 * Create a new RadioSet
33344 * @param {Object} config The config object
33347 Roo.bootstrap.RadioSet = function(config){
33349 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33353 Roo.bootstrap.RadioSet.register(this);
33358 * Fires when the element is checked or unchecked.
33359 * @param {Roo.bootstrap.RadioSet} this This radio
33360 * @param {Roo.bootstrap.Radio} item The checked item
33367 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33375 indicatorpos : 'left',
33377 getAutoCreate : function()
33381 cls : 'roo-radio-set-label',
33385 html : this.fieldLabel
33390 if(this.indicatorpos == 'left'){
33393 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33394 tooltip : 'This field is required'
33399 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33400 tooltip : 'This field is required'
33406 cls : 'roo-radio-set-items'
33409 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33411 if (align === 'left' && this.fieldLabel.length) {
33414 cls : "roo-radio-set-right",
33420 if(this.labelWidth > 12){
33421 label.style = "width: " + this.labelWidth + 'px';
33424 if(this.labelWidth < 13 && this.labelmd == 0){
33425 this.labelmd = this.labelWidth;
33428 if(this.labellg > 0){
33429 label.cls += ' col-lg-' + this.labellg;
33430 items.cls += ' col-lg-' + (12 - this.labellg);
33433 if(this.labelmd > 0){
33434 label.cls += ' col-md-' + this.labelmd;
33435 items.cls += ' col-md-' + (12 - this.labelmd);
33438 if(this.labelsm > 0){
33439 label.cls += ' col-sm-' + this.labelsm;
33440 items.cls += ' col-sm-' + (12 - this.labelsm);
33443 if(this.labelxs > 0){
33444 label.cls += ' col-xs-' + this.labelxs;
33445 items.cls += ' col-xs-' + (12 - this.labelxs);
33451 cls : 'roo-radio-set',
33455 cls : 'roo-radio-set-input',
33458 value : this.value ? this.value : ''
33465 if(this.weight.length){
33466 cfg.cls += ' roo-radio-' + this.weight;
33470 cfg.cls += ' roo-radio-set-inline';
33474 ['xs','sm','md','lg'].map(function(size){
33475 if (settings[size]) {
33476 cfg.cls += ' col-' + size + '-' + settings[size];
33484 initEvents : function()
33486 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33487 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33489 if(!this.fieldLabel.length){
33490 this.labelEl.hide();
33493 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33494 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33496 this.indicatorEl().addClass('invisible');
33498 this.originalValue = this.getValue();
33502 inputEl: function ()
33504 return this.el.select('.roo-radio-set-input', true).first();
33507 getChildContainer : function()
33509 return this.itemsEl;
33512 register : function(item)
33514 this.radioes.push(item);
33518 validate : function()
33522 Roo.each(this.radioes, function(i){
33531 if(this.allowBlank) {
33535 if(this.disabled || valid){
33540 this.markInvalid();
33545 markValid : function()
33547 if(this.labelEl.isVisible(true)){
33548 this.indicatorEl().removeClass('visible');
33549 this.indicatorEl().addClass('invisible');
33552 this.el.removeClass([this.invalidClass, this.validClass]);
33553 this.el.addClass(this.validClass);
33555 this.fireEvent('valid', this);
33558 markInvalid : function(msg)
33560 if(this.allowBlank || this.disabled){
33564 if(this.labelEl.isVisible(true)){
33565 this.indicatorEl().removeClass('invisible');
33566 this.indicatorEl().addClass('visible');
33569 this.el.removeClass([this.invalidClass, this.validClass]);
33570 this.el.addClass(this.invalidClass);
33572 this.fireEvent('invalid', this, msg);
33576 setValue : function(v, suppressEvent)
33578 if(this.value === v){
33585 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33588 Roo.each(this.radioes, function(i){
33591 i.el.removeClass('checked');
33593 if(i.value === v || i.value.toString() === v.toString()){
33595 i.el.addClass('checked');
33597 if(suppressEvent !== true){
33598 this.fireEvent('check', this, i);
33607 clearInvalid : function(){
33609 if(!this.el || this.preventMark){
33613 this.el.removeClass([this.invalidClass]);
33615 this.fireEvent('valid', this);
33620 Roo.apply(Roo.bootstrap.RadioSet, {
33624 register : function(set)
33626 this.groups[set.name] = set;
33629 get: function(name)
33631 if (typeof(this.groups[name]) == 'undefined') {
33635 return this.groups[name] ;
33641 * Ext JS Library 1.1.1
33642 * Copyright(c) 2006-2007, Ext JS, LLC.
33644 * Originally Released Under LGPL - original licence link has changed is not relivant.
33647 * <script type="text/javascript">
33652 * @class Roo.bootstrap.SplitBar
33653 * @extends Roo.util.Observable
33654 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33658 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33659 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33660 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33661 split.minSize = 100;
33662 split.maxSize = 600;
33663 split.animate = true;
33664 split.on('moved', splitterMoved);
33667 * Create a new SplitBar
33668 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33669 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33670 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33671 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33672 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33673 position of the SplitBar).
33675 Roo.bootstrap.SplitBar = function(cfg){
33680 // dragElement : elm
33681 // resizingElement: el,
33683 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33684 // placement : Roo.bootstrap.SplitBar.LEFT ,
33685 // existingProxy ???
33688 this.el = Roo.get(cfg.dragElement, true);
33689 this.el.dom.unselectable = "on";
33691 this.resizingEl = Roo.get(cfg.resizingElement, true);
33695 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33696 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33699 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33702 * The minimum size of the resizing element. (Defaults to 0)
33708 * The maximum size of the resizing element. (Defaults to 2000)
33711 this.maxSize = 2000;
33714 * Whether to animate the transition to the new size
33717 this.animate = false;
33720 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33723 this.useShim = false;
33728 if(!cfg.existingProxy){
33730 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33732 this.proxy = Roo.get(cfg.existingProxy).dom;
33735 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33738 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33741 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33744 this.dragSpecs = {};
33747 * @private The adapter to use to positon and resize elements
33749 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33750 this.adapter.init(this);
33752 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33754 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33755 this.el.addClass("roo-splitbar-h");
33758 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33759 this.el.addClass("roo-splitbar-v");
33765 * Fires when the splitter is moved (alias for {@link #event-moved})
33766 * @param {Roo.bootstrap.SplitBar} this
33767 * @param {Number} newSize the new width or height
33772 * Fires when the splitter is moved
33773 * @param {Roo.bootstrap.SplitBar} this
33774 * @param {Number} newSize the new width or height
33778 * @event beforeresize
33779 * Fires before the splitter is dragged
33780 * @param {Roo.bootstrap.SplitBar} this
33782 "beforeresize" : true,
33784 "beforeapply" : true
33787 Roo.util.Observable.call(this);
33790 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33791 onStartProxyDrag : function(x, y){
33792 this.fireEvent("beforeresize", this);
33794 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33796 o.enableDisplayMode("block");
33797 // all splitbars share the same overlay
33798 Roo.bootstrap.SplitBar.prototype.overlay = o;
33800 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33801 this.overlay.show();
33802 Roo.get(this.proxy).setDisplayed("block");
33803 var size = this.adapter.getElementSize(this);
33804 this.activeMinSize = this.getMinimumSize();;
33805 this.activeMaxSize = this.getMaximumSize();;
33806 var c1 = size - this.activeMinSize;
33807 var c2 = Math.max(this.activeMaxSize - size, 0);
33808 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33809 this.dd.resetConstraints();
33810 this.dd.setXConstraint(
33811 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33812 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33814 this.dd.setYConstraint(0, 0);
33816 this.dd.resetConstraints();
33817 this.dd.setXConstraint(0, 0);
33818 this.dd.setYConstraint(
33819 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33820 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33823 this.dragSpecs.startSize = size;
33824 this.dragSpecs.startPoint = [x, y];
33825 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33829 * @private Called after the drag operation by the DDProxy
33831 onEndProxyDrag : function(e){
33832 Roo.get(this.proxy).setDisplayed(false);
33833 var endPoint = Roo.lib.Event.getXY(e);
33835 this.overlay.hide();
33838 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33839 newSize = this.dragSpecs.startSize +
33840 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33841 endPoint[0] - this.dragSpecs.startPoint[0] :
33842 this.dragSpecs.startPoint[0] - endPoint[0]
33845 newSize = this.dragSpecs.startSize +
33846 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33847 endPoint[1] - this.dragSpecs.startPoint[1] :
33848 this.dragSpecs.startPoint[1] - endPoint[1]
33851 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33852 if(newSize != this.dragSpecs.startSize){
33853 if(this.fireEvent('beforeapply', this, newSize) !== false){
33854 this.adapter.setElementSize(this, newSize);
33855 this.fireEvent("moved", this, newSize);
33856 this.fireEvent("resize", this, newSize);
33862 * Get the adapter this SplitBar uses
33863 * @return The adapter object
33865 getAdapter : function(){
33866 return this.adapter;
33870 * Set the adapter this SplitBar uses
33871 * @param {Object} adapter A SplitBar adapter object
33873 setAdapter : function(adapter){
33874 this.adapter = adapter;
33875 this.adapter.init(this);
33879 * Gets the minimum size for the resizing element
33880 * @return {Number} The minimum size
33882 getMinimumSize : function(){
33883 return this.minSize;
33887 * Sets the minimum size for the resizing element
33888 * @param {Number} minSize The minimum size
33890 setMinimumSize : function(minSize){
33891 this.minSize = minSize;
33895 * Gets the maximum size for the resizing element
33896 * @return {Number} The maximum size
33898 getMaximumSize : function(){
33899 return this.maxSize;
33903 * Sets the maximum size for the resizing element
33904 * @param {Number} maxSize The maximum size
33906 setMaximumSize : function(maxSize){
33907 this.maxSize = maxSize;
33911 * Sets the initialize size for the resizing element
33912 * @param {Number} size The initial size
33914 setCurrentSize : function(size){
33915 var oldAnimate = this.animate;
33916 this.animate = false;
33917 this.adapter.setElementSize(this, size);
33918 this.animate = oldAnimate;
33922 * Destroy this splitbar.
33923 * @param {Boolean} removeEl True to remove the element
33925 destroy : function(removeEl){
33927 this.shim.remove();
33930 this.proxy.parentNode.removeChild(this.proxy);
33938 * @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.
33940 Roo.bootstrap.SplitBar.createProxy = function(dir){
33941 var proxy = new Roo.Element(document.createElement("div"));
33942 proxy.unselectable();
33943 var cls = 'roo-splitbar-proxy';
33944 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33945 document.body.appendChild(proxy.dom);
33950 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33951 * Default Adapter. It assumes the splitter and resizing element are not positioned
33952 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33954 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33957 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33958 // do nothing for now
33959 init : function(s){
33963 * Called before drag operations to get the current size of the resizing element.
33964 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33966 getElementSize : function(s){
33967 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33968 return s.resizingEl.getWidth();
33970 return s.resizingEl.getHeight();
33975 * Called after drag operations to set the size of the resizing element.
33976 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33977 * @param {Number} newSize The new size to set
33978 * @param {Function} onComplete A function to be invoked when resizing is complete
33980 setElementSize : function(s, newSize, onComplete){
33981 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33983 s.resizingEl.setWidth(newSize);
33985 onComplete(s, newSize);
33988 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33993 s.resizingEl.setHeight(newSize);
33995 onComplete(s, newSize);
33998 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34005 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34006 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34007 * Adapter that moves the splitter element to align with the resized sizing element.
34008 * Used with an absolute positioned SplitBar.
34009 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34010 * document.body, make sure you assign an id to the body element.
34012 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34013 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34014 this.container = Roo.get(container);
34017 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34018 init : function(s){
34019 this.basic.init(s);
34022 getElementSize : function(s){
34023 return this.basic.getElementSize(s);
34026 setElementSize : function(s, newSize, onComplete){
34027 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34030 moveSplitter : function(s){
34031 var yes = Roo.bootstrap.SplitBar;
34032 switch(s.placement){
34034 s.el.setX(s.resizingEl.getRight());
34037 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34040 s.el.setY(s.resizingEl.getBottom());
34043 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34050 * Orientation constant - Create a vertical SplitBar
34054 Roo.bootstrap.SplitBar.VERTICAL = 1;
34057 * Orientation constant - Create a horizontal SplitBar
34061 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34064 * Placement constant - The resizing element is to the left of the splitter element
34068 Roo.bootstrap.SplitBar.LEFT = 1;
34071 * Placement constant - The resizing element is to the right of the splitter element
34075 Roo.bootstrap.SplitBar.RIGHT = 2;
34078 * Placement constant - The resizing element is positioned above the splitter element
34082 Roo.bootstrap.SplitBar.TOP = 3;
34085 * Placement constant - The resizing element is positioned under splitter element
34089 Roo.bootstrap.SplitBar.BOTTOM = 4;
34090 Roo.namespace("Roo.bootstrap.layout");/*
34092 * Ext JS Library 1.1.1
34093 * Copyright(c) 2006-2007, Ext JS, LLC.
34095 * Originally Released Under LGPL - original licence link has changed is not relivant.
34098 * <script type="text/javascript">
34102 * @class Roo.bootstrap.layout.Manager
34103 * @extends Roo.bootstrap.Component
34104 * Base class for layout managers.
34106 Roo.bootstrap.layout.Manager = function(config)
34108 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34114 /** false to disable window resize monitoring @type Boolean */
34115 this.monitorWindowResize = true;
34120 * Fires when a layout is performed.
34121 * @param {Roo.LayoutManager} this
34125 * @event regionresized
34126 * Fires when the user resizes a region.
34127 * @param {Roo.LayoutRegion} region The resized region
34128 * @param {Number} newSize The new size (width for east/west, height for north/south)
34130 "regionresized" : true,
34132 * @event regioncollapsed
34133 * Fires when a region is collapsed.
34134 * @param {Roo.LayoutRegion} region The collapsed region
34136 "regioncollapsed" : true,
34138 * @event regionexpanded
34139 * Fires when a region is expanded.
34140 * @param {Roo.LayoutRegion} region The expanded region
34142 "regionexpanded" : true
34144 this.updating = false;
34147 this.el = Roo.get(config.el);
34153 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34158 monitorWindowResize : true,
34164 onRender : function(ct, position)
34167 this.el = Roo.get(ct);
34170 //this.fireEvent('render',this);
34174 initEvents: function()
34178 // ie scrollbar fix
34179 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34180 document.body.scroll = "no";
34181 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34182 this.el.position('relative');
34184 this.id = this.el.id;
34185 this.el.addClass("roo-layout-container");
34186 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34187 if(this.el.dom != document.body ) {
34188 this.el.on('resize', this.layout,this);
34189 this.el.on('show', this.layout,this);
34195 * Returns true if this layout is currently being updated
34196 * @return {Boolean}
34198 isUpdating : function(){
34199 return this.updating;
34203 * Suspend the LayoutManager from doing auto-layouts while
34204 * making multiple add or remove calls
34206 beginUpdate : function(){
34207 this.updating = true;
34211 * Restore auto-layouts and optionally disable the manager from performing a layout
34212 * @param {Boolean} noLayout true to disable a layout update
34214 endUpdate : function(noLayout){
34215 this.updating = false;
34221 layout: function(){
34225 onRegionResized : function(region, newSize){
34226 this.fireEvent("regionresized", region, newSize);
34230 onRegionCollapsed : function(region){
34231 this.fireEvent("regioncollapsed", region);
34234 onRegionExpanded : function(region){
34235 this.fireEvent("regionexpanded", region);
34239 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34240 * performs box-model adjustments.
34241 * @return {Object} The size as an object {width: (the width), height: (the height)}
34243 getViewSize : function()
34246 if(this.el.dom != document.body){
34247 size = this.el.getSize();
34249 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34251 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34252 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34257 * Returns the Element this layout is bound to.
34258 * @return {Roo.Element}
34260 getEl : function(){
34265 * Returns the specified region.
34266 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34267 * @return {Roo.LayoutRegion}
34269 getRegion : function(target){
34270 return this.regions[target.toLowerCase()];
34273 onWindowResize : function(){
34274 if(this.monitorWindowResize){
34281 * Ext JS Library 1.1.1
34282 * Copyright(c) 2006-2007, Ext JS, LLC.
34284 * Originally Released Under LGPL - original licence link has changed is not relivant.
34287 * <script type="text/javascript">
34290 * @class Roo.bootstrap.layout.Border
34291 * @extends Roo.bootstrap.layout.Manager
34292 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34293 * please see: examples/bootstrap/nested.html<br><br>
34295 <b>The container the layout is rendered into can be either the body element or any other element.
34296 If it is not the body element, the container needs to either be an absolute positioned element,
34297 or you will need to add "position:relative" to the css of the container. You will also need to specify
34298 the container size if it is not the body element.</b>
34301 * Create a new Border
34302 * @param {Object} config Configuration options
34304 Roo.bootstrap.layout.Border = function(config){
34305 config = config || {};
34306 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34310 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34311 if(config[region]){
34312 config[region].region = region;
34313 this.addRegion(config[region]);
34319 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34321 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34323 * Creates and adds a new region if it doesn't already exist.
34324 * @param {String} target The target region key (north, south, east, west or center).
34325 * @param {Object} config The regions config object
34326 * @return {BorderLayoutRegion} The new region
34328 addRegion : function(config)
34330 if(!this.regions[config.region]){
34331 var r = this.factory(config);
34332 this.bindRegion(r);
34334 return this.regions[config.region];
34338 bindRegion : function(r){
34339 this.regions[r.config.region] = r;
34341 r.on("visibilitychange", this.layout, this);
34342 r.on("paneladded", this.layout, this);
34343 r.on("panelremoved", this.layout, this);
34344 r.on("invalidated", this.layout, this);
34345 r.on("resized", this.onRegionResized, this);
34346 r.on("collapsed", this.onRegionCollapsed, this);
34347 r.on("expanded", this.onRegionExpanded, this);
34351 * Performs a layout update.
34353 layout : function()
34355 if(this.updating) {
34359 // render all the rebions if they have not been done alreayd?
34360 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34361 if(this.regions[region] && !this.regions[region].bodyEl){
34362 this.regions[region].onRender(this.el)
34366 var size = this.getViewSize();
34367 var w = size.width;
34368 var h = size.height;
34373 //var x = 0, y = 0;
34375 var rs = this.regions;
34376 var north = rs["north"];
34377 var south = rs["south"];
34378 var west = rs["west"];
34379 var east = rs["east"];
34380 var center = rs["center"];
34381 //if(this.hideOnLayout){ // not supported anymore
34382 //c.el.setStyle("display", "none");
34384 if(north && north.isVisible()){
34385 var b = north.getBox();
34386 var m = north.getMargins();
34387 b.width = w - (m.left+m.right);
34390 centerY = b.height + b.y + m.bottom;
34391 centerH -= centerY;
34392 north.updateBox(this.safeBox(b));
34394 if(south && south.isVisible()){
34395 var b = south.getBox();
34396 var m = south.getMargins();
34397 b.width = w - (m.left+m.right);
34399 var totalHeight = (b.height + m.top + m.bottom);
34400 b.y = h - totalHeight + m.top;
34401 centerH -= totalHeight;
34402 south.updateBox(this.safeBox(b));
34404 if(west && west.isVisible()){
34405 var b = west.getBox();
34406 var m = west.getMargins();
34407 b.height = centerH - (m.top+m.bottom);
34409 b.y = centerY + m.top;
34410 var totalWidth = (b.width + m.left + m.right);
34411 centerX += totalWidth;
34412 centerW -= totalWidth;
34413 west.updateBox(this.safeBox(b));
34415 if(east && east.isVisible()){
34416 var b = east.getBox();
34417 var m = east.getMargins();
34418 b.height = centerH - (m.top+m.bottom);
34419 var totalWidth = (b.width + m.left + m.right);
34420 b.x = w - totalWidth + m.left;
34421 b.y = centerY + m.top;
34422 centerW -= totalWidth;
34423 east.updateBox(this.safeBox(b));
34426 var m = center.getMargins();
34428 x: centerX + m.left,
34429 y: centerY + m.top,
34430 width: centerW - (m.left+m.right),
34431 height: centerH - (m.top+m.bottom)
34433 //if(this.hideOnLayout){
34434 //center.el.setStyle("display", "block");
34436 center.updateBox(this.safeBox(centerBox));
34439 this.fireEvent("layout", this);
34443 safeBox : function(box){
34444 box.width = Math.max(0, box.width);
34445 box.height = Math.max(0, box.height);
34450 * Adds a ContentPanel (or subclass) to this layout.
34451 * @param {String} target The target region key (north, south, east, west or center).
34452 * @param {Roo.ContentPanel} panel The panel to add
34453 * @return {Roo.ContentPanel} The added panel
34455 add : function(target, panel){
34457 target = target.toLowerCase();
34458 return this.regions[target].add(panel);
34462 * Remove a ContentPanel (or subclass) to this layout.
34463 * @param {String} target The target region key (north, south, east, west or center).
34464 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34465 * @return {Roo.ContentPanel} The removed panel
34467 remove : function(target, panel){
34468 target = target.toLowerCase();
34469 return this.regions[target].remove(panel);
34473 * Searches all regions for a panel with the specified id
34474 * @param {String} panelId
34475 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34477 findPanel : function(panelId){
34478 var rs = this.regions;
34479 for(var target in rs){
34480 if(typeof rs[target] != "function"){
34481 var p = rs[target].getPanel(panelId);
34491 * Searches all regions for a panel with the specified id and activates (shows) it.
34492 * @param {String/ContentPanel} panelId The panels id or the panel itself
34493 * @return {Roo.ContentPanel} The shown panel or null
34495 showPanel : function(panelId) {
34496 var rs = this.regions;
34497 for(var target in rs){
34498 var r = rs[target];
34499 if(typeof r != "function"){
34500 if(r.hasPanel(panelId)){
34501 return r.showPanel(panelId);
34509 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34510 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34513 restoreState : function(provider){
34515 provider = Roo.state.Manager;
34517 var sm = new Roo.LayoutStateManager();
34518 sm.init(this, provider);
34524 * Adds a xtype elements to the layout.
34528 xtype : 'ContentPanel',
34535 xtype : 'NestedLayoutPanel',
34541 items : [ ... list of content panels or nested layout panels.. ]
34545 * @param {Object} cfg Xtype definition of item to add.
34547 addxtype : function(cfg)
34549 // basically accepts a pannel...
34550 // can accept a layout region..!?!?
34551 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34554 // theory? children can only be panels??
34556 //if (!cfg.xtype.match(/Panel$/)) {
34561 if (typeof(cfg.region) == 'undefined') {
34562 Roo.log("Failed to add Panel, region was not set");
34566 var region = cfg.region;
34572 xitems = cfg.items;
34579 case 'Content': // ContentPanel (el, cfg)
34580 case 'Scroll': // ContentPanel (el, cfg)
34582 cfg.autoCreate = true;
34583 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34585 // var el = this.el.createChild();
34586 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34589 this.add(region, ret);
34593 case 'TreePanel': // our new panel!
34594 cfg.el = this.el.createChild();
34595 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34596 this.add(region, ret);
34601 // create a new Layout (which is a Border Layout...
34603 var clayout = cfg.layout;
34604 clayout.el = this.el.createChild();
34605 clayout.items = clayout.items || [];
34609 // replace this exitems with the clayout ones..
34610 xitems = clayout.items;
34612 // force background off if it's in center...
34613 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34614 cfg.background = false;
34616 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34619 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34620 //console.log('adding nested layout panel ' + cfg.toSource());
34621 this.add(region, ret);
34622 nb = {}; /// find first...
34627 // needs grid and region
34629 //var el = this.getRegion(region).el.createChild();
34631 *var el = this.el.createChild();
34632 // create the grid first...
34633 cfg.grid.container = el;
34634 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34637 if (region == 'center' && this.active ) {
34638 cfg.background = false;
34641 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34643 this.add(region, ret);
34645 if (cfg.background) {
34646 // render grid on panel activation (if panel background)
34647 ret.on('activate', function(gp) {
34648 if (!gp.grid.rendered) {
34649 // gp.grid.render(el);
34653 // cfg.grid.render(el);
34659 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34660 // it was the old xcomponent building that caused this before.
34661 // espeically if border is the top element in the tree.
34671 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34673 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34674 this.add(region, ret);
34678 throw "Can not add '" + cfg.xtype + "' to Border";
34684 this.beginUpdate();
34688 Roo.each(xitems, function(i) {
34689 region = nb && i.region ? i.region : false;
34691 var add = ret.addxtype(i);
34694 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34695 if (!i.background) {
34696 abn[region] = nb[region] ;
34703 // make the last non-background panel active..
34704 //if (nb) { Roo.log(abn); }
34707 for(var r in abn) {
34708 region = this.getRegion(r);
34710 // tried using nb[r], but it does not work..
34712 region.showPanel(abn[r]);
34723 factory : function(cfg)
34726 var validRegions = Roo.bootstrap.layout.Border.regions;
34728 var target = cfg.region;
34731 var r = Roo.bootstrap.layout;
34735 return new r.North(cfg);
34737 return new r.South(cfg);
34739 return new r.East(cfg);
34741 return new r.West(cfg);
34743 return new r.Center(cfg);
34745 throw 'Layout region "'+target+'" not supported.';
34752 * Ext JS Library 1.1.1
34753 * Copyright(c) 2006-2007, Ext JS, LLC.
34755 * Originally Released Under LGPL - original licence link has changed is not relivant.
34758 * <script type="text/javascript">
34762 * @class Roo.bootstrap.layout.Basic
34763 * @extends Roo.util.Observable
34764 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34765 * and does not have a titlebar, tabs or any other features. All it does is size and position
34766 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34767 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34768 * @cfg {string} region the region that it inhabits..
34769 * @cfg {bool} skipConfig skip config?
34773 Roo.bootstrap.layout.Basic = function(config){
34775 this.mgr = config.mgr;
34777 this.position = config.region;
34779 var skipConfig = config.skipConfig;
34783 * @scope Roo.BasicLayoutRegion
34787 * @event beforeremove
34788 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34789 * @param {Roo.LayoutRegion} this
34790 * @param {Roo.ContentPanel} panel The panel
34791 * @param {Object} e The cancel event object
34793 "beforeremove" : true,
34795 * @event invalidated
34796 * Fires when the layout for this region is changed.
34797 * @param {Roo.LayoutRegion} this
34799 "invalidated" : true,
34801 * @event visibilitychange
34802 * Fires when this region is shown or hidden
34803 * @param {Roo.LayoutRegion} this
34804 * @param {Boolean} visibility true or false
34806 "visibilitychange" : true,
34808 * @event paneladded
34809 * Fires when a panel is added.
34810 * @param {Roo.LayoutRegion} this
34811 * @param {Roo.ContentPanel} panel The panel
34813 "paneladded" : true,
34815 * @event panelremoved
34816 * Fires when a panel is removed.
34817 * @param {Roo.LayoutRegion} this
34818 * @param {Roo.ContentPanel} panel The panel
34820 "panelremoved" : true,
34822 * @event beforecollapse
34823 * Fires when this region before collapse.
34824 * @param {Roo.LayoutRegion} this
34826 "beforecollapse" : true,
34829 * Fires when this region is collapsed.
34830 * @param {Roo.LayoutRegion} this
34832 "collapsed" : true,
34835 * Fires when this region is expanded.
34836 * @param {Roo.LayoutRegion} this
34841 * Fires when this region is slid into view.
34842 * @param {Roo.LayoutRegion} this
34844 "slideshow" : true,
34847 * Fires when this region slides out of view.
34848 * @param {Roo.LayoutRegion} this
34850 "slidehide" : true,
34852 * @event panelactivated
34853 * Fires when a panel is activated.
34854 * @param {Roo.LayoutRegion} this
34855 * @param {Roo.ContentPanel} panel The activated panel
34857 "panelactivated" : true,
34860 * Fires when the user resizes this region.
34861 * @param {Roo.LayoutRegion} this
34862 * @param {Number} newSize The new size (width for east/west, height for north/south)
34866 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34867 this.panels = new Roo.util.MixedCollection();
34868 this.panels.getKey = this.getPanelId.createDelegate(this);
34870 this.activePanel = null;
34871 // ensure listeners are added...
34873 if (config.listeners || config.events) {
34874 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34875 listeners : config.listeners || {},
34876 events : config.events || {}
34880 if(skipConfig !== true){
34881 this.applyConfig(config);
34885 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34887 getPanelId : function(p){
34891 applyConfig : function(config){
34892 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34893 this.config = config;
34898 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34899 * the width, for horizontal (north, south) the height.
34900 * @param {Number} newSize The new width or height
34902 resizeTo : function(newSize){
34903 var el = this.el ? this.el :
34904 (this.activePanel ? this.activePanel.getEl() : null);
34906 switch(this.position){
34909 el.setWidth(newSize);
34910 this.fireEvent("resized", this, newSize);
34914 el.setHeight(newSize);
34915 this.fireEvent("resized", this, newSize);
34921 getBox : function(){
34922 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34925 getMargins : function(){
34926 return this.margins;
34929 updateBox : function(box){
34931 var el = this.activePanel.getEl();
34932 el.dom.style.left = box.x + "px";
34933 el.dom.style.top = box.y + "px";
34934 this.activePanel.setSize(box.width, box.height);
34938 * Returns the container element for this region.
34939 * @return {Roo.Element}
34941 getEl : function(){
34942 return this.activePanel;
34946 * Returns true if this region is currently visible.
34947 * @return {Boolean}
34949 isVisible : function(){
34950 return this.activePanel ? true : false;
34953 setActivePanel : function(panel){
34954 panel = this.getPanel(panel);
34955 if(this.activePanel && this.activePanel != panel){
34956 this.activePanel.setActiveState(false);
34957 this.activePanel.getEl().setLeftTop(-10000,-10000);
34959 this.activePanel = panel;
34960 panel.setActiveState(true);
34962 panel.setSize(this.box.width, this.box.height);
34964 this.fireEvent("panelactivated", this, panel);
34965 this.fireEvent("invalidated");
34969 * Show the specified panel.
34970 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34971 * @return {Roo.ContentPanel} The shown panel or null
34973 showPanel : function(panel){
34974 panel = this.getPanel(panel);
34976 this.setActivePanel(panel);
34982 * Get the active panel for this region.
34983 * @return {Roo.ContentPanel} The active panel or null
34985 getActivePanel : function(){
34986 return this.activePanel;
34990 * Add the passed ContentPanel(s)
34991 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34992 * @return {Roo.ContentPanel} The panel added (if only one was added)
34994 add : function(panel){
34995 if(arguments.length > 1){
34996 for(var i = 0, len = arguments.length; i < len; i++) {
34997 this.add(arguments[i]);
35001 if(this.hasPanel(panel)){
35002 this.showPanel(panel);
35005 var el = panel.getEl();
35006 if(el.dom.parentNode != this.mgr.el.dom){
35007 this.mgr.el.dom.appendChild(el.dom);
35009 if(panel.setRegion){
35010 panel.setRegion(this);
35012 this.panels.add(panel);
35013 el.setStyle("position", "absolute");
35014 if(!panel.background){
35015 this.setActivePanel(panel);
35016 if(this.config.initialSize && this.panels.getCount()==1){
35017 this.resizeTo(this.config.initialSize);
35020 this.fireEvent("paneladded", this, panel);
35025 * Returns true if the panel is in this region.
35026 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35027 * @return {Boolean}
35029 hasPanel : function(panel){
35030 if(typeof panel == "object"){ // must be panel obj
35031 panel = panel.getId();
35033 return this.getPanel(panel) ? true : false;
35037 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35038 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35039 * @param {Boolean} preservePanel Overrides the config preservePanel option
35040 * @return {Roo.ContentPanel} The panel that was removed
35042 remove : function(panel, preservePanel){
35043 panel = this.getPanel(panel);
35048 this.fireEvent("beforeremove", this, panel, e);
35049 if(e.cancel === true){
35052 var panelId = panel.getId();
35053 this.panels.removeKey(panelId);
35058 * Returns the panel specified or null if it's not in this region.
35059 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35060 * @return {Roo.ContentPanel}
35062 getPanel : function(id){
35063 if(typeof id == "object"){ // must be panel obj
35066 return this.panels.get(id);
35070 * Returns this regions position (north/south/east/west/center).
35073 getPosition: function(){
35074 return this.position;
35078 * Ext JS Library 1.1.1
35079 * Copyright(c) 2006-2007, Ext JS, LLC.
35081 * Originally Released Under LGPL - original licence link has changed is not relivant.
35084 * <script type="text/javascript">
35088 * @class Roo.bootstrap.layout.Region
35089 * @extends Roo.bootstrap.layout.Basic
35090 * This class represents a region in a layout manager.
35092 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35093 * @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})
35094 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35095 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35096 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35097 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35098 * @cfg {String} title The title for the region (overrides panel titles)
35099 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35100 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35101 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35102 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35103 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35104 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35105 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35106 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35107 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35108 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35110 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35111 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35112 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35113 * @cfg {Number} width For East/West panels
35114 * @cfg {Number} height For North/South panels
35115 * @cfg {Boolean} split To show the splitter
35116 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35118 * @cfg {string} cls Extra CSS classes to add to region
35120 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35121 * @cfg {string} region the region that it inhabits..
35124 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35125 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35127 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35128 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35129 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35131 Roo.bootstrap.layout.Region = function(config)
35133 this.applyConfig(config);
35135 var mgr = config.mgr;
35136 var pos = config.region;
35137 config.skipConfig = true;
35138 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35141 this.onRender(mgr.el);
35144 this.visible = true;
35145 this.collapsed = false;
35146 this.unrendered_panels = [];
35149 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35151 position: '', // set by wrapper (eg. north/south etc..)
35152 unrendered_panels : null, // unrendered panels.
35153 createBody : function(){
35154 /** This region's body element
35155 * @type Roo.Element */
35156 this.bodyEl = this.el.createChild({
35158 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35162 onRender: function(ctr, pos)
35164 var dh = Roo.DomHelper;
35165 /** This region's container element
35166 * @type Roo.Element */
35167 this.el = dh.append(ctr.dom, {
35169 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35171 /** This region's title element
35172 * @type Roo.Element */
35174 this.titleEl = dh.append(this.el.dom,
35177 unselectable: "on",
35178 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35180 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35181 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35184 this.titleEl.enableDisplayMode();
35185 /** This region's title text element
35186 * @type HTMLElement */
35187 this.titleTextEl = this.titleEl.dom.firstChild;
35188 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35190 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35191 this.closeBtn.enableDisplayMode();
35192 this.closeBtn.on("click", this.closeClicked, this);
35193 this.closeBtn.hide();
35195 this.createBody(this.config);
35196 if(this.config.hideWhenEmpty){
35198 this.on("paneladded", this.validateVisibility, this);
35199 this.on("panelremoved", this.validateVisibility, this);
35201 if(this.autoScroll){
35202 this.bodyEl.setStyle("overflow", "auto");
35204 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35206 //if(c.titlebar !== false){
35207 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35208 this.titleEl.hide();
35210 this.titleEl.show();
35211 if(this.config.title){
35212 this.titleTextEl.innerHTML = this.config.title;
35216 if(this.config.collapsed){
35217 this.collapse(true);
35219 if(this.config.hidden){
35223 if (this.unrendered_panels && this.unrendered_panels.length) {
35224 for (var i =0;i< this.unrendered_panels.length; i++) {
35225 this.add(this.unrendered_panels[i]);
35227 this.unrendered_panels = null;
35233 applyConfig : function(c)
35236 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35237 var dh = Roo.DomHelper;
35238 if(c.titlebar !== false){
35239 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35240 this.collapseBtn.on("click", this.collapse, this);
35241 this.collapseBtn.enableDisplayMode();
35243 if(c.showPin === true || this.showPin){
35244 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35245 this.stickBtn.enableDisplayMode();
35246 this.stickBtn.on("click", this.expand, this);
35247 this.stickBtn.hide();
35252 /** This region's collapsed element
35253 * @type Roo.Element */
35256 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35257 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35260 if(c.floatable !== false){
35261 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35262 this.collapsedEl.on("click", this.collapseClick, this);
35265 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35266 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35267 id: "message", unselectable: "on", style:{"float":"left"}});
35268 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35270 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35271 this.expandBtn.on("click", this.expand, this);
35275 if(this.collapseBtn){
35276 this.collapseBtn.setVisible(c.collapsible == true);
35279 this.cmargins = c.cmargins || this.cmargins ||
35280 (this.position == "west" || this.position == "east" ?
35281 {top: 0, left: 2, right:2, bottom: 0} :
35282 {top: 2, left: 0, right:0, bottom: 2});
35284 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35287 this.bottomTabs = c.tabPosition != "top";
35289 this.autoScroll = c.autoScroll || false;
35294 this.duration = c.duration || .30;
35295 this.slideDuration = c.slideDuration || .45;
35300 * Returns true if this region is currently visible.
35301 * @return {Boolean}
35303 isVisible : function(){
35304 return this.visible;
35308 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35309 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35311 //setCollapsedTitle : function(title){
35312 // title = title || " ";
35313 // if(this.collapsedTitleTextEl){
35314 // this.collapsedTitleTextEl.innerHTML = title;
35318 getBox : function(){
35320 // if(!this.collapsed){
35321 b = this.el.getBox(false, true);
35323 // b = this.collapsedEl.getBox(false, true);
35328 getMargins : function(){
35329 return this.margins;
35330 //return this.collapsed ? this.cmargins : this.margins;
35333 highlight : function(){
35334 this.el.addClass("x-layout-panel-dragover");
35337 unhighlight : function(){
35338 this.el.removeClass("x-layout-panel-dragover");
35341 updateBox : function(box)
35343 if (!this.bodyEl) {
35344 return; // not rendered yet..
35348 if(!this.collapsed){
35349 this.el.dom.style.left = box.x + "px";
35350 this.el.dom.style.top = box.y + "px";
35351 this.updateBody(box.width, box.height);
35353 this.collapsedEl.dom.style.left = box.x + "px";
35354 this.collapsedEl.dom.style.top = box.y + "px";
35355 this.collapsedEl.setSize(box.width, box.height);
35358 this.tabs.autoSizeTabs();
35362 updateBody : function(w, h)
35365 this.el.setWidth(w);
35366 w -= this.el.getBorderWidth("rl");
35367 if(this.config.adjustments){
35368 w += this.config.adjustments[0];
35371 if(h !== null && h > 0){
35372 this.el.setHeight(h);
35373 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35374 h -= this.el.getBorderWidth("tb");
35375 if(this.config.adjustments){
35376 h += this.config.adjustments[1];
35378 this.bodyEl.setHeight(h);
35380 h = this.tabs.syncHeight(h);
35383 if(this.panelSize){
35384 w = w !== null ? w : this.panelSize.width;
35385 h = h !== null ? h : this.panelSize.height;
35387 if(this.activePanel){
35388 var el = this.activePanel.getEl();
35389 w = w !== null ? w : el.getWidth();
35390 h = h !== null ? h : el.getHeight();
35391 this.panelSize = {width: w, height: h};
35392 this.activePanel.setSize(w, h);
35394 if(Roo.isIE && this.tabs){
35395 this.tabs.el.repaint();
35400 * Returns the container element for this region.
35401 * @return {Roo.Element}
35403 getEl : function(){
35408 * Hides this region.
35411 //if(!this.collapsed){
35412 this.el.dom.style.left = "-2000px";
35415 // this.collapsedEl.dom.style.left = "-2000px";
35416 // this.collapsedEl.hide();
35418 this.visible = false;
35419 this.fireEvent("visibilitychange", this, false);
35423 * Shows this region if it was previously hidden.
35426 //if(!this.collapsed){
35429 // this.collapsedEl.show();
35431 this.visible = true;
35432 this.fireEvent("visibilitychange", this, true);
35435 closeClicked : function(){
35436 if(this.activePanel){
35437 this.remove(this.activePanel);
35441 collapseClick : function(e){
35443 e.stopPropagation();
35446 e.stopPropagation();
35452 * Collapses this region.
35453 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35456 collapse : function(skipAnim, skipCheck = false){
35457 if(this.collapsed) {
35461 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35463 this.collapsed = true;
35465 this.split.el.hide();
35467 if(this.config.animate && skipAnim !== true){
35468 this.fireEvent("invalidated", this);
35469 this.animateCollapse();
35471 this.el.setLocation(-20000,-20000);
35473 this.collapsedEl.show();
35474 this.fireEvent("collapsed", this);
35475 this.fireEvent("invalidated", this);
35481 animateCollapse : function(){
35486 * Expands this region if it was previously collapsed.
35487 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35488 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35491 expand : function(e, skipAnim){
35493 e.stopPropagation();
35495 if(!this.collapsed || this.el.hasActiveFx()) {
35499 this.afterSlideIn();
35502 this.collapsed = false;
35503 if(this.config.animate && skipAnim !== true){
35504 this.animateExpand();
35508 this.split.el.show();
35510 this.collapsedEl.setLocation(-2000,-2000);
35511 this.collapsedEl.hide();
35512 this.fireEvent("invalidated", this);
35513 this.fireEvent("expanded", this);
35517 animateExpand : function(){
35521 initTabs : function()
35523 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35525 var ts = new Roo.bootstrap.panel.Tabs({
35526 el: this.bodyEl.dom,
35527 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35528 disableTooltips: this.config.disableTabTips,
35529 toolbar : this.config.toolbar
35532 if(this.config.hideTabs){
35533 ts.stripWrap.setDisplayed(false);
35536 ts.resizeTabs = this.config.resizeTabs === true;
35537 ts.minTabWidth = this.config.minTabWidth || 40;
35538 ts.maxTabWidth = this.config.maxTabWidth || 250;
35539 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35540 ts.monitorResize = false;
35541 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35542 ts.bodyEl.addClass('roo-layout-tabs-body');
35543 this.panels.each(this.initPanelAsTab, this);
35546 initPanelAsTab : function(panel){
35547 var ti = this.tabs.addTab(
35551 this.config.closeOnTab && panel.isClosable(),
35554 if(panel.tabTip !== undefined){
35555 ti.setTooltip(panel.tabTip);
35557 ti.on("activate", function(){
35558 this.setActivePanel(panel);
35561 if(this.config.closeOnTab){
35562 ti.on("beforeclose", function(t, e){
35564 this.remove(panel);
35568 panel.tabItem = ti;
35573 updatePanelTitle : function(panel, title)
35575 if(this.activePanel == panel){
35576 this.updateTitle(title);
35579 var ti = this.tabs.getTab(panel.getEl().id);
35581 if(panel.tabTip !== undefined){
35582 ti.setTooltip(panel.tabTip);
35587 updateTitle : function(title){
35588 if(this.titleTextEl && !this.config.title){
35589 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35593 setActivePanel : function(panel)
35595 panel = this.getPanel(panel);
35596 if(this.activePanel && this.activePanel != panel){
35597 if(this.activePanel.setActiveState(false) === false){
35601 this.activePanel = panel;
35602 panel.setActiveState(true);
35603 if(this.panelSize){
35604 panel.setSize(this.panelSize.width, this.panelSize.height);
35607 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35609 this.updateTitle(panel.getTitle());
35611 this.fireEvent("invalidated", this);
35613 this.fireEvent("panelactivated", this, panel);
35617 * Shows the specified panel.
35618 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35619 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35621 showPanel : function(panel)
35623 panel = this.getPanel(panel);
35626 var tab = this.tabs.getTab(panel.getEl().id);
35627 if(tab.isHidden()){
35628 this.tabs.unhideTab(tab.id);
35632 this.setActivePanel(panel);
35639 * Get the active panel for this region.
35640 * @return {Roo.ContentPanel} The active panel or null
35642 getActivePanel : function(){
35643 return this.activePanel;
35646 validateVisibility : function(){
35647 if(this.panels.getCount() < 1){
35648 this.updateTitle(" ");
35649 this.closeBtn.hide();
35652 if(!this.isVisible()){
35659 * Adds the passed ContentPanel(s) to this region.
35660 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35661 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35663 add : function(panel)
35665 if(arguments.length > 1){
35666 for(var i = 0, len = arguments.length; i < len; i++) {
35667 this.add(arguments[i]);
35672 // if we have not been rendered yet, then we can not really do much of this..
35673 if (!this.bodyEl) {
35674 this.unrendered_panels.push(panel);
35681 if(this.hasPanel(panel)){
35682 this.showPanel(panel);
35685 panel.setRegion(this);
35686 this.panels.add(panel);
35687 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35688 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35689 // and hide them... ???
35690 this.bodyEl.dom.appendChild(panel.getEl().dom);
35691 if(panel.background !== true){
35692 this.setActivePanel(panel);
35694 this.fireEvent("paneladded", this, panel);
35701 this.initPanelAsTab(panel);
35705 if(panel.background !== true){
35706 this.tabs.activate(panel.getEl().id);
35708 this.fireEvent("paneladded", this, panel);
35713 * Hides the tab for the specified panel.
35714 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35716 hidePanel : function(panel){
35717 if(this.tabs && (panel = this.getPanel(panel))){
35718 this.tabs.hideTab(panel.getEl().id);
35723 * Unhides the tab for a previously hidden panel.
35724 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35726 unhidePanel : function(panel){
35727 if(this.tabs && (panel = this.getPanel(panel))){
35728 this.tabs.unhideTab(panel.getEl().id);
35732 clearPanels : function(){
35733 while(this.panels.getCount() > 0){
35734 this.remove(this.panels.first());
35739 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35740 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35741 * @param {Boolean} preservePanel Overrides the config preservePanel option
35742 * @return {Roo.ContentPanel} The panel that was removed
35744 remove : function(panel, preservePanel)
35746 panel = this.getPanel(panel);
35751 this.fireEvent("beforeremove", this, panel, e);
35752 if(e.cancel === true){
35755 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35756 var panelId = panel.getId();
35757 this.panels.removeKey(panelId);
35759 document.body.appendChild(panel.getEl().dom);
35762 this.tabs.removeTab(panel.getEl().id);
35763 }else if (!preservePanel){
35764 this.bodyEl.dom.removeChild(panel.getEl().dom);
35766 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35767 var p = this.panels.first();
35768 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35769 tempEl.appendChild(p.getEl().dom);
35770 this.bodyEl.update("");
35771 this.bodyEl.dom.appendChild(p.getEl().dom);
35773 this.updateTitle(p.getTitle());
35775 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35776 this.setActivePanel(p);
35778 panel.setRegion(null);
35779 if(this.activePanel == panel){
35780 this.activePanel = null;
35782 if(this.config.autoDestroy !== false && preservePanel !== true){
35783 try{panel.destroy();}catch(e){}
35785 this.fireEvent("panelremoved", this, panel);
35790 * Returns the TabPanel component used by this region
35791 * @return {Roo.TabPanel}
35793 getTabs : function(){
35797 createTool : function(parentEl, className){
35798 var btn = Roo.DomHelper.append(parentEl, {
35800 cls: "x-layout-tools-button",
35803 cls: "roo-layout-tools-button-inner " + className,
35807 btn.addClassOnOver("roo-layout-tools-button-over");
35812 * Ext JS Library 1.1.1
35813 * Copyright(c) 2006-2007, Ext JS, LLC.
35815 * Originally Released Under LGPL - original licence link has changed is not relivant.
35818 * <script type="text/javascript">
35824 * @class Roo.SplitLayoutRegion
35825 * @extends Roo.LayoutRegion
35826 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35828 Roo.bootstrap.layout.Split = function(config){
35829 this.cursor = config.cursor;
35830 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35833 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35835 splitTip : "Drag to resize.",
35836 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35837 useSplitTips : false,
35839 applyConfig : function(config){
35840 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35843 onRender : function(ctr,pos) {
35845 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35846 if(!this.config.split){
35851 var splitEl = Roo.DomHelper.append(ctr.dom, {
35853 id: this.el.id + "-split",
35854 cls: "roo-layout-split roo-layout-split-"+this.position,
35857 /** The SplitBar for this region
35858 * @type Roo.SplitBar */
35859 // does not exist yet...
35860 Roo.log([this.position, this.orientation]);
35862 this.split = new Roo.bootstrap.SplitBar({
35863 dragElement : splitEl,
35864 resizingElement: this.el,
35865 orientation : this.orientation
35868 this.split.on("moved", this.onSplitMove, this);
35869 this.split.useShim = this.config.useShim === true;
35870 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35871 if(this.useSplitTips){
35872 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35874 //if(config.collapsible){
35875 // this.split.el.on("dblclick", this.collapse, this);
35878 if(typeof this.config.minSize != "undefined"){
35879 this.split.minSize = this.config.minSize;
35881 if(typeof this.config.maxSize != "undefined"){
35882 this.split.maxSize = this.config.maxSize;
35884 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35885 this.hideSplitter();
35890 getHMaxSize : function(){
35891 var cmax = this.config.maxSize || 10000;
35892 var center = this.mgr.getRegion("center");
35893 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35896 getVMaxSize : function(){
35897 var cmax = this.config.maxSize || 10000;
35898 var center = this.mgr.getRegion("center");
35899 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35902 onSplitMove : function(split, newSize){
35903 this.fireEvent("resized", this, newSize);
35907 * Returns the {@link Roo.SplitBar} for this region.
35908 * @return {Roo.SplitBar}
35910 getSplitBar : function(){
35915 this.hideSplitter();
35916 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35919 hideSplitter : function(){
35921 this.split.el.setLocation(-2000,-2000);
35922 this.split.el.hide();
35928 this.split.el.show();
35930 Roo.bootstrap.layout.Split.superclass.show.call(this);
35933 beforeSlide: function(){
35934 if(Roo.isGecko){// firefox overflow auto bug workaround
35935 this.bodyEl.clip();
35937 this.tabs.bodyEl.clip();
35939 if(this.activePanel){
35940 this.activePanel.getEl().clip();
35942 if(this.activePanel.beforeSlide){
35943 this.activePanel.beforeSlide();
35949 afterSlide : function(){
35950 if(Roo.isGecko){// firefox overflow auto bug workaround
35951 this.bodyEl.unclip();
35953 this.tabs.bodyEl.unclip();
35955 if(this.activePanel){
35956 this.activePanel.getEl().unclip();
35957 if(this.activePanel.afterSlide){
35958 this.activePanel.afterSlide();
35964 initAutoHide : function(){
35965 if(this.autoHide !== false){
35966 if(!this.autoHideHd){
35967 var st = new Roo.util.DelayedTask(this.slideIn, this);
35968 this.autoHideHd = {
35969 "mouseout": function(e){
35970 if(!e.within(this.el, true)){
35974 "mouseover" : function(e){
35980 this.el.on(this.autoHideHd);
35984 clearAutoHide : function(){
35985 if(this.autoHide !== false){
35986 this.el.un("mouseout", this.autoHideHd.mouseout);
35987 this.el.un("mouseover", this.autoHideHd.mouseover);
35991 clearMonitor : function(){
35992 Roo.get(document).un("click", this.slideInIf, this);
35995 // these names are backwards but not changed for compat
35996 slideOut : function(){
35997 if(this.isSlid || this.el.hasActiveFx()){
36000 this.isSlid = true;
36001 if(this.collapseBtn){
36002 this.collapseBtn.hide();
36004 this.closeBtnState = this.closeBtn.getStyle('display');
36005 this.closeBtn.hide();
36007 this.stickBtn.show();
36010 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36011 this.beforeSlide();
36012 this.el.setStyle("z-index", 10001);
36013 this.el.slideIn(this.getSlideAnchor(), {
36014 callback: function(){
36016 this.initAutoHide();
36017 Roo.get(document).on("click", this.slideInIf, this);
36018 this.fireEvent("slideshow", this);
36025 afterSlideIn : function(){
36026 this.clearAutoHide();
36027 this.isSlid = false;
36028 this.clearMonitor();
36029 this.el.setStyle("z-index", "");
36030 if(this.collapseBtn){
36031 this.collapseBtn.show();
36033 this.closeBtn.setStyle('display', this.closeBtnState);
36035 this.stickBtn.hide();
36037 this.fireEvent("slidehide", this);
36040 slideIn : function(cb){
36041 if(!this.isSlid || this.el.hasActiveFx()){
36045 this.isSlid = false;
36046 this.beforeSlide();
36047 this.el.slideOut(this.getSlideAnchor(), {
36048 callback: function(){
36049 this.el.setLeftTop(-10000, -10000);
36051 this.afterSlideIn();
36059 slideInIf : function(e){
36060 if(!e.within(this.el)){
36065 animateCollapse : function(){
36066 this.beforeSlide();
36067 this.el.setStyle("z-index", 20000);
36068 var anchor = this.getSlideAnchor();
36069 this.el.slideOut(anchor, {
36070 callback : function(){
36071 this.el.setStyle("z-index", "");
36072 this.collapsedEl.slideIn(anchor, {duration:.3});
36074 this.el.setLocation(-10000,-10000);
36076 this.fireEvent("collapsed", this);
36083 animateExpand : function(){
36084 this.beforeSlide();
36085 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36086 this.el.setStyle("z-index", 20000);
36087 this.collapsedEl.hide({
36090 this.el.slideIn(this.getSlideAnchor(), {
36091 callback : function(){
36092 this.el.setStyle("z-index", "");
36095 this.split.el.show();
36097 this.fireEvent("invalidated", this);
36098 this.fireEvent("expanded", this);
36126 getAnchor : function(){
36127 return this.anchors[this.position];
36130 getCollapseAnchor : function(){
36131 return this.canchors[this.position];
36134 getSlideAnchor : function(){
36135 return this.sanchors[this.position];
36138 getAlignAdj : function(){
36139 var cm = this.cmargins;
36140 switch(this.position){
36156 getExpandAdj : function(){
36157 var c = this.collapsedEl, cm = this.cmargins;
36158 switch(this.position){
36160 return [-(cm.right+c.getWidth()+cm.left), 0];
36163 return [cm.right+c.getWidth()+cm.left, 0];
36166 return [0, -(cm.top+cm.bottom+c.getHeight())];
36169 return [0, cm.top+cm.bottom+c.getHeight()];
36175 * Ext JS Library 1.1.1
36176 * Copyright(c) 2006-2007, Ext JS, LLC.
36178 * Originally Released Under LGPL - original licence link has changed is not relivant.
36181 * <script type="text/javascript">
36184 * These classes are private internal classes
36186 Roo.bootstrap.layout.Center = function(config){
36187 config.region = "center";
36188 Roo.bootstrap.layout.Region.call(this, config);
36189 this.visible = true;
36190 this.minWidth = config.minWidth || 20;
36191 this.minHeight = config.minHeight || 20;
36194 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36196 // center panel can't be hidden
36200 // center panel can't be hidden
36203 getMinWidth: function(){
36204 return this.minWidth;
36207 getMinHeight: function(){
36208 return this.minHeight;
36221 Roo.bootstrap.layout.North = function(config)
36223 config.region = 'north';
36224 config.cursor = 'n-resize';
36226 Roo.bootstrap.layout.Split.call(this, config);
36230 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36231 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36232 this.split.el.addClass("roo-layout-split-v");
36234 var size = config.initialSize || config.height;
36235 if(typeof size != "undefined"){
36236 this.el.setHeight(size);
36239 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36241 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36245 getBox : function(){
36246 if(this.collapsed){
36247 return this.collapsedEl.getBox();
36249 var box = this.el.getBox();
36251 box.height += this.split.el.getHeight();
36256 updateBox : function(box){
36257 if(this.split && !this.collapsed){
36258 box.height -= this.split.el.getHeight();
36259 this.split.el.setLeft(box.x);
36260 this.split.el.setTop(box.y+box.height);
36261 this.split.el.setWidth(box.width);
36263 if(this.collapsed){
36264 this.updateBody(box.width, null);
36266 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36274 Roo.bootstrap.layout.South = function(config){
36275 config.region = 'south';
36276 config.cursor = 's-resize';
36277 Roo.bootstrap.layout.Split.call(this, config);
36279 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36280 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36281 this.split.el.addClass("roo-layout-split-v");
36283 var size = config.initialSize || config.height;
36284 if(typeof size != "undefined"){
36285 this.el.setHeight(size);
36289 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36290 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36291 getBox : function(){
36292 if(this.collapsed){
36293 return this.collapsedEl.getBox();
36295 var box = this.el.getBox();
36297 var sh = this.split.el.getHeight();
36304 updateBox : function(box){
36305 if(this.split && !this.collapsed){
36306 var sh = this.split.el.getHeight();
36309 this.split.el.setLeft(box.x);
36310 this.split.el.setTop(box.y-sh);
36311 this.split.el.setWidth(box.width);
36313 if(this.collapsed){
36314 this.updateBody(box.width, null);
36316 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36320 Roo.bootstrap.layout.East = function(config){
36321 config.region = "east";
36322 config.cursor = "e-resize";
36323 Roo.bootstrap.layout.Split.call(this, config);
36325 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36326 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36327 this.split.el.addClass("roo-layout-split-h");
36329 var size = config.initialSize || config.width;
36330 if(typeof size != "undefined"){
36331 this.el.setWidth(size);
36334 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36335 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36336 getBox : function(){
36337 if(this.collapsed){
36338 return this.collapsedEl.getBox();
36340 var box = this.el.getBox();
36342 var sw = this.split.el.getWidth();
36349 updateBox : function(box){
36350 if(this.split && !this.collapsed){
36351 var sw = this.split.el.getWidth();
36353 this.split.el.setLeft(box.x);
36354 this.split.el.setTop(box.y);
36355 this.split.el.setHeight(box.height);
36358 if(this.collapsed){
36359 this.updateBody(null, box.height);
36361 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36365 Roo.bootstrap.layout.West = function(config){
36366 config.region = "west";
36367 config.cursor = "w-resize";
36369 Roo.bootstrap.layout.Split.call(this, config);
36371 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36372 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36373 this.split.el.addClass("roo-layout-split-h");
36377 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36378 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36380 onRender: function(ctr, pos)
36382 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36383 var size = this.config.initialSize || this.config.width;
36384 if(typeof size != "undefined"){
36385 this.el.setWidth(size);
36389 getBox : function(){
36390 if(this.collapsed){
36391 return this.collapsedEl.getBox();
36393 var box = this.el.getBox();
36395 box.width += this.split.el.getWidth();
36400 updateBox : function(box){
36401 if(this.split && !this.collapsed){
36402 var sw = this.split.el.getWidth();
36404 this.split.el.setLeft(box.x+box.width);
36405 this.split.el.setTop(box.y);
36406 this.split.el.setHeight(box.height);
36408 if(this.collapsed){
36409 this.updateBody(null, box.height);
36411 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36414 Roo.namespace("Roo.bootstrap.panel");/*
36416 * Ext JS Library 1.1.1
36417 * Copyright(c) 2006-2007, Ext JS, LLC.
36419 * Originally Released Under LGPL - original licence link has changed is not relivant.
36422 * <script type="text/javascript">
36425 * @class Roo.ContentPanel
36426 * @extends Roo.util.Observable
36427 * A basic ContentPanel element.
36428 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36429 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36430 * @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
36431 * @cfg {Boolean} closable True if the panel can be closed/removed
36432 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36433 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36434 * @cfg {Toolbar} toolbar A toolbar for this panel
36435 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36436 * @cfg {String} title The title for this panel
36437 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36438 * @cfg {String} url Calls {@link #setUrl} with this value
36439 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36440 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36441 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36442 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36443 * @cfg {Boolean} badges render the badges
36446 * Create a new ContentPanel.
36447 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36448 * @param {String/Object} config A string to set only the title or a config object
36449 * @param {String} content (optional) Set the HTML content for this panel
36450 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36452 Roo.bootstrap.panel.Content = function( config){
36454 this.tpl = config.tpl || false;
36456 var el = config.el;
36457 var content = config.content;
36459 if(config.autoCreate){ // xtype is available if this is called from factory
36462 this.el = Roo.get(el);
36463 if(!this.el && config && config.autoCreate){
36464 if(typeof config.autoCreate == "object"){
36465 if(!config.autoCreate.id){
36466 config.autoCreate.id = config.id||el;
36468 this.el = Roo.DomHelper.append(document.body,
36469 config.autoCreate, true);
36471 var elcfg = { tag: "div",
36472 cls: "roo-layout-inactive-content",
36476 elcfg.html = config.html;
36480 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36483 this.closable = false;
36484 this.loaded = false;
36485 this.active = false;
36488 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36490 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36492 this.wrapEl = this.el; //this.el.wrap();
36494 if (config.toolbar.items) {
36495 ti = config.toolbar.items ;
36496 delete config.toolbar.items ;
36500 this.toolbar.render(this.wrapEl, 'before');
36501 for(var i =0;i < ti.length;i++) {
36502 // Roo.log(['add child', items[i]]);
36503 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36505 this.toolbar.items = nitems;
36506 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36507 delete config.toolbar;
36511 // xtype created footer. - not sure if will work as we normally have to render first..
36512 if (this.footer && !this.footer.el && this.footer.xtype) {
36513 if (!this.wrapEl) {
36514 this.wrapEl = this.el.wrap();
36517 this.footer.container = this.wrapEl.createChild();
36519 this.footer = Roo.factory(this.footer, Roo);
36524 if(typeof config == "string"){
36525 this.title = config;
36527 Roo.apply(this, config);
36531 this.resizeEl = Roo.get(this.resizeEl, true);
36533 this.resizeEl = this.el;
36535 // handle view.xtype
36543 * Fires when this panel is activated.
36544 * @param {Roo.ContentPanel} this
36548 * @event deactivate
36549 * Fires when this panel is activated.
36550 * @param {Roo.ContentPanel} this
36552 "deactivate" : true,
36556 * Fires when this panel is resized if fitToFrame is true.
36557 * @param {Roo.ContentPanel} this
36558 * @param {Number} width The width after any component adjustments
36559 * @param {Number} height The height after any component adjustments
36565 * Fires when this tab is created
36566 * @param {Roo.ContentPanel} this
36577 if(this.autoScroll){
36578 this.resizeEl.setStyle("overflow", "auto");
36580 // fix randome scrolling
36581 //this.el.on('scroll', function() {
36582 // Roo.log('fix random scolling');
36583 // this.scrollTo('top',0);
36586 content = content || this.content;
36588 this.setContent(content);
36590 if(config && config.url){
36591 this.setUrl(this.url, this.params, this.loadOnce);
36596 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36598 if (this.view && typeof(this.view.xtype) != 'undefined') {
36599 this.view.el = this.el.appendChild(document.createElement("div"));
36600 this.view = Roo.factory(this.view);
36601 this.view.render && this.view.render(false, '');
36605 this.fireEvent('render', this);
36608 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36612 setRegion : function(region){
36613 this.region = region;
36614 this.setActiveClass(region && !this.background);
36618 setActiveClass: function(state)
36621 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36622 this.el.setStyle('position','relative');
36624 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36625 this.el.setStyle('position', 'absolute');
36630 * Returns the toolbar for this Panel if one was configured.
36631 * @return {Roo.Toolbar}
36633 getToolbar : function(){
36634 return this.toolbar;
36637 setActiveState : function(active)
36639 this.active = active;
36640 this.setActiveClass(active);
36642 if(this.fireEvent("deactivate", this) === false){
36647 this.fireEvent("activate", this);
36651 * Updates this panel's element
36652 * @param {String} content The new content
36653 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36655 setContent : function(content, loadScripts){
36656 this.el.update(content, loadScripts);
36659 ignoreResize : function(w, h){
36660 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36663 this.lastSize = {width: w, height: h};
36668 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36669 * @return {Roo.UpdateManager} The UpdateManager
36671 getUpdateManager : function(){
36672 return this.el.getUpdateManager();
36675 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36676 * @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:
36679 url: "your-url.php",
36680 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36681 callback: yourFunction,
36682 scope: yourObject, //(optional scope)
36685 text: "Loading...",
36690 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36691 * 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.
36692 * @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}
36693 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36694 * @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.
36695 * @return {Roo.ContentPanel} this
36698 var um = this.el.getUpdateManager();
36699 um.update.apply(um, arguments);
36705 * 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.
36706 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36707 * @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)
36708 * @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)
36709 * @return {Roo.UpdateManager} The UpdateManager
36711 setUrl : function(url, params, loadOnce){
36712 if(this.refreshDelegate){
36713 this.removeListener("activate", this.refreshDelegate);
36715 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36716 this.on("activate", this.refreshDelegate);
36717 return this.el.getUpdateManager();
36720 _handleRefresh : function(url, params, loadOnce){
36721 if(!loadOnce || !this.loaded){
36722 var updater = this.el.getUpdateManager();
36723 updater.update(url, params, this._setLoaded.createDelegate(this));
36727 _setLoaded : function(){
36728 this.loaded = true;
36732 * Returns this panel's id
36735 getId : function(){
36740 * Returns this panel's element - used by regiosn to add.
36741 * @return {Roo.Element}
36743 getEl : function(){
36744 return this.wrapEl || this.el;
36749 adjustForComponents : function(width, height)
36751 //Roo.log('adjustForComponents ');
36752 if(this.resizeEl != this.el){
36753 width -= this.el.getFrameWidth('lr');
36754 height -= this.el.getFrameWidth('tb');
36757 var te = this.toolbar.getEl();
36758 te.setWidth(width);
36759 height -= te.getHeight();
36762 var te = this.footer.getEl();
36763 te.setWidth(width);
36764 height -= te.getHeight();
36768 if(this.adjustments){
36769 width += this.adjustments[0];
36770 height += this.adjustments[1];
36772 return {"width": width, "height": height};
36775 setSize : function(width, height){
36776 if(this.fitToFrame && !this.ignoreResize(width, height)){
36777 if(this.fitContainer && this.resizeEl != this.el){
36778 this.el.setSize(width, height);
36780 var size = this.adjustForComponents(width, height);
36781 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36782 this.fireEvent('resize', this, size.width, size.height);
36787 * Returns this panel's title
36790 getTitle : function(){
36792 if (typeof(this.title) != 'object') {
36797 for (var k in this.title) {
36798 if (!this.title.hasOwnProperty(k)) {
36802 if (k.indexOf('-') >= 0) {
36803 var s = k.split('-');
36804 for (var i = 0; i<s.length; i++) {
36805 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36808 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36815 * Set this panel's title
36816 * @param {String} title
36818 setTitle : function(title){
36819 this.title = title;
36821 this.region.updatePanelTitle(this, title);
36826 * Returns true is this panel was configured to be closable
36827 * @return {Boolean}
36829 isClosable : function(){
36830 return this.closable;
36833 beforeSlide : function(){
36835 this.resizeEl.clip();
36838 afterSlide : function(){
36840 this.resizeEl.unclip();
36844 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36845 * Will fail silently if the {@link #setUrl} method has not been called.
36846 * This does not activate the panel, just updates its content.
36848 refresh : function(){
36849 if(this.refreshDelegate){
36850 this.loaded = false;
36851 this.refreshDelegate();
36856 * Destroys this panel
36858 destroy : function(){
36859 this.el.removeAllListeners();
36860 var tempEl = document.createElement("span");
36861 tempEl.appendChild(this.el.dom);
36862 tempEl.innerHTML = "";
36868 * form - if the content panel contains a form - this is a reference to it.
36869 * @type {Roo.form.Form}
36873 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36874 * This contains a reference to it.
36880 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36890 * @param {Object} cfg Xtype definition of item to add.
36894 getChildContainer: function () {
36895 return this.getEl();
36900 var ret = new Roo.factory(cfg);
36905 if (cfg.xtype.match(/^Form$/)) {
36908 //if (this.footer) {
36909 // el = this.footer.container.insertSibling(false, 'before');
36911 el = this.el.createChild();
36914 this.form = new Roo.form.Form(cfg);
36917 if ( this.form.allItems.length) {
36918 this.form.render(el.dom);
36922 // should only have one of theses..
36923 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36924 // views.. should not be just added - used named prop 'view''
36926 cfg.el = this.el.appendChild(document.createElement("div"));
36929 var ret = new Roo.factory(cfg);
36931 ret.render && ret.render(false, ''); // render blank..
36941 * @class Roo.bootstrap.panel.Grid
36942 * @extends Roo.bootstrap.panel.Content
36944 * Create a new GridPanel.
36945 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36946 * @param {Object} config A the config object
36952 Roo.bootstrap.panel.Grid = function(config)
36956 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36957 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36959 config.el = this.wrapper;
36960 //this.el = this.wrapper;
36962 if (config.container) {
36963 // ctor'ed from a Border/panel.grid
36966 this.wrapper.setStyle("overflow", "hidden");
36967 this.wrapper.addClass('roo-grid-container');
36972 if(config.toolbar){
36973 var tool_el = this.wrapper.createChild();
36974 this.toolbar = Roo.factory(config.toolbar);
36976 if (config.toolbar.items) {
36977 ti = config.toolbar.items ;
36978 delete config.toolbar.items ;
36982 this.toolbar.render(tool_el);
36983 for(var i =0;i < ti.length;i++) {
36984 // Roo.log(['add child', items[i]]);
36985 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36987 this.toolbar.items = nitems;
36989 delete config.toolbar;
36992 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36993 config.grid.scrollBody = true;;
36994 config.grid.monitorWindowResize = false; // turn off autosizing
36995 config.grid.autoHeight = false;
36996 config.grid.autoWidth = false;
36998 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37000 if (config.background) {
37001 // render grid on panel activation (if panel background)
37002 this.on('activate', function(gp) {
37003 if (!gp.grid.rendered) {
37004 gp.grid.render(this.wrapper);
37005 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37010 this.grid.render(this.wrapper);
37011 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37014 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37015 // ??? needed ??? config.el = this.wrapper;
37020 // xtype created footer. - not sure if will work as we normally have to render first..
37021 if (this.footer && !this.footer.el && this.footer.xtype) {
37023 var ctr = this.grid.getView().getFooterPanel(true);
37024 this.footer.dataSource = this.grid.dataSource;
37025 this.footer = Roo.factory(this.footer, Roo);
37026 this.footer.render(ctr);
37036 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37037 getId : function(){
37038 return this.grid.id;
37042 * Returns the grid for this panel
37043 * @return {Roo.bootstrap.Table}
37045 getGrid : function(){
37049 setSize : function(width, height){
37050 if(!this.ignoreResize(width, height)){
37051 var grid = this.grid;
37052 var size = this.adjustForComponents(width, height);
37053 var gridel = grid.getGridEl();
37054 gridel.setSize(size.width, size.height);
37056 var thd = grid.getGridEl().select('thead',true).first();
37057 var tbd = grid.getGridEl().select('tbody', true).first();
37059 tbd.setSize(width, height - thd.getHeight());
37068 beforeSlide : function(){
37069 this.grid.getView().scroller.clip();
37072 afterSlide : function(){
37073 this.grid.getView().scroller.unclip();
37076 destroy : function(){
37077 this.grid.destroy();
37079 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37084 * @class Roo.bootstrap.panel.Nest
37085 * @extends Roo.bootstrap.panel.Content
37087 * Create a new Panel, that can contain a layout.Border.
37090 * @param {Roo.BorderLayout} layout The layout for this panel
37091 * @param {String/Object} config A string to set only the title or a config object
37093 Roo.bootstrap.panel.Nest = function(config)
37095 // construct with only one argument..
37096 /* FIXME - implement nicer consturctors
37097 if (layout.layout) {
37099 layout = config.layout;
37100 delete config.layout;
37102 if (layout.xtype && !layout.getEl) {
37103 // then layout needs constructing..
37104 layout = Roo.factory(layout, Roo);
37108 config.el = config.layout.getEl();
37110 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37112 config.layout.monitorWindowResize = false; // turn off autosizing
37113 this.layout = config.layout;
37114 this.layout.getEl().addClass("roo-layout-nested-layout");
37121 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37123 setSize : function(width, height){
37124 if(!this.ignoreResize(width, height)){
37125 var size = this.adjustForComponents(width, height);
37126 var el = this.layout.getEl();
37127 if (size.height < 1) {
37128 el.setWidth(size.width);
37130 el.setSize(size.width, size.height);
37132 var touch = el.dom.offsetWidth;
37133 this.layout.layout();
37134 // ie requires a double layout on the first pass
37135 if(Roo.isIE && !this.initialized){
37136 this.initialized = true;
37137 this.layout.layout();
37142 // activate all subpanels if not currently active..
37144 setActiveState : function(active){
37145 this.active = active;
37146 this.setActiveClass(active);
37149 this.fireEvent("deactivate", this);
37153 this.fireEvent("activate", this);
37154 // not sure if this should happen before or after..
37155 if (!this.layout) {
37156 return; // should not happen..
37159 for (var r in this.layout.regions) {
37160 reg = this.layout.getRegion(r);
37161 if (reg.getActivePanel()) {
37162 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37163 reg.setActivePanel(reg.getActivePanel());
37166 if (!reg.panels.length) {
37169 reg.showPanel(reg.getPanel(0));
37178 * Returns the nested BorderLayout for this panel
37179 * @return {Roo.BorderLayout}
37181 getLayout : function(){
37182 return this.layout;
37186 * Adds a xtype elements to the layout of the nested panel
37190 xtype : 'ContentPanel',
37197 xtype : 'NestedLayoutPanel',
37203 items : [ ... list of content panels or nested layout panels.. ]
37207 * @param {Object} cfg Xtype definition of item to add.
37209 addxtype : function(cfg) {
37210 return this.layout.addxtype(cfg);
37215 * Ext JS Library 1.1.1
37216 * Copyright(c) 2006-2007, Ext JS, LLC.
37218 * Originally Released Under LGPL - original licence link has changed is not relivant.
37221 * <script type="text/javascript">
37224 * @class Roo.TabPanel
37225 * @extends Roo.util.Observable
37226 * A lightweight tab container.
37230 // basic tabs 1, built from existing content
37231 var tabs = new Roo.TabPanel("tabs1");
37232 tabs.addTab("script", "View Script");
37233 tabs.addTab("markup", "View Markup");
37234 tabs.activate("script");
37236 // more advanced tabs, built from javascript
37237 var jtabs = new Roo.TabPanel("jtabs");
37238 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37240 // set up the UpdateManager
37241 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37242 var updater = tab2.getUpdateManager();
37243 updater.setDefaultUrl("ajax1.htm");
37244 tab2.on('activate', updater.refresh, updater, true);
37246 // Use setUrl for Ajax loading
37247 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37248 tab3.setUrl("ajax2.htm", null, true);
37251 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37254 jtabs.activate("jtabs-1");
37257 * Create a new TabPanel.
37258 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37259 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37261 Roo.bootstrap.panel.Tabs = function(config){
37263 * The container element for this TabPanel.
37264 * @type Roo.Element
37266 this.el = Roo.get(config.el);
37269 if(typeof config == "boolean"){
37270 this.tabPosition = config ? "bottom" : "top";
37272 Roo.apply(this, config);
37276 if(this.tabPosition == "bottom"){
37277 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37278 this.el.addClass("roo-tabs-bottom");
37280 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37281 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37282 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37284 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37286 if(this.tabPosition != "bottom"){
37287 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37288 * @type Roo.Element
37290 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37291 this.el.addClass("roo-tabs-top");
37295 this.bodyEl.setStyle("position", "relative");
37297 this.active = null;
37298 this.activateDelegate = this.activate.createDelegate(this);
37303 * Fires when the active tab changes
37304 * @param {Roo.TabPanel} this
37305 * @param {Roo.TabPanelItem} activePanel The new active tab
37309 * @event beforetabchange
37310 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37311 * @param {Roo.TabPanel} this
37312 * @param {Object} e Set cancel to true on this object to cancel the tab change
37313 * @param {Roo.TabPanelItem} tab The tab being changed to
37315 "beforetabchange" : true
37318 Roo.EventManager.onWindowResize(this.onResize, this);
37319 this.cpad = this.el.getPadding("lr");
37320 this.hiddenCount = 0;
37323 // toolbar on the tabbar support...
37324 if (this.toolbar) {
37325 alert("no toolbar support yet");
37326 this.toolbar = false;
37328 var tcfg = this.toolbar;
37329 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37330 this.toolbar = new Roo.Toolbar(tcfg);
37331 if (Roo.isSafari) {
37332 var tbl = tcfg.container.child('table', true);
37333 tbl.setAttribute('width', '100%');
37341 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37344 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37346 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37348 tabPosition : "top",
37350 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37352 currentTabWidth : 0,
37354 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37358 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37362 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37364 preferredTabWidth : 175,
37366 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37368 resizeTabs : false,
37370 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37372 monitorResize : true,
37374 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37379 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37380 * @param {String} id The id of the div to use <b>or create</b>
37381 * @param {String} text The text for the tab
37382 * @param {String} content (optional) Content to put in the TabPanelItem body
37383 * @param {Boolean} closable (optional) True to create a close icon on the tab
37384 * @return {Roo.TabPanelItem} The created TabPanelItem
37386 addTab : function(id, text, content, closable, tpl)
37388 var item = new Roo.bootstrap.panel.TabItem({
37392 closable : closable,
37395 this.addTabItem(item);
37397 item.setContent(content);
37403 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37404 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37405 * @return {Roo.TabPanelItem}
37407 getTab : function(id){
37408 return this.items[id];
37412 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37413 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37415 hideTab : function(id){
37416 var t = this.items[id];
37419 this.hiddenCount++;
37420 this.autoSizeTabs();
37425 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37426 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37428 unhideTab : function(id){
37429 var t = this.items[id];
37431 t.setHidden(false);
37432 this.hiddenCount--;
37433 this.autoSizeTabs();
37438 * Adds an existing {@link Roo.TabPanelItem}.
37439 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37441 addTabItem : function(item){
37442 this.items[item.id] = item;
37443 this.items.push(item);
37444 // if(this.resizeTabs){
37445 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37446 // this.autoSizeTabs();
37448 // item.autoSize();
37453 * Removes a {@link Roo.TabPanelItem}.
37454 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37456 removeTab : function(id){
37457 var items = this.items;
37458 var tab = items[id];
37459 if(!tab) { return; }
37460 var index = items.indexOf(tab);
37461 if(this.active == tab && items.length > 1){
37462 var newTab = this.getNextAvailable(index);
37467 this.stripEl.dom.removeChild(tab.pnode.dom);
37468 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37469 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37471 items.splice(index, 1);
37472 delete this.items[tab.id];
37473 tab.fireEvent("close", tab);
37474 tab.purgeListeners();
37475 this.autoSizeTabs();
37478 getNextAvailable : function(start){
37479 var items = this.items;
37481 // look for a next tab that will slide over to
37482 // replace the one being removed
37483 while(index < items.length){
37484 var item = items[++index];
37485 if(item && !item.isHidden()){
37489 // if one isn't found select the previous tab (on the left)
37492 var item = items[--index];
37493 if(item && !item.isHidden()){
37501 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37502 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37504 disableTab : function(id){
37505 var tab = this.items[id];
37506 if(tab && this.active != tab){
37512 * Enables a {@link Roo.TabPanelItem} that is disabled.
37513 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37515 enableTab : function(id){
37516 var tab = this.items[id];
37521 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37522 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37523 * @return {Roo.TabPanelItem} The TabPanelItem.
37525 activate : function(id){
37526 var tab = this.items[id];
37530 if(tab == this.active || tab.disabled){
37534 this.fireEvent("beforetabchange", this, e, tab);
37535 if(e.cancel !== true && !tab.disabled){
37537 this.active.hide();
37539 this.active = this.items[id];
37540 this.active.show();
37541 this.fireEvent("tabchange", this, this.active);
37547 * Gets the active {@link Roo.TabPanelItem}.
37548 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37550 getActiveTab : function(){
37551 return this.active;
37555 * Updates the tab body element to fit the height of the container element
37556 * for overflow scrolling
37557 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37559 syncHeight : function(targetHeight){
37560 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37561 var bm = this.bodyEl.getMargins();
37562 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37563 this.bodyEl.setHeight(newHeight);
37567 onResize : function(){
37568 if(this.monitorResize){
37569 this.autoSizeTabs();
37574 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37576 beginUpdate : function(){
37577 this.updating = true;
37581 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37583 endUpdate : function(){
37584 this.updating = false;
37585 this.autoSizeTabs();
37589 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37591 autoSizeTabs : function(){
37592 var count = this.items.length;
37593 var vcount = count - this.hiddenCount;
37594 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37597 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37598 var availWidth = Math.floor(w / vcount);
37599 var b = this.stripBody;
37600 if(b.getWidth() > w){
37601 var tabs = this.items;
37602 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37603 if(availWidth < this.minTabWidth){
37604 /*if(!this.sleft){ // incomplete scrolling code
37605 this.createScrollButtons();
37608 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37611 if(this.currentTabWidth < this.preferredTabWidth){
37612 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37618 * Returns the number of tabs in this TabPanel.
37621 getCount : function(){
37622 return this.items.length;
37626 * Resizes all the tabs to the passed width
37627 * @param {Number} The new width
37629 setTabWidth : function(width){
37630 this.currentTabWidth = width;
37631 for(var i = 0, len = this.items.length; i < len; i++) {
37632 if(!this.items[i].isHidden()) {
37633 this.items[i].setWidth(width);
37639 * Destroys this TabPanel
37640 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37642 destroy : function(removeEl){
37643 Roo.EventManager.removeResizeListener(this.onResize, this);
37644 for(var i = 0, len = this.items.length; i < len; i++){
37645 this.items[i].purgeListeners();
37647 if(removeEl === true){
37648 this.el.update("");
37653 createStrip : function(container)
37655 var strip = document.createElement("nav");
37656 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37657 container.appendChild(strip);
37661 createStripList : function(strip)
37663 // div wrapper for retard IE
37664 // returns the "tr" element.
37665 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37666 //'<div class="x-tabs-strip-wrap">'+
37667 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37668 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37669 return strip.firstChild; //.firstChild.firstChild.firstChild;
37671 createBody : function(container)
37673 var body = document.createElement("div");
37674 Roo.id(body, "tab-body");
37675 //Roo.fly(body).addClass("x-tabs-body");
37676 Roo.fly(body).addClass("tab-content");
37677 container.appendChild(body);
37680 createItemBody :function(bodyEl, id){
37681 var body = Roo.getDom(id);
37683 body = document.createElement("div");
37686 //Roo.fly(body).addClass("x-tabs-item-body");
37687 Roo.fly(body).addClass("tab-pane");
37688 bodyEl.insertBefore(body, bodyEl.firstChild);
37692 createStripElements : function(stripEl, text, closable, tpl)
37694 var td = document.createElement("li"); // was td..
37697 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37700 stripEl.appendChild(td);
37702 td.className = "x-tabs-closable";
37703 if(!this.closeTpl){
37704 this.closeTpl = new Roo.Template(
37705 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37706 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37707 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37710 var el = this.closeTpl.overwrite(td, {"text": text});
37711 var close = el.getElementsByTagName("div")[0];
37712 var inner = el.getElementsByTagName("em")[0];
37713 return {"el": el, "close": close, "inner": inner};
37716 // not sure what this is..
37717 // if(!this.tabTpl){
37718 //this.tabTpl = new Roo.Template(
37719 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37720 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37722 // this.tabTpl = new Roo.Template(
37723 // '<a href="#">' +
37724 // '<span unselectable="on"' +
37725 // (this.disableTooltips ? '' : ' title="{text}"') +
37726 // ' >{text}</span></a>'
37732 var template = tpl || this.tabTpl || false;
37736 template = new Roo.Template(
37738 '<span unselectable="on"' +
37739 (this.disableTooltips ? '' : ' title="{text}"') +
37740 ' >{text}</span></a>'
37744 switch (typeof(template)) {
37748 template = new Roo.Template(template);
37754 var el = template.overwrite(td, {"text": text});
37756 var inner = el.getElementsByTagName("span")[0];
37758 return {"el": el, "inner": inner};
37766 * @class Roo.TabPanelItem
37767 * @extends Roo.util.Observable
37768 * Represents an individual item (tab plus body) in a TabPanel.
37769 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37770 * @param {String} id The id of this TabPanelItem
37771 * @param {String} text The text for the tab of this TabPanelItem
37772 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37774 Roo.bootstrap.panel.TabItem = function(config){
37776 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37777 * @type Roo.TabPanel
37779 this.tabPanel = config.panel;
37781 * The id for this TabPanelItem
37784 this.id = config.id;
37786 this.disabled = false;
37788 this.text = config.text;
37790 this.loaded = false;
37791 this.closable = config.closable;
37794 * The body element for this TabPanelItem.
37795 * @type Roo.Element
37797 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37798 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37799 this.bodyEl.setStyle("display", "block");
37800 this.bodyEl.setStyle("zoom", "1");
37801 //this.hideAction();
37803 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37805 this.el = Roo.get(els.el);
37806 this.inner = Roo.get(els.inner, true);
37807 this.textEl = Roo.get(this.el.dom.firstChild, true);
37808 this.pnode = Roo.get(els.el.parentNode, true);
37809 // this.el.on("mousedown", this.onTabMouseDown, this);
37810 this.el.on("click", this.onTabClick, this);
37812 if(config.closable){
37813 var c = Roo.get(els.close, true);
37814 c.dom.title = this.closeText;
37815 c.addClassOnOver("close-over");
37816 c.on("click", this.closeClick, this);
37822 * Fires when this tab becomes the active tab.
37823 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37824 * @param {Roo.TabPanelItem} this
37828 * @event beforeclose
37829 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37830 * @param {Roo.TabPanelItem} this
37831 * @param {Object} e Set cancel to true on this object to cancel the close.
37833 "beforeclose": true,
37836 * Fires when this tab is closed.
37837 * @param {Roo.TabPanelItem} this
37841 * @event deactivate
37842 * Fires when this tab is no longer the active tab.
37843 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37844 * @param {Roo.TabPanelItem} this
37846 "deactivate" : true
37848 this.hidden = false;
37850 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37853 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37855 purgeListeners : function(){
37856 Roo.util.Observable.prototype.purgeListeners.call(this);
37857 this.el.removeAllListeners();
37860 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37863 this.pnode.addClass("active");
37866 this.tabPanel.stripWrap.repaint();
37868 this.fireEvent("activate", this.tabPanel, this);
37872 * Returns true if this tab is the active tab.
37873 * @return {Boolean}
37875 isActive : function(){
37876 return this.tabPanel.getActiveTab() == this;
37880 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37883 this.pnode.removeClass("active");
37885 this.fireEvent("deactivate", this.tabPanel, this);
37888 hideAction : function(){
37889 this.bodyEl.hide();
37890 this.bodyEl.setStyle("position", "absolute");
37891 this.bodyEl.setLeft("-20000px");
37892 this.bodyEl.setTop("-20000px");
37895 showAction : function(){
37896 this.bodyEl.setStyle("position", "relative");
37897 this.bodyEl.setTop("");
37898 this.bodyEl.setLeft("");
37899 this.bodyEl.show();
37903 * Set the tooltip for the tab.
37904 * @param {String} tooltip The tab's tooltip
37906 setTooltip : function(text){
37907 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37908 this.textEl.dom.qtip = text;
37909 this.textEl.dom.removeAttribute('title');
37911 this.textEl.dom.title = text;
37915 onTabClick : function(e){
37916 e.preventDefault();
37917 this.tabPanel.activate(this.id);
37920 onTabMouseDown : function(e){
37921 e.preventDefault();
37922 this.tabPanel.activate(this.id);
37925 getWidth : function(){
37926 return this.inner.getWidth();
37929 setWidth : function(width){
37930 var iwidth = width - this.pnode.getPadding("lr");
37931 this.inner.setWidth(iwidth);
37932 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37933 this.pnode.setWidth(width);
37937 * Show or hide the tab
37938 * @param {Boolean} hidden True to hide or false to show.
37940 setHidden : function(hidden){
37941 this.hidden = hidden;
37942 this.pnode.setStyle("display", hidden ? "none" : "");
37946 * Returns true if this tab is "hidden"
37947 * @return {Boolean}
37949 isHidden : function(){
37950 return this.hidden;
37954 * Returns the text for this tab
37957 getText : function(){
37961 autoSize : function(){
37962 //this.el.beginMeasure();
37963 this.textEl.setWidth(1);
37965 * #2804 [new] Tabs in Roojs
37966 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37968 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37969 //this.el.endMeasure();
37973 * Sets the text for the tab (Note: this also sets the tooltip text)
37974 * @param {String} text The tab's text and tooltip
37976 setText : function(text){
37978 this.textEl.update(text);
37979 this.setTooltip(text);
37980 //if(!this.tabPanel.resizeTabs){
37981 // this.autoSize();
37985 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37987 activate : function(){
37988 this.tabPanel.activate(this.id);
37992 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37994 disable : function(){
37995 if(this.tabPanel.active != this){
37996 this.disabled = true;
37997 this.pnode.addClass("disabled");
38002 * Enables this TabPanelItem if it was previously disabled.
38004 enable : function(){
38005 this.disabled = false;
38006 this.pnode.removeClass("disabled");
38010 * Sets the content for this TabPanelItem.
38011 * @param {String} content The content
38012 * @param {Boolean} loadScripts true to look for and load scripts
38014 setContent : function(content, loadScripts){
38015 this.bodyEl.update(content, loadScripts);
38019 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38020 * @return {Roo.UpdateManager} The UpdateManager
38022 getUpdateManager : function(){
38023 return this.bodyEl.getUpdateManager();
38027 * Set a URL to be used to load the content for this TabPanelItem.
38028 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38029 * @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)
38030 * @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)
38031 * @return {Roo.UpdateManager} The UpdateManager
38033 setUrl : function(url, params, loadOnce){
38034 if(this.refreshDelegate){
38035 this.un('activate', this.refreshDelegate);
38037 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38038 this.on("activate", this.refreshDelegate);
38039 return this.bodyEl.getUpdateManager();
38043 _handleRefresh : function(url, params, loadOnce){
38044 if(!loadOnce || !this.loaded){
38045 var updater = this.bodyEl.getUpdateManager();
38046 updater.update(url, params, this._setLoaded.createDelegate(this));
38051 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38052 * Will fail silently if the setUrl method has not been called.
38053 * This does not activate the panel, just updates its content.
38055 refresh : function(){
38056 if(this.refreshDelegate){
38057 this.loaded = false;
38058 this.refreshDelegate();
38063 _setLoaded : function(){
38064 this.loaded = true;
38068 closeClick : function(e){
38071 this.fireEvent("beforeclose", this, o);
38072 if(o.cancel !== true){
38073 this.tabPanel.removeTab(this.id);
38077 * The text displayed in the tooltip for the close icon.
38080 closeText : "Close this tab"
38083 * This script refer to:
38084 * Title: International Telephone Input
38085 * Author: Jack O'Connor
38086 * Code version: v12.1.12
38087 * Availability: https://github.com/jackocnr/intl-tel-input.git
38090 Roo.bootstrap.PhoneInputData = function() {
38093 "Afghanistan (افغانستان)",
38098 "Albania (Shqipëri)",
38103 "Algeria (الجزائر)",
38128 "Antigua and Barbuda",
38138 "Armenia (Հայաստան)",
38154 "Austria (Österreich)",
38159 "Azerbaijan (Azərbaycan)",
38169 "Bahrain (البحرين)",
38174 "Bangladesh (বাংলাদেশ)",
38184 "Belarus (Беларусь)",
38189 "Belgium (België)",
38219 "Bosnia and Herzegovina (Босна и Херцеговина)",
38234 "British Indian Ocean Territory",
38239 "British Virgin Islands",
38249 "Bulgaria (България)",
38259 "Burundi (Uburundi)",
38264 "Cambodia (កម្ពុជា)",
38269 "Cameroon (Cameroun)",
38278 ["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"]
38281 "Cape Verde (Kabu Verdi)",
38286 "Caribbean Netherlands",
38297 "Central African Republic (République centrafricaine)",
38317 "Christmas Island",
38323 "Cocos (Keeling) Islands",
38334 "Comoros (جزر القمر)",
38339 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38344 "Congo (Republic) (Congo-Brazzaville)",
38364 "Croatia (Hrvatska)",
38385 "Czech Republic (Česká republika)",
38390 "Denmark (Danmark)",
38405 "Dominican Republic (República Dominicana)",
38409 ["809", "829", "849"]
38427 "Equatorial Guinea (Guinea Ecuatorial)",
38447 "Falkland Islands (Islas Malvinas)",
38452 "Faroe Islands (Føroyar)",
38473 "French Guiana (Guyane française)",
38478 "French Polynesia (Polynésie française)",
38493 "Georgia (საქართველო)",
38498 "Germany (Deutschland)",
38518 "Greenland (Kalaallit Nunaat)",
38555 "Guinea-Bissau (Guiné Bissau)",
38580 "Hungary (Magyarország)",
38585 "Iceland (Ísland)",
38605 "Iraq (العراق)",
38621 "Israel (ישראל)",
38648 "Jordan (الأردن)",
38653 "Kazakhstan (Казахстан)",
38674 "Kuwait (الكويت)",
38679 "Kyrgyzstan (Кыргызстан)",
38689 "Latvia (Latvija)",
38694 "Lebanon (لبنان)",
38709 "Libya (ليبيا)",
38719 "Lithuania (Lietuva)",
38734 "Macedonia (FYROM) (Македонија)",
38739 "Madagascar (Madagasikara)",
38769 "Marshall Islands",
38779 "Mauritania (موريتانيا)",
38784 "Mauritius (Moris)",
38805 "Moldova (Republica Moldova)",
38815 "Mongolia (Монгол)",
38820 "Montenegro (Crna Gora)",
38830 "Morocco (المغرب)",
38836 "Mozambique (Moçambique)",
38841 "Myanmar (Burma) (မြန်မာ)",
38846 "Namibia (Namibië)",
38861 "Netherlands (Nederland)",
38866 "New Caledonia (Nouvelle-Calédonie)",
38901 "North Korea (조선 민주주의 인민 공화국)",
38906 "Northern Mariana Islands",
38922 "Pakistan (پاکستان)",
38932 "Palestine (فلسطين)",
38942 "Papua New Guinea",
38984 "Réunion (La Réunion)",
38990 "Romania (România)",
39006 "Saint Barthélemy",
39017 "Saint Kitts and Nevis",
39027 "Saint Martin (Saint-Martin (partie française))",
39033 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39038 "Saint Vincent and the Grenadines",
39053 "São Tomé and Príncipe (São Tomé e Príncipe)",
39058 "Saudi Arabia (المملكة العربية السعودية)",
39063 "Senegal (Sénégal)",
39093 "Slovakia (Slovensko)",
39098 "Slovenia (Slovenija)",
39108 "Somalia (Soomaaliya)",
39118 "South Korea (대한민국)",
39123 "South Sudan (جنوب السودان)",
39133 "Sri Lanka (ශ්රී ලංකාව)",
39138 "Sudan (السودان)",
39148 "Svalbard and Jan Mayen",
39159 "Sweden (Sverige)",
39164 "Switzerland (Schweiz)",
39169 "Syria (سوريا)",
39214 "Trinidad and Tobago",
39219 "Tunisia (تونس)",
39224 "Turkey (Türkiye)",
39234 "Turks and Caicos Islands",
39244 "U.S. Virgin Islands",
39254 "Ukraine (Україна)",
39259 "United Arab Emirates (الإمارات العربية المتحدة)",
39281 "Uzbekistan (Oʻzbekiston)",
39291 "Vatican City (Città del Vaticano)",
39302 "Vietnam (Việt Nam)",
39307 "Wallis and Futuna (Wallis-et-Futuna)",
39312 "Western Sahara (الصحراء الغربية)",
39318 "Yemen (اليمن)",
39342 * This script refer to:
39343 * Title: International Telephone Input
39344 * Author: Jack O'Connor
39345 * Code version: v12.1.12
39346 * Availability: https://github.com/jackocnr/intl-tel-input.git
39350 * @class Roo.bootstrap.PhoneInput
39351 * @extends Roo.bootstrap.TriggerField
39352 * An input with International dial-code selection
39354 * @cfg {String} defaultDialCode default '+852'
39355 * @cfg {Array} preferedCountries default []
39358 * Create a new PhoneInput.
39359 * @param {Object} config Configuration options
39362 Roo.bootstrap.PhoneInput = function(config) {
39363 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39366 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39368 listWidth: undefined,
39370 selectedClass: 'active',
39372 invalidClass : "has-warning",
39374 validClass: 'has-success',
39376 allowed: '0123456789',
39379 * @cfg {String} defaultDialCode The default dial code when initializing the input
39381 defaultDialCode: '+852',
39384 * @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
39386 preferedCountries: false,
39388 getAutoCreate : function()
39390 var data = Roo.bootstrap.PhoneInputData();
39391 var align = this.labelAlign || this.parentLabelAlign();
39394 this.allCountries = [];
39395 this.dialCodeMapping = [];
39397 for (var i = 0; i < data.length; i++) {
39399 this.allCountries[i] = {
39403 priority: c[3] || 0,
39404 areaCodes: c[4] || null
39406 this.dialCodeMapping[c[2]] = {
39409 priority: c[3] || 0,
39410 areaCodes: c[4] || null
39422 cls : 'form-control tel-input',
39423 autocomplete: 'new-password'
39426 var hiddenInput = {
39429 cls: 'hidden-tel-input'
39433 hiddenInput.name = this.name;
39436 if (this.disabled) {
39437 input.disabled = true;
39440 var flag_container = {
39457 cls: this.hasFeedback ? 'has-feedback' : '',
39463 cls: 'dial-code-holder',
39470 cls: 'roo-select2-container input-group',
39477 if (this.fieldLabel.length) {
39480 tooltip: 'This field is required'
39486 cls: 'control-label',
39492 html: this.fieldLabel
39495 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39501 if(this.indicatorpos == 'right') {
39502 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39509 if(align == 'left') {
39517 if(this.labelWidth > 12){
39518 label.style = "width: " + this.labelWidth + 'px';
39520 if(this.labelWidth < 13 && this.labelmd == 0){
39521 this.labelmd = this.labelWidth;
39523 if(this.labellg > 0){
39524 label.cls += ' col-lg-' + this.labellg;
39525 input.cls += ' col-lg-' + (12 - this.labellg);
39527 if(this.labelmd > 0){
39528 label.cls += ' col-md-' + this.labelmd;
39529 container.cls += ' col-md-' + (12 - this.labelmd);
39531 if(this.labelsm > 0){
39532 label.cls += ' col-sm-' + this.labelsm;
39533 container.cls += ' col-sm-' + (12 - this.labelsm);
39535 if(this.labelxs > 0){
39536 label.cls += ' col-xs-' + this.labelxs;
39537 container.cls += ' col-xs-' + (12 - this.labelxs);
39547 var settings = this;
39549 ['xs','sm','md','lg'].map(function(size){
39550 if (settings[size]) {
39551 cfg.cls += ' col-' + size + '-' + settings[size];
39555 this.store = new Roo.data.Store({
39556 proxy : new Roo.data.MemoryProxy({}),
39557 reader : new Roo.data.JsonReader({
39568 'name' : 'dialCode',
39572 'name' : 'priority',
39576 'name' : 'areaCodes',
39583 if(!this.preferedCountries) {
39584 this.preferedCountries = [
39591 var p = this.preferedCountries.reverse();
39594 for (var i = 0; i < p.length; i++) {
39595 for (var j = 0; j < this.allCountries.length; j++) {
39596 if(this.allCountries[j].iso2 == p[i]) {
39597 var t = this.allCountries[j];
39598 this.allCountries.splice(j,1);
39599 this.allCountries.unshift(t);
39605 this.store.proxy.data = {
39607 data: this.allCountries
39613 initEvents : function()
39616 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39618 this.indicator = this.indicatorEl();
39619 this.flag = this.flagEl();
39620 this.dialCodeHolder = this.dialCodeHolderEl();
39622 this.trigger = this.el.select('div.flag-box',true).first();
39623 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39628 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39629 _this.list.setWidth(lw);
39632 this.list.on('mouseover', this.onViewOver, this);
39633 this.list.on('mousemove', this.onViewMove, this);
39634 this.inputEl().on("keyup", this.onKeyUp, this);
39636 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39638 this.view = new Roo.View(this.list, this.tpl, {
39639 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39642 this.view.on('click', this.onViewClick, this);
39643 this.setValue(this.defaultDialCode);
39646 onTriggerClick : function(e)
39648 Roo.log('trigger click');
39653 if(this.isExpanded()){
39655 this.hasFocus = false;
39657 this.store.load({});
39658 this.hasFocus = true;
39663 isExpanded : function()
39665 return this.list.isVisible();
39668 collapse : function()
39670 if(!this.isExpanded()){
39674 Roo.get(document).un('mousedown', this.collapseIf, this);
39675 Roo.get(document).un('mousewheel', this.collapseIf, this);
39676 this.fireEvent('collapse', this);
39680 expand : function()
39684 if(this.isExpanded() || !this.hasFocus){
39688 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39689 this.list.setWidth(lw);
39692 this.restrictHeight();
39694 Roo.get(document).on('mousedown', this.collapseIf, this);
39695 Roo.get(document).on('mousewheel', this.collapseIf, this);
39697 this.fireEvent('expand', this);
39700 restrictHeight : function()
39702 this.list.alignTo(this.inputEl(), this.listAlign);
39703 this.list.alignTo(this.inputEl(), this.listAlign);
39706 onViewOver : function(e, t)
39708 if(this.inKeyMode){
39711 var item = this.view.findItemFromChild(t);
39714 var index = this.view.indexOf(item);
39715 this.select(index, false);
39720 onViewClick : function(view, doFocus, el, e)
39722 var index = this.view.getSelectedIndexes()[0];
39724 var r = this.store.getAt(index);
39727 this.onSelect(r, index);
39729 if(doFocus !== false && !this.blockFocus){
39730 this.inputEl().focus();
39734 onViewMove : function(e, t)
39736 this.inKeyMode = false;
39739 select : function(index, scrollIntoView)
39741 this.selectedIndex = index;
39742 this.view.select(index);
39743 if(scrollIntoView !== false){
39744 var el = this.view.getNode(index);
39746 this.list.scrollChildIntoView(el, false);
39751 createList : function()
39753 this.list = Roo.get(document.body).createChild({
39755 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39756 style: 'display:none'
39758 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39761 collapseIf : function(e)
39763 var in_combo = e.within(this.el);
39764 var in_list = e.within(this.list);
39765 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39767 if (in_combo || in_list || is_list) {
39773 onSelect : function(record, index)
39775 if(this.fireEvent('beforeselect', this, record, index) !== false){
39777 this.setFlagClass(record.data.iso2);
39778 this.setDialCode(record.data.dialCode);
39779 this.hasFocus = false;
39781 this.fireEvent('select', this, record, index);
39785 flagEl : function()
39787 var flag = this.el.select('div.flag',true).first();
39794 dialCodeHolderEl : function()
39796 var d = this.el.select('input.dial-code-holder',true).first();
39803 setDialCode : function(v)
39805 this.dialCodeHolder.dom.value = '+'+v;
39808 setFlagClass : function(n)
39810 this.flag.dom.className = 'flag '+n;
39813 getValue : function()
39815 var v = this.inputEl().getValue();
39816 if(this.dialCodeHolder) {
39817 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39822 setValue : function(v)
39824 var d = this.getDialCode(v);
39826 //invalid dial code
39827 if(v.length == 0 || !d || d.length == 0) {
39829 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39830 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39836 this.setFlagClass(this.dialCodeMapping[d].iso2);
39837 this.setDialCode(d);
39838 this.inputEl().dom.value = v.replace('+'+d,'');
39839 this.hiddenEl().dom.value = this.getValue();
39844 getDialCode : function(v = '')
39846 if (v.length == 0) {
39847 return this.dialCodeHolder.dom.value;
39851 if (v.charAt(0) != "+") {
39854 var numericChars = "";
39855 for (var i = 1; i < v.length; i++) {
39856 var c = v.charAt(i);
39859 if (this.dialCodeMapping[numericChars]) {
39860 dialCode = v.substr(1, i);
39862 if (numericChars.length == 4) {
39872 this.setValue(this.defaultDialCode);
39876 hiddenEl : function()
39878 return this.el.select('input.hidden-tel-input',true).first();
39881 onKeyUp : function(e){
39883 var k = e.getKey();
39884 var c = e.getCharCode();
39887 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39888 this.allowed.indexOf(String.fromCharCode(c)) === -1
39893 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39896 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39900 this.setValue(this.getValue());
39905 * @class Roo.bootstrap.MoneyField
39906 * @extends Roo.bootstrap.ComboBox
39907 * Bootstrap MoneyField class
39910 * Create a new MoneyField.
39911 * @param {Object} config Configuration options
39914 Roo.bootstrap.MoneyField = function(config) {
39916 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39920 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39923 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39925 allowDecimals : true,
39927 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39929 decimalSeparator : ".",
39931 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39933 decimalPrecision : 2,
39935 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39937 allowNegative : true,
39939 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39941 minValue : Number.NEGATIVE_INFINITY,
39943 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39945 maxValue : Number.MAX_VALUE,
39947 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39949 minText : "The minimum value for this field is {0}",
39951 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39953 maxText : "The maximum value for this field is {0}",
39955 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39956 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39958 nanText : "{0} is not a valid number",
39960 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39971 getAutoCreate : function()
39973 var align = this.labelAlign || this.parentLabelAlign();
39985 cls : 'form-control roo-money-amount-input',
39986 autocomplete: 'new-password'
39990 input.name = this.name;
39993 if (this.disabled) {
39994 input.disabled = true;
39997 var clg = 12 - this.inputlg;
39998 var cmd = 12 - this.inputmd;
39999 var csm = 12 - this.inputsm;
40000 var cxs = 12 - this.inputxs;
40004 cls : 'row roo-money-field',
40008 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40012 cls: 'roo-select2-container input-group',
40016 cls : 'form-control roo-money-currency-input',
40017 autocomplete: 'new-password',
40019 name : this.currencyName
40023 cls : 'input-group-addon',
40037 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40041 cls: this.hasFeedback ? 'has-feedback' : '',
40052 if (this.fieldLabel.length) {
40055 tooltip: 'This field is required'
40061 cls: 'control-label',
40067 html: this.fieldLabel
40070 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40076 if(this.indicatorpos == 'right') {
40077 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40084 if(align == 'left') {
40092 if(this.labelWidth > 12){
40093 label.style = "width: " + this.labelWidth + 'px';
40095 if(this.labelWidth < 13 && this.labelmd == 0){
40096 this.labelmd = this.labelWidth;
40098 if(this.labellg > 0){
40099 label.cls += ' col-lg-' + this.labellg;
40100 input.cls += ' col-lg-' + (12 - this.labellg);
40102 if(this.labelmd > 0){
40103 label.cls += ' col-md-' + this.labelmd;
40104 container.cls += ' col-md-' + (12 - this.labelmd);
40106 if(this.labelsm > 0){
40107 label.cls += ' col-sm-' + this.labelsm;
40108 container.cls += ' col-sm-' + (12 - this.labelsm);
40110 if(this.labelxs > 0){
40111 label.cls += ' col-xs-' + this.labelxs;
40112 container.cls += ' col-xs-' + (12 - this.labelxs);
40122 var settings = this;
40124 ['xs','sm','md','lg'].map(function(size){
40125 if (settings[size]) {
40126 cfg.cls += ' col-' + size + '-' + settings[size];
40134 initEvents : function()
40136 this.indicator = this.indicatorEl();
40138 this.initCurrencyEvent();
40140 this.initNumberEvent();
40144 initCurrencyEvent : function()
40147 throw "can not find store for combo";
40150 this.store = Roo.factory(this.store, Roo.data);
40151 this.store.parent = this;
40155 this.triggerEl = this.el.select('.input-group-addon', true).first();
40157 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40162 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40163 _this.list.setWidth(lw);
40166 this.list.on('mouseover', this.onViewOver, this);
40167 this.list.on('mousemove', this.onViewMove, this);
40168 this.list.on('scroll', this.onViewScroll, this);
40171 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40174 this.view = new Roo.View(this.list, this.tpl, {
40175 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40178 this.view.on('click', this.onViewClick, this);
40180 this.store.on('beforeload', this.onBeforeLoad, this);
40181 this.store.on('load', this.onLoad, this);
40182 this.store.on('loadexception', this.onLoadException, this);
40184 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40185 "up" : function(e){
40186 this.inKeyMode = true;
40190 "down" : function(e){
40191 if(!this.isExpanded()){
40192 this.onTriggerClick();
40194 this.inKeyMode = true;
40199 "enter" : function(e){
40202 if(this.fireEvent("specialkey", this, e)){
40203 this.onViewClick(false);
40209 "esc" : function(e){
40213 "tab" : function(e){
40216 if(this.fireEvent("specialkey", this, e)){
40217 this.onViewClick(false);
40225 doRelay : function(foo, bar, hname){
40226 if(hname == 'down' || this.scope.isExpanded()){
40227 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40235 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40239 initNumberEvent : function(e)
40241 this.inputEl().on("keydown" , this.fireKey, this);
40242 this.inputEl().on("focus", this.onFocus, this);
40243 this.inputEl().on("blur", this.onBlur, this);
40245 this.inputEl().relayEvent('keyup', this);
40247 if(this.indicator){
40248 this.indicator.addClass('invisible');
40251 this.originalValue = this.getValue();
40253 if(this.validationEvent == 'keyup'){
40254 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40255 this.inputEl().on('keyup', this.filterValidation, this);
40257 else if(this.validationEvent !== false){
40258 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40261 if(this.selectOnFocus){
40262 this.on("focus", this.preFocus, this);
40265 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40266 this.inputEl().on("keypress", this.filterKeys, this);
40268 this.inputEl().relayEvent('keypress', this);
40271 var allowed = "0123456789";
40273 if(this.allowDecimals){
40274 allowed += this.decimalSeparator;
40277 if(this.allowNegative){
40281 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40283 var keyPress = function(e){
40285 var k = e.getKey();
40287 var c = e.getCharCode();
40290 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40291 allowed.indexOf(String.fromCharCode(c)) === -1
40297 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40301 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40306 this.inputEl().on("keypress", keyPress, this);
40310 onTriggerClick : function(e)
40317 this.loadNext = false;
40319 if(this.isExpanded()){
40324 this.hasFocus = true;
40326 if(this.triggerAction == 'all') {
40327 this.doQuery(this.allQuery, true);
40331 this.doQuery(this.getRawValue());
40334 getCurrency : function()
40336 var v = this.currencyEl().getValue();
40341 restrictHeight : function()
40343 this.list.alignTo(this.currencyEl(), this.listAlign);
40344 this.list.alignTo(this.currencyEl(), this.listAlign);
40347 onViewClick : function(view, doFocus, el, e)
40349 var index = this.view.getSelectedIndexes()[0];
40351 var r = this.store.getAt(index);
40354 this.onSelect(r, index);
40358 onSelect : function(record, index){
40360 if(this.fireEvent('beforeselect', this, record, index) !== false){
40362 this.setFromCurrencyData(index > -1 ? record.data : false);
40366 this.fireEvent('select', this, record, index);
40370 setFromCurrencyData : function(o)
40374 this.lastCurrency = o;
40376 if (this.currencyField) {
40377 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40379 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40382 this.lastSelectionText = currency;
40384 this.setCurrency(currency);
40387 setFromData : function(o)
40391 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40393 this.setFromCurrencyData(c);
40398 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40400 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40403 this.setValue(value);
40407 setCurrency : function(v)
40409 this.currencyValue = v;
40412 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40417 setValue : function(v)
40419 v = this.fixPrecision(v);
40421 v = String(v).replace(".", this.decimalSeparator);
40426 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40431 getRawValue : function()
40433 var v = this.inputEl().getValue();
40438 getValue : function()
40440 return this.fixPrecision(this.parseValue(this.getRawValue()));
40443 parseValue : function(value)
40445 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40446 return isNaN(value) ? '' : value;
40449 fixPrecision : function(value)
40451 var nan = isNaN(value);
40453 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40454 return nan ? '' : value;
40457 return parseFloat(value).toFixed(this.decimalPrecision);
40460 decimalPrecisionFcn : function(v)
40462 return Math.floor(v);
40465 validateValue : function(value)
40467 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40471 var num = this.parseValue(value);
40474 this.markInvalid(String.format(this.nanText, value));
40478 if(num < this.minValue){
40479 this.markInvalid(String.format(this.minText, this.minValue));
40483 if(num > this.maxValue){
40484 this.markInvalid(String.format(this.maxText, this.maxValue));
40491 validate : function()
40493 if(this.disabled || this.allowBlank){
40498 var currency = this.getCurrency();
40500 if(this.validateValue(this.getRawValue()) && currency.length){
40505 this.markInvalid();
40509 getName: function()
40514 beforeBlur : function()
40520 var v = this.parseValue(this.getRawValue());
40527 onBlur : function()
40531 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40532 //this.el.removeClass(this.focusClass);
40535 this.hasFocus = false;
40537 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40541 var v = this.getValue();
40543 if(String(v) !== String(this.startValue)){
40544 this.fireEvent('change', this, v, this.startValue);
40547 this.fireEvent("blur", this);
40550 inputEl : function()
40552 return this.el.select('.roo-money-amount-input', true).first();
40555 currencyEl : function()
40557 return this.el.select('.roo-money-currency-input', true).first();