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 // if parent was disabled, then do not try and create the children..
251 if(!this[cntr](true)){
256 cn = Roo.factory(tree);
258 cn.parentType = this.xtype; //??
259 cn.parentId = this.id;
261 var build_from_html = Roo.XComponent.build_from_html;
264 // does the container contain child eleemnts with 'xtype' attributes.
265 // that match this xtype..
266 // note - when we render we create these as well..
267 // so we should check to see if body has xtype set.
268 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270 var self_cntr_el = Roo.get(this[cntr](false));
271 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273 //Roo.log(Roo.XComponent.build_from_html);
274 //Roo.log("got echild:");
277 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
278 // and are not displayed -this causes this to use up the wrong element when matching.
279 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
282 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
283 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
289 //echild.dom.removeAttribute('xtype');
291 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
292 Roo.debug && Roo.log(self_cntr_el);
293 Roo.debug && Roo.log(echild);
294 Roo.debug && Roo.log(cn);
300 // if object has flexy:if - then it may or may not be rendered.
301 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
302 // skip a flexy if element.
303 Roo.debug && Roo.log('skipping render');
304 Roo.debug && Roo.log(tree);
306 Roo.debug && Roo.log('skipping all children');
307 skip_children = true;
312 // actually if flexy:foreach is found, we really want to create
313 // multiple copies here...
315 //Roo.log(this[cntr]());
316 // some elements do not have render methods.. like the layouts...
318 if(this[cntr](true) === false){
323 cn.render && cn.render(this[cntr](true));
326 // then add the element..
333 if (typeof (tree.menu) != 'undefined') {
334 tree.menu.parentType = cn.xtype;
335 tree.menu.triggerEl = cn.el;
336 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
340 if (!tree.items || !tree.items.length) {
342 //Roo.log(["no children", this]);
347 var items = tree.items;
350 //Roo.log(items.length);
352 if (!skip_children) {
353 for(var i =0;i < items.length;i++) {
354 // Roo.log(['add child', items[i]]);
355 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
361 //Roo.log("fire childrenrendered");
363 cn.fireEvent('childrenrendered', this);
368 * Show a component - removes 'hidden' class
373 this.el.removeClass('hidden');
377 * Hide a component - adds 'hidden' class
381 if (this.el && !this.el.hasClass('hidden')) {
382 this.el.addClass('hidden');
395 * @class Roo.bootstrap.Body
396 * @extends Roo.bootstrap.Component
397 * Bootstrap Body class
401 * @param {Object} config The config object
404 Roo.bootstrap.Body = function(config){
406 config = config || {};
408 Roo.bootstrap.Body.superclass.constructor.call(this, config);
409 this.el = Roo.get(config.el ? config.el : document.body );
410 if (this.cls && this.cls.length) {
411 Roo.get(document.body).addClass(this.cls);
415 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
417 is_body : true,// just to make sure it's constructed?
422 onRender : function(ct, position)
424 /* Roo.log("Roo.bootstrap.Body - onRender");
425 if (this.cls && this.cls.length) {
426 Roo.get(document.body).addClass(this.cls);
445 * @class Roo.bootstrap.ButtonGroup
446 * @extends Roo.bootstrap.Component
447 * Bootstrap ButtonGroup class
448 * @cfg {String} size lg | sm | xs (default empty normal)
449 * @cfg {String} align vertical | justified (default none)
450 * @cfg {String} direction up | down (default down)
451 * @cfg {Boolean} toolbar false | true
452 * @cfg {Boolean} btn true | false
457 * @param {Object} config The config object
460 Roo.bootstrap.ButtonGroup = function(config){
461 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
464 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
472 getAutoCreate : function(){
478 cfg.html = this.html || cfg.html;
489 if (['vertical','justified'].indexOf(this.align)!==-1) {
490 cfg.cls = 'btn-group-' + this.align;
492 if (this.align == 'justified') {
493 console.log(this.items);
497 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
498 cfg.cls += ' btn-group-' + this.size;
501 if (this.direction == 'up') {
502 cfg.cls += ' dropup' ;
518 * @class Roo.bootstrap.Button
519 * @extends Roo.bootstrap.Component
520 * Bootstrap Button class
521 * @cfg {String} html The button content
522 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
523 * @cfg {String} size ( lg | sm | xs)
524 * @cfg {String} tag ( a | input | submit)
525 * @cfg {String} href empty or href
526 * @cfg {Boolean} disabled default false;
527 * @cfg {Boolean} isClose default false;
528 * @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)
529 * @cfg {String} badge text for badge
530 * @cfg {String} theme default
531 * @cfg {Boolean} inverse
532 * @cfg {Boolean} toggle
533 * @cfg {String} ontext text for on toggle state
534 * @cfg {String} offtext text for off toggle state
535 * @cfg {Boolean} defaulton
536 * @cfg {Boolean} preventDefault default true
537 * @cfg {Boolean} removeClass remove the standard class..
538 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
541 * Create a new button
542 * @param {Object} config The config object
546 Roo.bootstrap.Button = function(config){
547 Roo.bootstrap.Button.superclass.constructor.call(this, config);
548 this.weightClass = ["btn-default",
560 * When a butotn is pressed
561 * @param {Roo.bootstrap.Button} this
562 * @param {Roo.EventObject} e
567 * After the button has been toggles
568 * @param {Roo.EventObject} e
569 * @param {boolean} pressed (also available as button.pressed)
575 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
593 preventDefault: true,
602 getAutoCreate : function(){
610 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
611 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
616 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
618 if (this.toggle == true) {
621 cls: 'slider-frame roo-button',
626 'data-off-text':'OFF',
627 cls: 'slider-button',
633 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
634 cfg.cls += ' '+this.weight;
643 cfg["aria-hidden"] = true;
645 cfg.html = "×";
651 if (this.theme==='default') {
652 cfg.cls = 'btn roo-button';
654 //if (this.parentType != 'Navbar') {
655 this.weight = this.weight.length ? this.weight : 'default';
657 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
659 cfg.cls += ' btn-' + this.weight;
661 } else if (this.theme==='glow') {
664 cfg.cls = 'btn-glow roo-button';
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
668 cfg.cls += ' ' + this.weight;
674 this.cls += ' inverse';
679 cfg.cls += ' active';
683 cfg.disabled = 'disabled';
687 Roo.log('changing to ul' );
689 this.glyphicon = 'caret';
692 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
694 //gsRoo.log(this.parentType);
695 if (this.parentType === 'Navbar' && !this.parent().bar) {
696 Roo.log('changing to li?');
705 href : this.href || '#'
708 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
709 cfg.cls += ' dropdown';
716 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
718 if (this.glyphicon) {
719 cfg.html = ' ' + cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon
734 // cfg.cls='btn roo-button';
738 var value = cfg.html;
743 cls: 'glyphicon glyphicon-' + this.glyphicon,
762 cfg.cls += ' dropdown';
763 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
766 if (cfg.tag !== 'a' && this.href !== '') {
767 throw "Tag must be a to set href.";
768 } else if (this.href.length > 0) {
769 cfg.href = this.href;
772 if(this.removeClass){
777 cfg.target = this.target;
782 initEvents: function() {
783 // Roo.log('init events?');
784 // Roo.log(this.el.dom);
787 if (typeof (this.menu) != 'undefined') {
788 this.menu.parentType = this.xtype;
789 this.menu.triggerEl = this.el;
790 this.addxtype(Roo.apply({}, this.menu));
794 if (this.el.hasClass('roo-button')) {
795 this.el.on('click', this.onClick, this);
797 this.el.select('.roo-button').on('click', this.onClick, this);
800 if(this.removeClass){
801 this.el.on('click', this.onClick, this);
804 this.el.enableDisplayMode();
807 onClick : function(e)
814 Roo.log('button on click ');
815 if(this.preventDefault){
818 if (this.pressed === true || this.pressed === false) {
819 this.pressed = !this.pressed;
820 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
821 this.fireEvent('toggle', this, e, this.pressed);
825 this.fireEvent('click', this, e);
829 * Enables this button
833 this.disabled = false;
834 this.el.removeClass('disabled');
838 * Disable this button
842 this.disabled = true;
843 this.el.addClass('disabled');
846 * sets the active state on/off,
847 * @param {Boolean} state (optional) Force a particular state
849 setActive : function(v) {
851 this.el[v ? 'addClass' : 'removeClass']('active');
854 * toggles the current active state
856 toggleActive : function()
858 var active = this.el.hasClass('active');
859 this.setActive(!active);
863 setText : function(str)
865 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
869 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
880 setWeight : function(str)
882 this.el.removeClass(this.weightClass);
883 this.el.addClass('btn-' + str);
897 * @class Roo.bootstrap.Column
898 * @extends Roo.bootstrap.Component
899 * Bootstrap Column class
900 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
901 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
902 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
903 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
904 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
905 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
906 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
907 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
910 * @cfg {Boolean} hidden (true|false) hide the element
911 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
912 * @cfg {String} fa (ban|check|...) font awesome icon
913 * @cfg {Number} fasize (1|2|....) font awsome size
915 * @cfg {String} icon (info-sign|check|...) glyphicon name
917 * @cfg {String} html content of column.
920 * Create a new Column
921 * @param {Object} config The config object
924 Roo.bootstrap.Column = function(config){
925 Roo.bootstrap.Column.superclass.constructor.call(this, config);
928 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
946 getAutoCreate : function(){
947 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
955 ['xs','sm','md','lg'].map(function(size){
956 //Roo.log( size + ':' + settings[size]);
958 if (settings[size+'off'] !== false) {
959 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
962 if (settings[size] === false) {
966 if (!settings[size]) { // 0 = hidden
967 cfg.cls += ' hidden-' + size;
970 cfg.cls += ' col-' + size + '-' + settings[size];
975 cfg.cls += ' hidden';
978 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
979 cfg.cls +=' alert alert-' + this.alert;
983 if (this.html.length) {
984 cfg.html = this.html;
988 if (this.fasize > 1) {
989 fasize = ' fa-' + this.fasize + 'x';
991 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
996 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1015 * @class Roo.bootstrap.Container
1016 * @extends Roo.bootstrap.Component
1017 * Bootstrap Container class
1018 * @cfg {Boolean} jumbotron is it a jumbotron element
1019 * @cfg {String} html content of element
1020 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1021 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1022 * @cfg {String} header content of header (for panel)
1023 * @cfg {String} footer content of footer (for panel)
1024 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1025 * @cfg {String} tag (header|aside|section) type of HTML tag.
1026 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1027 * @cfg {String} fa font awesome icon
1028 * @cfg {String} icon (info-sign|check|...) glyphicon name
1029 * @cfg {Boolean} hidden (true|false) hide the element
1030 * @cfg {Boolean} expandable (true|false) default false
1031 * @cfg {Boolean} expanded (true|false) default true
1032 * @cfg {String} rheader contet on the right of header
1033 * @cfg {Boolean} clickable (true|false) default false
1037 * Create a new Container
1038 * @param {Object} config The config object
1041 Roo.bootstrap.Container = function(config){
1042 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1048 * After the panel has been expand
1050 * @param {Roo.bootstrap.Container} this
1055 * After the panel has been collapsed
1057 * @param {Roo.bootstrap.Container} this
1062 * When a element is chick
1063 * @param {Roo.bootstrap.Container} this
1064 * @param {Roo.EventObject} e
1070 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1088 getChildContainer : function() {
1094 if (this.panel.length) {
1095 return this.el.select('.panel-body',true).first();
1102 getAutoCreate : function(){
1105 tag : this.tag || 'div',
1109 if (this.jumbotron) {
1110 cfg.cls = 'jumbotron';
1115 // - this is applied by the parent..
1117 // cfg.cls = this.cls + '';
1120 if (this.sticky.length) {
1122 var bd = Roo.get(document.body);
1123 if (!bd.hasClass('bootstrap-sticky')) {
1124 bd.addClass('bootstrap-sticky');
1125 Roo.select('html',true).setStyle('height', '100%');
1128 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1132 if (this.well.length) {
1133 switch (this.well) {
1136 cfg.cls +=' well well-' +this.well;
1145 cfg.cls += ' hidden';
1149 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1150 cfg.cls +=' alert alert-' + this.alert;
1155 if (this.panel.length) {
1156 cfg.cls += ' panel panel-' + this.panel;
1158 if (this.header.length) {
1162 if(this.expandable){
1164 cfg.cls = cfg.cls + ' expandable';
1168 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1176 cls : 'panel-title',
1177 html : (this.expandable ? ' ' : '') + this.header
1181 cls: 'panel-header-right',
1187 cls : 'panel-heading',
1188 style : this.expandable ? 'cursor: pointer' : '',
1196 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1201 if (this.footer.length) {
1203 cls : 'panel-footer',
1212 body.html = this.html || cfg.html;
1213 // prefix with the icons..
1215 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1218 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1223 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1224 cfg.cls = 'container';
1230 initEvents: function()
1232 if(this.expandable){
1233 var headerEl = this.headerEl();
1236 headerEl.on('click', this.onToggleClick, this);
1241 this.el.on('click', this.onClick, this);
1246 onToggleClick : function()
1248 var headerEl = this.headerEl();
1264 if(this.fireEvent('expand', this)) {
1266 this.expanded = true;
1268 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1270 this.el.select('.panel-body',true).first().removeClass('hide');
1272 var toggleEl = this.toggleEl();
1278 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1283 collapse : function()
1285 if(this.fireEvent('collapse', this)) {
1287 this.expanded = false;
1289 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1290 this.el.select('.panel-body',true).first().addClass('hide');
1292 var toggleEl = this.toggleEl();
1298 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1302 toggleEl : function()
1304 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1308 return this.el.select('.panel-heading .fa',true).first();
1311 headerEl : function()
1313 if(!this.el || !this.panel.length || !this.header.length){
1317 return this.el.select('.panel-heading',true).first()
1322 if(!this.el || !this.panel.length){
1326 return this.el.select('.panel-body',true).first()
1329 titleEl : function()
1331 if(!this.el || !this.panel.length || !this.header.length){
1335 return this.el.select('.panel-title',true).first();
1338 setTitle : function(v)
1340 var titleEl = this.titleEl();
1346 titleEl.dom.innerHTML = v;
1349 getTitle : function()
1352 var titleEl = this.titleEl();
1358 return titleEl.dom.innerHTML;
1361 setRightTitle : function(v)
1363 var t = this.el.select('.panel-header-right',true).first();
1369 t.dom.innerHTML = v;
1372 onClick : function(e)
1376 this.fireEvent('click', this, e);
1390 * @class Roo.bootstrap.Img
1391 * @extends Roo.bootstrap.Component
1392 * Bootstrap Img class
1393 * @cfg {Boolean} imgResponsive false | true
1394 * @cfg {String} border rounded | circle | thumbnail
1395 * @cfg {String} src image source
1396 * @cfg {String} alt image alternative text
1397 * @cfg {String} href a tag href
1398 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1399 * @cfg {String} xsUrl xs image source
1400 * @cfg {String} smUrl sm image source
1401 * @cfg {String} mdUrl md image source
1402 * @cfg {String} lgUrl lg image source
1405 * Create a new Input
1406 * @param {Object} config The config object
1409 Roo.bootstrap.Img = function(config){
1410 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1416 * The img click event for the img.
1417 * @param {Roo.EventObject} e
1423 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1425 imgResponsive: true,
1435 getAutoCreate : function()
1437 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1438 return this.createSingleImg();
1443 cls: 'roo-image-responsive-group',
1448 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1450 if(!_this[size + 'Url']){
1456 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1457 html: _this.html || cfg.html,
1458 src: _this[size + 'Url']
1461 img.cls += ' roo-image-responsive-' + size;
1463 var s = ['xs', 'sm', 'md', 'lg'];
1465 s.splice(s.indexOf(size), 1);
1467 Roo.each(s, function(ss){
1468 img.cls += ' hidden-' + ss;
1471 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1472 cfg.cls += ' img-' + _this.border;
1476 cfg.alt = _this.alt;
1489 a.target = _this.target;
1493 cfg.cn.push((_this.href) ? a : img);
1500 createSingleImg : function()
1504 cls: (this.imgResponsive) ? 'img-responsive' : '',
1506 src : 'about:blank' // just incase src get's set to undefined?!?
1509 cfg.html = this.html || cfg.html;
1511 cfg.src = this.src || cfg.src;
1513 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1514 cfg.cls += ' img-' + this.border;
1531 a.target = this.target;
1536 return (this.href) ? a : cfg;
1539 initEvents: function()
1542 this.el.on('click', this.onClick, this);
1547 onClick : function(e)
1549 Roo.log('img onclick');
1550 this.fireEvent('click', this, e);
1553 * Sets the url of the image - used to update it
1554 * @param {String} url the url of the image
1557 setSrc : function(url)
1561 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1562 this.el.dom.src = url;
1566 this.el.select('img', true).first().dom.src = url;
1582 * @class Roo.bootstrap.Link
1583 * @extends Roo.bootstrap.Component
1584 * Bootstrap Link Class
1585 * @cfg {String} alt image alternative text
1586 * @cfg {String} href a tag href
1587 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1588 * @cfg {String} html the content of the link.
1589 * @cfg {String} anchor name for the anchor link
1590 * @cfg {String} fa - favicon
1592 * @cfg {Boolean} preventDefault (true | false) default false
1596 * Create a new Input
1597 * @param {Object} config The config object
1600 Roo.bootstrap.Link = function(config){
1601 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1607 * The img click event for the img.
1608 * @param {Roo.EventObject} e
1614 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1618 preventDefault: false,
1624 getAutoCreate : function()
1626 var html = this.html || '';
1628 if (this.fa !== false) {
1629 html = '<i class="fa fa-' + this.fa + '"></i>';
1634 // anchor's do not require html/href...
1635 if (this.anchor === false) {
1637 cfg.href = this.href || '#';
1639 cfg.name = this.anchor;
1640 if (this.html !== false || this.fa !== false) {
1643 if (this.href !== false) {
1644 cfg.href = this.href;
1648 if(this.alt !== false){
1653 if(this.target !== false) {
1654 cfg.target = this.target;
1660 initEvents: function() {
1662 if(!this.href || this.preventDefault){
1663 this.el.on('click', this.onClick, this);
1667 onClick : function(e)
1669 if(this.preventDefault){
1672 //Roo.log('img onclick');
1673 this.fireEvent('click', this, e);
1686 * @class Roo.bootstrap.Header
1687 * @extends Roo.bootstrap.Component
1688 * Bootstrap Header class
1689 * @cfg {String} html content of header
1690 * @cfg {Number} level (1|2|3|4|5|6) default 1
1693 * Create a new Header
1694 * @param {Object} config The config object
1698 Roo.bootstrap.Header = function(config){
1699 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1702 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1710 getAutoCreate : function(){
1715 tag: 'h' + (1 *this.level),
1716 html: this.html || ''
1728 * Ext JS Library 1.1.1
1729 * Copyright(c) 2006-2007, Ext JS, LLC.
1731 * Originally Released Under LGPL - original licence link has changed is not relivant.
1734 * <script type="text/javascript">
1738 * @class Roo.bootstrap.MenuMgr
1739 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1742 Roo.bootstrap.MenuMgr = function(){
1743 var menus, active, groups = {}, attached = false, lastShow = new Date();
1745 // private - called when first menu is created
1748 active = new Roo.util.MixedCollection();
1749 Roo.get(document).addKeyListener(27, function(){
1750 if(active.length > 0){
1758 if(active && active.length > 0){
1759 var c = active.clone();
1769 if(active.length < 1){
1770 Roo.get(document).un("mouseup", onMouseDown);
1778 var last = active.last();
1779 lastShow = new Date();
1782 Roo.get(document).on("mouseup", onMouseDown);
1787 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1788 m.parentMenu.activeChild = m;
1789 }else if(last && last.isVisible()){
1790 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1795 function onBeforeHide(m){
1797 m.activeChild.hide();
1799 if(m.autoHideTimer){
1800 clearTimeout(m.autoHideTimer);
1801 delete m.autoHideTimer;
1806 function onBeforeShow(m){
1807 var pm = m.parentMenu;
1808 if(!pm && !m.allowOtherMenus){
1810 }else if(pm && pm.activeChild && active != m){
1811 pm.activeChild.hide();
1815 // private this should really trigger on mouseup..
1816 function onMouseDown(e){
1817 Roo.log("on Mouse Up");
1819 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1820 Roo.log("MenuManager hideAll");
1829 function onBeforeCheck(mi, state){
1831 var g = groups[mi.group];
1832 for(var i = 0, l = g.length; i < l; i++){
1834 g[i].setChecked(false);
1843 * Hides all menus that are currently visible
1845 hideAll : function(){
1850 register : function(menu){
1854 menus[menu.id] = menu;
1855 menu.on("beforehide", onBeforeHide);
1856 menu.on("hide", onHide);
1857 menu.on("beforeshow", onBeforeShow);
1858 menu.on("show", onShow);
1860 if(g && menu.events["checkchange"]){
1864 groups[g].push(menu);
1865 menu.on("checkchange", onCheck);
1870 * Returns a {@link Roo.menu.Menu} object
1871 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1872 * be used to generate and return a new Menu instance.
1874 get : function(menu){
1875 if(typeof menu == "string"){ // menu id
1877 }else if(menu.events){ // menu instance
1880 /*else if(typeof menu.length == 'number'){ // array of menu items?
1881 return new Roo.bootstrap.Menu({items:menu});
1882 }else{ // otherwise, must be a config
1883 return new Roo.bootstrap.Menu(menu);
1890 unregister : function(menu){
1891 delete menus[menu.id];
1892 menu.un("beforehide", onBeforeHide);
1893 menu.un("hide", onHide);
1894 menu.un("beforeshow", onBeforeShow);
1895 menu.un("show", onShow);
1897 if(g && menu.events["checkchange"]){
1898 groups[g].remove(menu);
1899 menu.un("checkchange", onCheck);
1904 registerCheckable : function(menuItem){
1905 var g = menuItem.group;
1910 groups[g].push(menuItem);
1911 menuItem.on("beforecheckchange", onBeforeCheck);
1916 unregisterCheckable : function(menuItem){
1917 var g = menuItem.group;
1919 groups[g].remove(menuItem);
1920 menuItem.un("beforecheckchange", onBeforeCheck);
1932 * @class Roo.bootstrap.Menu
1933 * @extends Roo.bootstrap.Component
1934 * Bootstrap Menu class - container for MenuItems
1935 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1936 * @cfg {bool} hidden if the menu should be hidden when rendered.
1937 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1938 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1942 * @param {Object} config The config object
1946 Roo.bootstrap.Menu = function(config){
1947 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1948 if (this.registerMenu && this.type != 'treeview') {
1949 Roo.bootstrap.MenuMgr.register(this);
1954 * Fires before this menu is displayed
1955 * @param {Roo.menu.Menu} this
1960 * Fires before this menu is hidden
1961 * @param {Roo.menu.Menu} this
1966 * Fires after this menu is displayed
1967 * @param {Roo.menu.Menu} this
1972 * Fires after this menu is hidden
1973 * @param {Roo.menu.Menu} this
1978 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1979 * @param {Roo.menu.Menu} this
1980 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1981 * @param {Roo.EventObject} e
1986 * Fires when the mouse is hovering over this menu
1987 * @param {Roo.menu.Menu} this
1988 * @param {Roo.EventObject} e
1989 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1994 * Fires when the mouse exits this menu
1995 * @param {Roo.menu.Menu} this
1996 * @param {Roo.EventObject} e
1997 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2002 * Fires when a menu item contained in this menu is clicked
2003 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2004 * @param {Roo.EventObject} e
2008 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2011 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2015 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2018 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2020 registerMenu : true,
2022 menuItems :false, // stores the menu items..
2032 getChildContainer : function() {
2036 getAutoCreate : function(){
2038 //if (['right'].indexOf(this.align)!==-1) {
2039 // cfg.cn[1].cls += ' pull-right'
2045 cls : 'dropdown-menu' ,
2046 style : 'z-index:1000'
2050 if (this.type === 'submenu') {
2051 cfg.cls = 'submenu active';
2053 if (this.type === 'treeview') {
2054 cfg.cls = 'treeview-menu';
2059 initEvents : function() {
2061 // Roo.log("ADD event");
2062 // Roo.log(this.triggerEl.dom);
2064 this.triggerEl.on('click', this.onTriggerClick, this);
2066 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2068 this.triggerEl.addClass('dropdown-toggle');
2071 this.el.on('touchstart' , this.onTouch, this);
2073 this.el.on('click' , this.onClick, this);
2075 this.el.on("mouseover", this.onMouseOver, this);
2076 this.el.on("mouseout", this.onMouseOut, this);
2080 findTargetItem : function(e)
2082 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2086 //Roo.log(t); Roo.log(t.id);
2088 //Roo.log(this.menuitems);
2089 return this.menuitems.get(t.id);
2091 //return this.items.get(t.menuItemId);
2097 onTouch : function(e)
2099 Roo.log("menu.onTouch");
2100 //e.stopEvent(); this make the user popdown broken
2104 onClick : function(e)
2106 Roo.log("menu.onClick");
2108 var t = this.findTargetItem(e);
2109 if(!t || t.isContainer){
2114 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2115 if(t == this.activeItem && t.shouldDeactivate(e)){
2116 this.activeItem.deactivate();
2117 delete this.activeItem;
2121 this.setActiveItem(t, true);
2129 Roo.log('pass click event');
2133 this.fireEvent("click", this, t, e);
2137 if(!t.href.length || t.href == '#'){
2138 (function() { _this.hide(); }).defer(100);
2143 onMouseOver : function(e){
2144 var t = this.findTargetItem(e);
2147 // if(t.canActivate && !t.disabled){
2148 // this.setActiveItem(t, true);
2152 this.fireEvent("mouseover", this, e, t);
2154 isVisible : function(){
2155 return !this.hidden;
2157 onMouseOut : function(e){
2158 var t = this.findTargetItem(e);
2161 // if(t == this.activeItem && t.shouldDeactivate(e)){
2162 // this.activeItem.deactivate();
2163 // delete this.activeItem;
2166 this.fireEvent("mouseout", this, e, t);
2171 * Displays this menu relative to another element
2172 * @param {String/HTMLElement/Roo.Element} element The element to align to
2173 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2174 * the element (defaults to this.defaultAlign)
2175 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2177 show : function(el, pos, parentMenu){
2178 this.parentMenu = parentMenu;
2182 this.fireEvent("beforeshow", this);
2183 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2186 * Displays this menu at a specific xy position
2187 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2188 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2190 showAt : function(xy, parentMenu, /* private: */_e){
2191 this.parentMenu = parentMenu;
2196 this.fireEvent("beforeshow", this);
2197 //xy = this.el.adjustForConstraints(xy);
2201 this.hideMenuItems();
2202 this.hidden = false;
2203 this.triggerEl.addClass('open');
2205 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2206 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2209 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2214 this.fireEvent("show", this);
2220 this.doFocus.defer(50, this);
2224 doFocus : function(){
2226 this.focusEl.focus();
2231 * Hides this menu and optionally all parent menus
2232 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2234 hide : function(deep)
2237 this.hideMenuItems();
2238 if(this.el && this.isVisible()){
2239 this.fireEvent("beforehide", this);
2240 if(this.activeItem){
2241 this.activeItem.deactivate();
2242 this.activeItem = null;
2244 this.triggerEl.removeClass('open');;
2246 this.fireEvent("hide", this);
2248 if(deep === true && this.parentMenu){
2249 this.parentMenu.hide(true);
2253 onTriggerClick : function(e)
2255 Roo.log('trigger click');
2257 var target = e.getTarget();
2259 Roo.log(target.nodeName.toLowerCase());
2261 if(target.nodeName.toLowerCase() === 'i'){
2267 onTriggerPress : function(e)
2269 Roo.log('trigger press');
2270 //Roo.log(e.getTarget());
2271 // Roo.log(this.triggerEl.dom);
2273 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2274 var pel = Roo.get(e.getTarget());
2275 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2276 Roo.log('is treeview or dropdown?');
2280 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2284 if (this.isVisible()) {
2289 this.show(this.triggerEl, false, false);
2292 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2299 hideMenuItems : function()
2301 Roo.log("hide Menu Items");
2305 //$(backdrop).remove()
2306 this.el.select('.open',true).each(function(aa) {
2308 aa.removeClass('open');
2309 //var parent = getParent($(this))
2310 //var relatedTarget = { relatedTarget: this }
2312 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2313 //if (e.isDefaultPrevented()) return
2314 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2317 addxtypeChild : function (tree, cntr) {
2318 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2320 this.menuitems.add(comp);
2341 * @class Roo.bootstrap.MenuItem
2342 * @extends Roo.bootstrap.Component
2343 * Bootstrap MenuItem class
2344 * @cfg {String} html the menu label
2345 * @cfg {String} href the link
2346 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2347 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2348 * @cfg {Boolean} active used on sidebars to highlight active itesm
2349 * @cfg {String} fa favicon to show on left of menu item.
2350 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2354 * Create a new MenuItem
2355 * @param {Object} config The config object
2359 Roo.bootstrap.MenuItem = function(config){
2360 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2365 * The raw click event for the entire grid.
2366 * @param {Roo.bootstrap.MenuItem} this
2367 * @param {Roo.EventObject} e
2373 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2377 preventDefault: false,
2378 isContainer : false,
2382 getAutoCreate : function(){
2384 if(this.isContainer){
2387 cls: 'dropdown-menu-item'
2401 if (this.fa !== false) {
2404 cls : 'fa fa-' + this.fa
2413 cls: 'dropdown-menu-item',
2416 if (this.parent().type == 'treeview') {
2417 cfg.cls = 'treeview-menu';
2420 cfg.cls += ' active';
2425 anc.href = this.href || cfg.cn[0].href ;
2426 ctag.html = this.html || cfg.cn[0].html ;
2430 initEvents: function()
2432 if (this.parent().type == 'treeview') {
2433 this.el.select('a').on('click', this.onClick, this);
2437 this.menu.parentType = this.xtype;
2438 this.menu.triggerEl = this.el;
2439 this.menu = this.addxtype(Roo.apply({}, this.menu));
2443 onClick : function(e)
2445 Roo.log('item on click ');
2447 if(this.preventDefault){
2450 //this.parent().hideMenuItems();
2452 this.fireEvent('click', this, e);
2471 * @class Roo.bootstrap.MenuSeparator
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuSeparator class
2476 * Create a new MenuItem
2477 * @param {Object} config The config object
2481 Roo.bootstrap.MenuSeparator = function(config){
2482 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2485 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2487 getAutoCreate : function(){
2506 * @class Roo.bootstrap.Modal
2507 * @extends Roo.bootstrap.Component
2508 * Bootstrap Modal class
2509 * @cfg {String} title Title of dialog
2510 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2511 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2512 * @cfg {Boolean} specificTitle default false
2513 * @cfg {Array} buttons Array of buttons or standard button set..
2514 * @cfg {String} buttonPosition (left|right|center) default right
2515 * @cfg {Boolean} animate default true
2516 * @cfg {Boolean} allow_close default true
2517 * @cfg {Boolean} fitwindow default false
2518 * @cfg {String} size (sm|lg) default empty
2522 * Create a new Modal Dialog
2523 * @param {Object} config The config object
2526 Roo.bootstrap.Modal = function(config){
2527 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2532 * The raw btnclick event for the button
2533 * @param {Roo.EventObject} e
2538 * Fire when dialog resize
2539 * @param {Roo.bootstrap.Modal} this
2540 * @param {Roo.EventObject} e
2544 this.buttons = this.buttons || [];
2547 this.tmpl = Roo.factory(this.tmpl);
2552 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2554 title : 'test dialog',
2564 specificTitle: false,
2566 buttonPosition: 'right',
2585 onRender : function(ct, position)
2587 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2590 var cfg = Roo.apply({}, this.getAutoCreate());
2593 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2595 //if (!cfg.name.length) {
2599 cfg.cls += ' ' + this.cls;
2602 cfg.style = this.style;
2604 this.el = Roo.get(document.body).createChild(cfg, position);
2606 //var type = this.el.dom.type;
2609 if(this.tabIndex !== undefined){
2610 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2613 this.dialogEl = this.el.select('.modal-dialog',true).first();
2614 this.bodyEl = this.el.select('.modal-body',true).first();
2615 this.closeEl = this.el.select('.modal-header .close', true).first();
2616 this.headerEl = this.el.select('.modal-header',true).first();
2617 this.titleEl = this.el.select('.modal-title',true).first();
2618 this.footerEl = this.el.select('.modal-footer',true).first();
2620 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2621 this.maskEl.enableDisplayMode("block");
2623 //this.el.addClass("x-dlg-modal");
2625 if (this.buttons.length) {
2626 Roo.each(this.buttons, function(bb) {
2627 var b = Roo.apply({}, bb);
2628 b.xns = b.xns || Roo.bootstrap;
2629 b.xtype = b.xtype || 'Button';
2630 if (typeof(b.listeners) == 'undefined') {
2631 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2634 var btn = Roo.factory(b);
2636 btn.render(this.el.select('.modal-footer div').first());
2640 // render the children.
2643 if(typeof(this.items) != 'undefined'){
2644 var items = this.items;
2647 for(var i =0;i < items.length;i++) {
2648 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2652 this.items = nitems;
2654 // where are these used - they used to be body/close/footer
2658 //this.el.addClass([this.fieldClass, this.cls]);
2662 getAutoCreate : function(){
2667 html : this.html || ''
2672 cls : 'modal-title',
2676 if(this.specificTitle){
2682 if (this.allow_close) {
2694 if(this.size.length){
2695 size = 'modal-' + this.size;
2700 style : 'display: none',
2703 cls: "modal-dialog " + size,
2706 cls : "modal-content",
2709 cls : 'modal-header',
2714 cls : 'modal-footer',
2718 cls: 'btn-' + this.buttonPosition
2735 modal.cls += ' fade';
2741 getChildContainer : function() {
2746 getButtonContainer : function() {
2747 return this.el.select('.modal-footer div',true).first();
2750 initEvents : function()
2752 if (this.allow_close) {
2753 this.closeEl.on('click', this.hide, this);
2755 Roo.EventManager.onWindowResize(this.resize, this, true);
2762 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2763 if (this.fitwindow) {
2764 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2765 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2770 setSize : function(w,h)
2780 if (!this.rendered) {
2784 this.el.setStyle('display', 'block');
2786 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2789 this.el.addClass('in');
2792 this.el.addClass('in');
2796 // not sure how we can show data in here..
2798 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2801 Roo.get(document.body).addClass("x-body-masked");
2803 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2804 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2809 this.fireEvent('show', this);
2811 // set zindex here - otherwise it appears to be ignored...
2812 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2815 this.items.forEach( function(e) {
2816 e.layout ? e.layout() : false;
2824 if(this.fireEvent("beforehide", this) !== false){
2826 Roo.get(document.body).removeClass("x-body-masked");
2827 this.el.removeClass('in');
2828 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2830 if(this.animate){ // why
2832 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2834 this.el.setStyle('display', 'none');
2836 this.fireEvent('hide', this);
2840 addButton : function(str, cb)
2844 var b = Roo.apply({}, { html : str } );
2845 b.xns = b.xns || Roo.bootstrap;
2846 b.xtype = b.xtype || 'Button';
2847 if (typeof(b.listeners) == 'undefined') {
2848 b.listeners = { click : cb.createDelegate(this) };
2851 var btn = Roo.factory(b);
2853 btn.render(this.el.select('.modal-footer div').first());
2859 setDefaultButton : function(btn)
2861 //this.el.select('.modal-footer').()
2865 resizeTo: function(w,h)
2869 this.dialogEl.setWidth(w);
2870 if (this.diff === false) {
2871 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2874 this.bodyEl.setHeight(h-this.diff);
2876 this.fireEvent('resize', this);
2879 setContentSize : function(w, h)
2883 onButtonClick: function(btn,e)
2886 this.fireEvent('btnclick', btn.name, e);
2889 * Set the title of the Dialog
2890 * @param {String} str new Title
2892 setTitle: function(str) {
2893 this.titleEl.dom.innerHTML = str;
2896 * Set the body of the Dialog
2897 * @param {String} str new Title
2899 setBody: function(str) {
2900 this.bodyEl.dom.innerHTML = str;
2903 * Set the body of the Dialog using the template
2904 * @param {Obj} data - apply this data to the template and replace the body contents.
2906 applyBody: function(obj)
2909 Roo.log("Error - using apply Body without a template");
2912 this.tmpl.overwrite(this.bodyEl, obj);
2918 Roo.apply(Roo.bootstrap.Modal, {
2920 * Button config that displays a single OK button
2929 * Button config that displays Yes and No buttons
2945 * Button config that displays OK and Cancel buttons
2960 * Button config that displays Yes, No and Cancel buttons
2984 * messagebox - can be used as a replace
2988 * @class Roo.MessageBox
2989 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2993 Roo.Msg.alert('Status', 'Changes saved successfully.');
2995 // Prompt for user data:
2996 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2998 // process text value...
3002 // Show a dialog using config options:
3004 title:'Save Changes?',
3005 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3006 buttons: Roo.Msg.YESNOCANCEL,
3013 Roo.bootstrap.MessageBox = function(){
3014 var dlg, opt, mask, waitTimer;
3015 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3016 var buttons, activeTextEl, bwidth;
3020 var handleButton = function(button){
3022 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3026 var handleHide = function(){
3028 dlg.el.removeClass(opt.cls);
3031 // Roo.TaskMgr.stop(waitTimer);
3032 // waitTimer = null;
3037 var updateButtons = function(b){
3040 buttons["ok"].hide();
3041 buttons["cancel"].hide();
3042 buttons["yes"].hide();
3043 buttons["no"].hide();
3044 //dlg.footer.dom.style.display = 'none';
3047 dlg.footerEl.dom.style.display = '';
3048 for(var k in buttons){
3049 if(typeof buttons[k] != "function"){
3052 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3053 width += buttons[k].el.getWidth()+15;
3063 var handleEsc = function(d, k, e){
3064 if(opt && opt.closable !== false){
3074 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3075 * @return {Roo.BasicDialog} The BasicDialog element
3077 getDialog : function(){
3079 dlg = new Roo.bootstrap.Modal( {
3082 //constraintoviewport:false,
3084 //collapsible : false,
3089 //buttonAlign:"center",
3090 closeClick : function(){
3091 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3094 handleButton("cancel");
3099 dlg.on("hide", handleHide);
3101 //dlg.addKeyListener(27, handleEsc);
3103 this.buttons = buttons;
3104 var bt = this.buttonText;
3105 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3106 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3107 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3108 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3110 bodyEl = dlg.bodyEl.createChild({
3112 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3113 '<textarea class="roo-mb-textarea"></textarea>' +
3114 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3116 msgEl = bodyEl.dom.firstChild;
3117 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3118 textboxEl.enableDisplayMode();
3119 textboxEl.addKeyListener([10,13], function(){
3120 if(dlg.isVisible() && opt && opt.buttons){
3123 }else if(opt.buttons.yes){
3124 handleButton("yes");
3128 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3129 textareaEl.enableDisplayMode();
3130 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3131 progressEl.enableDisplayMode();
3133 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3134 var pf = progressEl.dom.firstChild;
3136 pp = Roo.get(pf.firstChild);
3137 pp.setHeight(pf.offsetHeight);
3145 * Updates the message box body text
3146 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3147 * the XHTML-compliant non-breaking space character '&#160;')
3148 * @return {Roo.MessageBox} This message box
3150 updateText : function(text)
3152 if(!dlg.isVisible() && !opt.width){
3153 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3154 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3156 msgEl.innerHTML = text || ' ';
3158 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3159 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3161 Math.min(opt.width || cw , this.maxWidth),
3162 Math.max(opt.minWidth || this.minWidth, bwidth)
3165 activeTextEl.setWidth(w);
3167 if(dlg.isVisible()){
3168 dlg.fixedcenter = false;
3170 // to big, make it scroll. = But as usual stupid IE does not support
3173 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3174 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3175 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3177 bodyEl.dom.style.height = '';
3178 bodyEl.dom.style.overflowY = '';
3181 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3183 bodyEl.dom.style.overflowX = '';
3186 dlg.setContentSize(w, bodyEl.getHeight());
3187 if(dlg.isVisible()){
3188 dlg.fixedcenter = true;
3194 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3195 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3196 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3197 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3198 * @return {Roo.MessageBox} This message box
3200 updateProgress : function(value, text){
3202 this.updateText(text);
3205 if (pp) { // weird bug on my firefox - for some reason this is not defined
3206 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3207 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3213 * Returns true if the message box is currently displayed
3214 * @return {Boolean} True if the message box is visible, else false
3216 isVisible : function(){
3217 return dlg && dlg.isVisible();
3221 * Hides the message box if it is displayed
3224 if(this.isVisible()){
3230 * Displays a new message box, or reinitializes an existing message box, based on the config options
3231 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3232 * The following config object properties are supported:
3234 Property Type Description
3235 ---------- --------------- ------------------------------------------------------------------------------------
3236 animEl String/Element An id or Element from which the message box should animate as it opens and
3237 closes (defaults to undefined)
3238 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3239 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3240 closable Boolean False to hide the top-right close button (defaults to true). Note that
3241 progress and wait dialogs will ignore this property and always hide the
3242 close button as they can only be closed programmatically.
3243 cls String A custom CSS class to apply to the message box element
3244 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3245 displayed (defaults to 75)
3246 fn Function A callback function to execute after closing the dialog. The arguments to the
3247 function will be btn (the name of the button that was clicked, if applicable,
3248 e.g. "ok"), and text (the value of the active text field, if applicable).
3249 Progress and wait dialogs will ignore this option since they do not respond to
3250 user actions and can only be closed programmatically, so any required function
3251 should be called by the same code after it closes the dialog.
3252 icon String A CSS class that provides a background image to be used as an icon for
3253 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3254 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3255 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3256 modal Boolean False to allow user interaction with the page while the message box is
3257 displayed (defaults to true)
3258 msg String A string that will replace the existing message box body text (defaults
3259 to the XHTML-compliant non-breaking space character ' ')
3260 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3261 progress Boolean True to display a progress bar (defaults to false)
3262 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3263 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3264 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3265 title String The title text
3266 value String The string value to set into the active textbox element if displayed
3267 wait Boolean True to display a progress bar (defaults to false)
3268 width Number The width of the dialog in pixels
3275 msg: 'Please enter your address:',
3277 buttons: Roo.MessageBox.OKCANCEL,
3280 animEl: 'addAddressBtn'
3283 * @param {Object} config Configuration options
3284 * @return {Roo.MessageBox} This message box
3286 show : function(options)
3289 // this causes nightmares if you show one dialog after another
3290 // especially on callbacks..
3292 if(this.isVisible()){
3295 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3296 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3297 Roo.log("New Dialog Message:" + options.msg )
3298 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3299 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3302 var d = this.getDialog();
3304 d.setTitle(opt.title || " ");
3305 d.closeEl.setDisplayed(opt.closable !== false);
3306 activeTextEl = textboxEl;
3307 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3312 textareaEl.setHeight(typeof opt.multiline == "number" ?
3313 opt.multiline : this.defaultTextHeight);
3314 activeTextEl = textareaEl;
3323 progressEl.setDisplayed(opt.progress === true);
3324 this.updateProgress(0);
3325 activeTextEl.dom.value = opt.value || "";
3327 dlg.setDefaultButton(activeTextEl);
3329 var bs = opt.buttons;
3333 }else if(bs && bs.yes){
3334 db = buttons["yes"];
3336 dlg.setDefaultButton(db);
3338 bwidth = updateButtons(opt.buttons);
3339 this.updateText(opt.msg);
3341 d.el.addClass(opt.cls);
3343 d.proxyDrag = opt.proxyDrag === true;
3344 d.modal = opt.modal !== false;
3345 d.mask = opt.modal !== false ? mask : false;
3347 // force it to the end of the z-index stack so it gets a cursor in FF
3348 document.body.appendChild(dlg.el.dom);
3349 d.animateTarget = null;
3350 d.show(options.animEl);
3356 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3357 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3358 * and closing the message box when the process is complete.
3359 * @param {String} title The title bar text
3360 * @param {String} msg The message box body text
3361 * @return {Roo.MessageBox} This message box
3363 progress : function(title, msg){
3370 minWidth: this.minProgressWidth,
3377 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3378 * If a callback function is passed it will be called after the user clicks the button, and the
3379 * id of the button that was clicked will be passed as the only parameter to the callback
3380 * (could also be the top-right close button).
3381 * @param {String} title The title bar text
3382 * @param {String} msg The message box body text
3383 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3384 * @param {Object} scope (optional) The scope of the callback function
3385 * @return {Roo.MessageBox} This message box
3387 alert : function(title, msg, fn, scope)
3402 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3403 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3404 * You are responsible for closing the message box when the process is complete.
3405 * @param {String} msg The message box body text
3406 * @param {String} title (optional) The title bar text
3407 * @return {Roo.MessageBox} This message box
3409 wait : function(msg, title){
3420 waitTimer = Roo.TaskMgr.start({
3422 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3430 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3431 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3432 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3433 * @param {String} title The title bar text
3434 * @param {String} msg The message box body text
3435 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3436 * @param {Object} scope (optional) The scope of the callback function
3437 * @return {Roo.MessageBox} This message box
3439 confirm : function(title, msg, fn, scope){
3443 buttons: this.YESNO,
3452 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3453 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3454 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3455 * (could also be the top-right close button) and the text that was entered will be passed as the two
3456 * parameters to the callback.
3457 * @param {String} title The title bar text
3458 * @param {String} msg The message box body text
3459 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3460 * @param {Object} scope (optional) The scope of the callback function
3461 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3462 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3463 * @return {Roo.MessageBox} This message box
3465 prompt : function(title, msg, fn, scope, multiline){
3469 buttons: this.OKCANCEL,
3474 multiline: multiline,
3481 * Button config that displays a single OK button
3486 * Button config that displays Yes and No buttons
3489 YESNO : {yes:true, no:true},
3491 * Button config that displays OK and Cancel buttons
3494 OKCANCEL : {ok:true, cancel:true},
3496 * Button config that displays Yes, No and Cancel buttons
3499 YESNOCANCEL : {yes:true, no:true, cancel:true},
3502 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3505 defaultTextHeight : 75,
3507 * The maximum width in pixels of the message box (defaults to 600)
3512 * The minimum width in pixels of the message box (defaults to 100)
3517 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3518 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3521 minProgressWidth : 250,
3523 * An object containing the default button text strings that can be overriden for localized language support.
3524 * Supported properties are: ok, cancel, yes and no.
3525 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3538 * Shorthand for {@link Roo.MessageBox}
3540 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3541 Roo.Msg = Roo.Msg || Roo.MessageBox;
3550 * @class Roo.bootstrap.Navbar
3551 * @extends Roo.bootstrap.Component
3552 * Bootstrap Navbar class
3555 * Create a new Navbar
3556 * @param {Object} config The config object
3560 Roo.bootstrap.Navbar = function(config){
3561 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3565 * @event beforetoggle
3566 * Fire before toggle the menu
3567 * @param {Roo.EventObject} e
3569 "beforetoggle" : true
3573 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3582 getAutoCreate : function(){
3585 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3589 initEvents :function ()
3591 //Roo.log(this.el.select('.navbar-toggle',true));
3592 this.el.select('.navbar-toggle',true).on('click', function() {
3593 if(this.fireEvent('beforetoggle', this) !== false){
3594 this.el.select('.navbar-collapse',true).toggleClass('in');
3604 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3606 var size = this.el.getSize();
3607 this.maskEl.setSize(size.width, size.height);
3608 this.maskEl.enableDisplayMode("block");
3617 getChildContainer : function()
3619 if (this.el.select('.collapse').getCount()) {
3620 return this.el.select('.collapse',true).first();
3653 * @class Roo.bootstrap.NavSimplebar
3654 * @extends Roo.bootstrap.Navbar
3655 * Bootstrap Sidebar class
3657 * @cfg {Boolean} inverse is inverted color
3659 * @cfg {String} type (nav | pills | tabs)
3660 * @cfg {Boolean} arrangement stacked | justified
3661 * @cfg {String} align (left | right) alignment
3663 * @cfg {Boolean} main (true|false) main nav bar? default false
3664 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3666 * @cfg {String} tag (header|footer|nav|div) default is nav
3672 * Create a new Sidebar
3673 * @param {Object} config The config object
3677 Roo.bootstrap.NavSimplebar = function(config){
3678 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3681 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3697 getAutoCreate : function(){
3701 tag : this.tag || 'div',
3714 this.type = this.type || 'nav';
3715 if (['tabs','pills'].indexOf(this.type)!==-1) {
3716 cfg.cn[0].cls += ' nav-' + this.type
3720 if (this.type!=='nav') {
3721 Roo.log('nav type must be nav/tabs/pills')
3723 cfg.cn[0].cls += ' navbar-nav'
3729 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3730 cfg.cn[0].cls += ' nav-' + this.arrangement;
3734 if (this.align === 'right') {
3735 cfg.cn[0].cls += ' navbar-right';
3739 cfg.cls += ' navbar-inverse';
3766 * @class Roo.bootstrap.NavHeaderbar
3767 * @extends Roo.bootstrap.NavSimplebar
3768 * Bootstrap Sidebar class
3770 * @cfg {String} brand what is brand
3771 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3772 * @cfg {String} brand_href href of the brand
3773 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3774 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3775 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3776 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3779 * Create a new Sidebar
3780 * @param {Object} config The config object
3784 Roo.bootstrap.NavHeaderbar = function(config){
3785 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3789 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3796 desktopCenter : false,
3799 getAutoCreate : function(){
3802 tag: this.nav || 'nav',
3809 if (this.desktopCenter) {
3810 cn.push({cls : 'container', cn : []});
3817 cls: 'navbar-header',
3822 cls: 'navbar-toggle',
3823 'data-toggle': 'collapse',
3828 html: 'Toggle navigation'
3850 cls: 'collapse navbar-collapse',
3854 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3856 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3857 cfg.cls += ' navbar-' + this.position;
3859 // tag can override this..
3861 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3864 if (this.brand !== '') {
3867 href: this.brand_href ? this.brand_href : '#',
3868 cls: 'navbar-brand',
3876 cfg.cls += ' main-nav';
3884 getHeaderChildContainer : function()
3886 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3887 return this.el.select('.navbar-header',true).first();
3890 return this.getChildContainer();
3894 initEvents : function()
3896 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3898 if (this.autohide) {
3903 Roo.get(document).on('scroll',function(e) {
3904 var ns = Roo.get(document).getScroll().top;
3905 var os = prevScroll;
3909 ft.removeClass('slideDown');
3910 ft.addClass('slideUp');
3913 ft.removeClass('slideUp');
3914 ft.addClass('slideDown');
3935 * @class Roo.bootstrap.NavSidebar
3936 * @extends Roo.bootstrap.Navbar
3937 * Bootstrap Sidebar class
3940 * Create a new Sidebar
3941 * @param {Object} config The config object
3945 Roo.bootstrap.NavSidebar = function(config){
3946 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3949 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3951 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3953 getAutoCreate : function(){
3958 cls: 'sidebar sidebar-nav'
3980 * @class Roo.bootstrap.NavGroup
3981 * @extends Roo.bootstrap.Component
3982 * Bootstrap NavGroup class
3983 * @cfg {String} align (left|right)
3984 * @cfg {Boolean} inverse
3985 * @cfg {String} type (nav|pills|tab) default nav
3986 * @cfg {String} navId - reference Id for navbar.
3990 * Create a new nav group
3991 * @param {Object} config The config object
3994 Roo.bootstrap.NavGroup = function(config){
3995 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3998 Roo.bootstrap.NavGroup.register(this);
4002 * Fires when the active item changes
4003 * @param {Roo.bootstrap.NavGroup} this
4004 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4005 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4012 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4023 getAutoCreate : function()
4025 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4032 if (['tabs','pills'].indexOf(this.type)!==-1) {
4033 cfg.cls += ' nav-' + this.type
4035 if (this.type!=='nav') {
4036 Roo.log('nav type must be nav/tabs/pills')
4038 cfg.cls += ' navbar-nav'
4041 if (this.parent() && this.parent().sidebar) {
4044 cls: 'dashboard-menu sidebar-menu'
4050 if (this.form === true) {
4056 if (this.align === 'right') {
4057 cfg.cls += ' navbar-right';
4059 cfg.cls += ' navbar-left';
4063 if (this.align === 'right') {
4064 cfg.cls += ' navbar-right';
4068 cfg.cls += ' navbar-inverse';
4076 * sets the active Navigation item
4077 * @param {Roo.bootstrap.NavItem} the new current navitem
4079 setActiveItem : function(item)
4082 Roo.each(this.navItems, function(v){
4087 v.setActive(false, true);
4094 item.setActive(true, true);
4095 this.fireEvent('changed', this, item, prev);
4100 * gets the active Navigation item
4101 * @return {Roo.bootstrap.NavItem} the current navitem
4103 getActive : function()
4107 Roo.each(this.navItems, function(v){
4118 indexOfNav : function()
4122 Roo.each(this.navItems, function(v,i){
4133 * adds a Navigation item
4134 * @param {Roo.bootstrap.NavItem} the navitem to add
4136 addItem : function(cfg)
4138 var cn = new Roo.bootstrap.NavItem(cfg);
4140 cn.parentId = this.id;
4141 cn.onRender(this.el, null);
4145 * register a Navigation item
4146 * @param {Roo.bootstrap.NavItem} the navitem to add
4148 register : function(item)
4150 this.navItems.push( item);
4151 item.navId = this.navId;
4156 * clear all the Navigation item
4159 clearAll : function()
4162 this.el.dom.innerHTML = '';
4165 getNavItem: function(tabId)
4168 Roo.each(this.navItems, function(e) {
4169 if (e.tabId == tabId) {
4179 setActiveNext : function()
4181 var i = this.indexOfNav(this.getActive());
4182 if (i > this.navItems.length) {
4185 this.setActiveItem(this.navItems[i+1]);
4187 setActivePrev : function()
4189 var i = this.indexOfNav(this.getActive());
4193 this.setActiveItem(this.navItems[i-1]);
4195 clearWasActive : function(except) {
4196 Roo.each(this.navItems, function(e) {
4197 if (e.tabId != except.tabId && e.was_active) {
4198 e.was_active = false;
4205 getWasActive : function ()
4208 Roo.each(this.navItems, function(e) {
4223 Roo.apply(Roo.bootstrap.NavGroup, {
4227 * register a Navigation Group
4228 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4230 register : function(navgrp)
4232 this.groups[navgrp.navId] = navgrp;
4236 * fetch a Navigation Group based on the navigation ID
4237 * @param {string} the navgroup to add
4238 * @returns {Roo.bootstrap.NavGroup} the navgroup
4240 get: function(navId) {
4241 if (typeof(this.groups[navId]) == 'undefined') {
4243 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4245 return this.groups[navId] ;
4260 * @class Roo.bootstrap.NavItem
4261 * @extends Roo.bootstrap.Component
4262 * Bootstrap Navbar.NavItem class
4263 * @cfg {String} href link to
4264 * @cfg {String} html content of button
4265 * @cfg {String} badge text inside badge
4266 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4267 * @cfg {String} glyphicon name of glyphicon
4268 * @cfg {String} icon name of font awesome icon
4269 * @cfg {Boolean} active Is item active
4270 * @cfg {Boolean} disabled Is item disabled
4272 * @cfg {Boolean} preventDefault (true | false) default false
4273 * @cfg {String} tabId the tab that this item activates.
4274 * @cfg {String} tagtype (a|span) render as a href or span?
4275 * @cfg {Boolean} animateRef (true|false) link to element default false
4278 * Create a new Navbar Item
4279 * @param {Object} config The config object
4281 Roo.bootstrap.NavItem = function(config){
4282 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4287 * The raw click event for the entire grid.
4288 * @param {Roo.EventObject} e
4293 * Fires when the active item active state changes
4294 * @param {Roo.bootstrap.NavItem} this
4295 * @param {boolean} state the new state
4301 * Fires when scroll to element
4302 * @param {Roo.bootstrap.NavItem} this
4303 * @param {Object} options
4304 * @param {Roo.EventObject} e
4312 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4320 preventDefault : false,
4327 getAutoCreate : function(){
4336 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4338 if (this.disabled) {
4339 cfg.cls += ' disabled';
4342 if (this.href || this.html || this.glyphicon || this.icon) {
4346 href : this.href || "#",
4347 html: this.html || ''
4352 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4355 if(this.glyphicon) {
4356 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4361 cfg.cn[0].html += " <span class='caret'></span>";
4365 if (this.badge !== '') {
4367 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4375 initEvents: function()
4377 if (typeof (this.menu) != 'undefined') {
4378 this.menu.parentType = this.xtype;
4379 this.menu.triggerEl = this.el;
4380 this.menu = this.addxtype(Roo.apply({}, this.menu));
4383 this.el.select('a',true).on('click', this.onClick, this);
4385 if(this.tagtype == 'span'){
4386 this.el.select('span',true).on('click', this.onClick, this);
4389 // at this point parent should be available..
4390 this.parent().register(this);
4393 onClick : function(e)
4395 if (e.getTarget('.dropdown-menu-item')) {
4396 // did you click on a menu itemm.... - then don't trigger onclick..
4401 this.preventDefault ||
4404 Roo.log("NavItem - prevent Default?");
4408 if (this.disabled) {
4412 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4413 if (tg && tg.transition) {
4414 Roo.log("waiting for the transitionend");
4420 //Roo.log("fire event clicked");
4421 if(this.fireEvent('click', this, e) === false){
4425 if(this.tagtype == 'span'){
4429 //Roo.log(this.href);
4430 var ael = this.el.select('a',true).first();
4433 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4434 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4435 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4436 return; // ignore... - it's a 'hash' to another page.
4438 Roo.log("NavItem - prevent Default?");
4440 this.scrollToElement(e);
4444 var p = this.parent();
4446 if (['tabs','pills'].indexOf(p.type)!==-1) {
4447 if (typeof(p.setActiveItem) !== 'undefined') {
4448 p.setActiveItem(this);
4452 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4453 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4454 // remove the collapsed menu expand...
4455 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4459 isActive: function () {
4462 setActive : function(state, fire, is_was_active)
4464 if (this.active && !state && this.navId) {
4465 this.was_active = true;
4466 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4468 nv.clearWasActive(this);
4472 this.active = state;
4475 this.el.removeClass('active');
4476 } else if (!this.el.hasClass('active')) {
4477 this.el.addClass('active');
4480 this.fireEvent('changed', this, state);
4483 // show a panel if it's registered and related..
4485 if (!this.navId || !this.tabId || !state || is_was_active) {
4489 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4493 var pan = tg.getPanelByName(this.tabId);
4497 // if we can not flip to new panel - go back to old nav highlight..
4498 if (false == tg.showPanel(pan)) {
4499 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4501 var onav = nv.getWasActive();
4503 onav.setActive(true, false, true);
4512 // this should not be here...
4513 setDisabled : function(state)
4515 this.disabled = state;
4517 this.el.removeClass('disabled');
4518 } else if (!this.el.hasClass('disabled')) {
4519 this.el.addClass('disabled');
4525 * Fetch the element to display the tooltip on.
4526 * @return {Roo.Element} defaults to this.el
4528 tooltipEl : function()
4530 return this.el.select('' + this.tagtype + '', true).first();
4533 scrollToElement : function(e)
4535 var c = document.body;
4538 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4540 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4541 c = document.documentElement;
4544 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4550 var o = target.calcOffsetsTo(c);
4557 this.fireEvent('scrollto', this, options, e);
4559 Roo.get(c).scrollTo('top', options.value, true);
4572 * <span> icon </span>
4573 * <span> text </span>
4574 * <span>badge </span>
4578 * @class Roo.bootstrap.NavSidebarItem
4579 * @extends Roo.bootstrap.NavItem
4580 * Bootstrap Navbar.NavSidebarItem class
4581 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4582 * {Boolean} open is the menu open
4583 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4584 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4585 * {String} buttonSize (sm|md|lg)the extra classes for the button
4586 * {Boolean} showArrow show arrow next to the text (default true)
4588 * Create a new Navbar Button
4589 * @param {Object} config The config object
4591 Roo.bootstrap.NavSidebarItem = function(config){
4592 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4597 * The raw click event for the entire grid.
4598 * @param {Roo.EventObject} e
4603 * Fires when the active item active state changes
4604 * @param {Roo.bootstrap.NavSidebarItem} this
4605 * @param {boolean} state the new state
4613 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4615 badgeWeight : 'default',
4621 buttonWeight : 'default',
4627 getAutoCreate : function(){
4632 href : this.href || '#',
4638 if(this.buttonView){
4641 href : this.href || '#',
4642 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4655 cfg.cls += ' active';
4658 if (this.disabled) {
4659 cfg.cls += ' disabled';
4662 cfg.cls += ' open x-open';
4665 if (this.glyphicon || this.icon) {
4666 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4667 a.cn.push({ tag : 'i', cls : c }) ;
4670 if(!this.buttonView){
4673 html : this.html || ''
4680 if (this.badge !== '') {
4681 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4687 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4690 a.cls += ' dropdown-toggle treeview' ;
4696 initEvents : function()
4698 if (typeof (this.menu) != 'undefined') {
4699 this.menu.parentType = this.xtype;
4700 this.menu.triggerEl = this.el;
4701 this.menu = this.addxtype(Roo.apply({}, this.menu));
4704 this.el.on('click', this.onClick, this);
4706 if(this.badge !== ''){
4707 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4712 onClick : function(e)
4719 if(this.preventDefault){
4723 this.fireEvent('click', this);
4726 disable : function()
4728 this.setDisabled(true);
4733 this.setDisabled(false);
4736 setDisabled : function(state)
4738 if(this.disabled == state){
4742 this.disabled = state;
4745 this.el.addClass('disabled');
4749 this.el.removeClass('disabled');
4754 setActive : function(state)
4756 if(this.active == state){
4760 this.active = state;
4763 this.el.addClass('active');
4767 this.el.removeClass('active');
4772 isActive: function ()
4777 setBadge : function(str)
4783 this.badgeEl.dom.innerHTML = str;
4800 * @class Roo.bootstrap.Row
4801 * @extends Roo.bootstrap.Component
4802 * Bootstrap Row class (contains columns...)
4806 * @param {Object} config The config object
4809 Roo.bootstrap.Row = function(config){
4810 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4813 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4815 getAutoCreate : function(){
4834 * @class Roo.bootstrap.Element
4835 * @extends Roo.bootstrap.Component
4836 * Bootstrap Element class
4837 * @cfg {String} html contents of the element
4838 * @cfg {String} tag tag of the element
4839 * @cfg {String} cls class of the element
4840 * @cfg {Boolean} preventDefault (true|false) default false
4841 * @cfg {Boolean} clickable (true|false) default false
4844 * Create a new Element
4845 * @param {Object} config The config object
4848 Roo.bootstrap.Element = function(config){
4849 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4855 * When a element is chick
4856 * @param {Roo.bootstrap.Element} this
4857 * @param {Roo.EventObject} e
4863 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4868 preventDefault: false,
4871 getAutoCreate : function(){
4882 initEvents: function()
4884 Roo.bootstrap.Element.superclass.initEvents.call(this);
4887 this.el.on('click', this.onClick, this);
4892 onClick : function(e)
4894 if(this.preventDefault){
4898 this.fireEvent('click', this, e);
4901 getValue : function()
4903 return this.el.dom.innerHTML;
4906 setValue : function(value)
4908 this.el.dom.innerHTML = value;
4923 * @class Roo.bootstrap.Pagination
4924 * @extends Roo.bootstrap.Component
4925 * Bootstrap Pagination class
4926 * @cfg {String} size xs | sm | md | lg
4927 * @cfg {Boolean} inverse false | true
4930 * Create a new Pagination
4931 * @param {Object} config The config object
4934 Roo.bootstrap.Pagination = function(config){
4935 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4938 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4944 getAutoCreate : function(){
4950 cfg.cls += ' inverse';
4956 cfg.cls += " " + this.cls;
4974 * @class Roo.bootstrap.PaginationItem
4975 * @extends Roo.bootstrap.Component
4976 * Bootstrap PaginationItem class
4977 * @cfg {String} html text
4978 * @cfg {String} href the link
4979 * @cfg {Boolean} preventDefault (true | false) default true
4980 * @cfg {Boolean} active (true | false) default false
4981 * @cfg {Boolean} disabled default false
4985 * Create a new PaginationItem
4986 * @param {Object} config The config object
4990 Roo.bootstrap.PaginationItem = function(config){
4991 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4996 * The raw click event for the entire grid.
4997 * @param {Roo.EventObject} e
5003 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5007 preventDefault: true,
5012 getAutoCreate : function(){
5018 href : this.href ? this.href : '#',
5019 html : this.html ? this.html : ''
5029 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5033 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5039 initEvents: function() {
5041 this.el.on('click', this.onClick, this);
5044 onClick : function(e)
5046 Roo.log('PaginationItem on click ');
5047 if(this.preventDefault){
5055 this.fireEvent('click', this, e);
5071 * @class Roo.bootstrap.Slider
5072 * @extends Roo.bootstrap.Component
5073 * Bootstrap Slider class
5076 * Create a new Slider
5077 * @param {Object} config The config object
5080 Roo.bootstrap.Slider = function(config){
5081 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5084 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5086 getAutoCreate : function(){
5090 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5094 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5106 * Ext JS Library 1.1.1
5107 * Copyright(c) 2006-2007, Ext JS, LLC.
5109 * Originally Released Under LGPL - original licence link has changed is not relivant.
5112 * <script type="text/javascript">
5117 * @class Roo.grid.ColumnModel
5118 * @extends Roo.util.Observable
5119 * This is the default implementation of a ColumnModel used by the Grid. It defines
5120 * the columns in the grid.
5123 var colModel = new Roo.grid.ColumnModel([
5124 {header: "Ticker", width: 60, sortable: true, locked: true},
5125 {header: "Company Name", width: 150, sortable: true},
5126 {header: "Market Cap.", width: 100, sortable: true},
5127 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5128 {header: "Employees", width: 100, sortable: true, resizable: false}
5133 * The config options listed for this class are options which may appear in each
5134 * individual column definition.
5135 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5137 * @param {Object} config An Array of column config objects. See this class's
5138 * config objects for details.
5140 Roo.grid.ColumnModel = function(config){
5142 * The config passed into the constructor
5144 this.config = config;
5147 // if no id, create one
5148 // if the column does not have a dataIndex mapping,
5149 // map it to the order it is in the config
5150 for(var i = 0, len = config.length; i < len; i++){
5152 if(typeof c.dataIndex == "undefined"){
5155 if(typeof c.renderer == "string"){
5156 c.renderer = Roo.util.Format[c.renderer];
5158 if(typeof c.id == "undefined"){
5161 if(c.editor && c.editor.xtype){
5162 c.editor = Roo.factory(c.editor, Roo.grid);
5164 if(c.editor && c.editor.isFormField){
5165 c.editor = new Roo.grid.GridEditor(c.editor);
5167 this.lookup[c.id] = c;
5171 * The width of columns which have no width specified (defaults to 100)
5174 this.defaultWidth = 100;
5177 * Default sortable of columns which have no sortable specified (defaults to false)
5180 this.defaultSortable = false;
5184 * @event widthchange
5185 * Fires when the width of a column changes.
5186 * @param {ColumnModel} this
5187 * @param {Number} columnIndex The column index
5188 * @param {Number} newWidth The new width
5190 "widthchange": true,
5192 * @event headerchange
5193 * Fires when the text of a header changes.
5194 * @param {ColumnModel} this
5195 * @param {Number} columnIndex The column index
5196 * @param {Number} newText The new header text
5198 "headerchange": true,
5200 * @event hiddenchange
5201 * Fires when a column is hidden or "unhidden".
5202 * @param {ColumnModel} this
5203 * @param {Number} columnIndex The column index
5204 * @param {Boolean} hidden true if hidden, false otherwise
5206 "hiddenchange": true,
5208 * @event columnmoved
5209 * Fires when a column is moved.
5210 * @param {ColumnModel} this
5211 * @param {Number} oldIndex
5212 * @param {Number} newIndex
5214 "columnmoved" : true,
5216 * @event columlockchange
5217 * Fires when a column's locked state is changed
5218 * @param {ColumnModel} this
5219 * @param {Number} colIndex
5220 * @param {Boolean} locked true if locked
5222 "columnlockchange" : true
5224 Roo.grid.ColumnModel.superclass.constructor.call(this);
5226 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5228 * @cfg {String} header The header text to display in the Grid view.
5231 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5232 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5233 * specified, the column's index is used as an index into the Record's data Array.
5236 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5237 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5240 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5241 * Defaults to the value of the {@link #defaultSortable} property.
5242 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5245 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5248 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5251 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5254 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5257 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5258 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5259 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5260 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5263 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5266 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5269 * @cfg {String} cursor (Optional)
5272 * @cfg {String} tooltip (Optional)
5275 * @cfg {Number} xs (Optional)
5278 * @cfg {Number} sm (Optional)
5281 * @cfg {Number} md (Optional)
5284 * @cfg {Number} lg (Optional)
5287 * Returns the id of the column at the specified index.
5288 * @param {Number} index The column index
5289 * @return {String} the id
5291 getColumnId : function(index){
5292 return this.config[index].id;
5296 * Returns the column for a specified id.
5297 * @param {String} id The column id
5298 * @return {Object} the column
5300 getColumnById : function(id){
5301 return this.lookup[id];
5306 * Returns the column for a specified dataIndex.
5307 * @param {String} dataIndex The column dataIndex
5308 * @return {Object|Boolean} the column or false if not found
5310 getColumnByDataIndex: function(dataIndex){
5311 var index = this.findColumnIndex(dataIndex);
5312 return index > -1 ? this.config[index] : false;
5316 * Returns the index for a specified column id.
5317 * @param {String} id The column id
5318 * @return {Number} the index, or -1 if not found
5320 getIndexById : function(id){
5321 for(var i = 0, len = this.config.length; i < len; i++){
5322 if(this.config[i].id == id){
5330 * Returns the index for a specified column dataIndex.
5331 * @param {String} dataIndex The column dataIndex
5332 * @return {Number} the index, or -1 if not found
5335 findColumnIndex : function(dataIndex){
5336 for(var i = 0, len = this.config.length; i < len; i++){
5337 if(this.config[i].dataIndex == dataIndex){
5345 moveColumn : function(oldIndex, newIndex){
5346 var c = this.config[oldIndex];
5347 this.config.splice(oldIndex, 1);
5348 this.config.splice(newIndex, 0, c);
5349 this.dataMap = null;
5350 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5353 isLocked : function(colIndex){
5354 return this.config[colIndex].locked === true;
5357 setLocked : function(colIndex, value, suppressEvent){
5358 if(this.isLocked(colIndex) == value){
5361 this.config[colIndex].locked = value;
5363 this.fireEvent("columnlockchange", this, colIndex, value);
5367 getTotalLockedWidth : function(){
5369 for(var i = 0; i < this.config.length; i++){
5370 if(this.isLocked(i) && !this.isHidden(i)){
5371 this.totalWidth += this.getColumnWidth(i);
5377 getLockedCount : function(){
5378 for(var i = 0, len = this.config.length; i < len; i++){
5379 if(!this.isLocked(i)){
5384 return this.config.length;
5388 * Returns the number of columns.
5391 getColumnCount : function(visibleOnly){
5392 if(visibleOnly === true){
5394 for(var i = 0, len = this.config.length; i < len; i++){
5395 if(!this.isHidden(i)){
5401 return this.config.length;
5405 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5406 * @param {Function} fn
5407 * @param {Object} scope (optional)
5408 * @return {Array} result
5410 getColumnsBy : function(fn, scope){
5412 for(var i = 0, len = this.config.length; i < len; i++){
5413 var c = this.config[i];
5414 if(fn.call(scope||this, c, i) === true){
5422 * Returns true if the specified column is sortable.
5423 * @param {Number} col The column index
5426 isSortable : function(col){
5427 if(typeof this.config[col].sortable == "undefined"){
5428 return this.defaultSortable;
5430 return this.config[col].sortable;
5434 * Returns the rendering (formatting) function defined for the column.
5435 * @param {Number} col The column index.
5436 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5438 getRenderer : function(col){
5439 if(!this.config[col].renderer){
5440 return Roo.grid.ColumnModel.defaultRenderer;
5442 return this.config[col].renderer;
5446 * Sets the rendering (formatting) function for a column.
5447 * @param {Number} col The column index
5448 * @param {Function} fn The function to use to process the cell's raw data
5449 * to return HTML markup for the grid view. The render function is called with
5450 * the following parameters:<ul>
5451 * <li>Data value.</li>
5452 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5453 * <li>css A CSS style string to apply to the table cell.</li>
5454 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5455 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5456 * <li>Row index</li>
5457 * <li>Column index</li>
5458 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5460 setRenderer : function(col, fn){
5461 this.config[col].renderer = fn;
5465 * Returns the width for the specified column.
5466 * @param {Number} col The column index
5469 getColumnWidth : function(col){
5470 return this.config[col].width * 1 || this.defaultWidth;
5474 * Sets the width for a column.
5475 * @param {Number} col The column index
5476 * @param {Number} width The new width
5478 setColumnWidth : function(col, width, suppressEvent){
5479 this.config[col].width = width;
5480 this.totalWidth = null;
5482 this.fireEvent("widthchange", this, col, width);
5487 * Returns the total width of all columns.
5488 * @param {Boolean} includeHidden True to include hidden column widths
5491 getTotalWidth : function(includeHidden){
5492 if(!this.totalWidth){
5493 this.totalWidth = 0;
5494 for(var i = 0, len = this.config.length; i < len; i++){
5495 if(includeHidden || !this.isHidden(i)){
5496 this.totalWidth += this.getColumnWidth(i);
5500 return this.totalWidth;
5504 * Returns the header for the specified column.
5505 * @param {Number} col The column index
5508 getColumnHeader : function(col){
5509 return this.config[col].header;
5513 * Sets the header for a column.
5514 * @param {Number} col The column index
5515 * @param {String} header The new header
5517 setColumnHeader : function(col, header){
5518 this.config[col].header = header;
5519 this.fireEvent("headerchange", this, col, header);
5523 * Returns the tooltip for the specified column.
5524 * @param {Number} col The column index
5527 getColumnTooltip : function(col){
5528 return this.config[col].tooltip;
5531 * Sets the tooltip for a column.
5532 * @param {Number} col The column index
5533 * @param {String} tooltip The new tooltip
5535 setColumnTooltip : function(col, tooltip){
5536 this.config[col].tooltip = tooltip;
5540 * Returns the dataIndex for the specified column.
5541 * @param {Number} col The column index
5544 getDataIndex : function(col){
5545 return this.config[col].dataIndex;
5549 * Sets the dataIndex for a column.
5550 * @param {Number} col The column index
5551 * @param {Number} dataIndex The new dataIndex
5553 setDataIndex : function(col, dataIndex){
5554 this.config[col].dataIndex = dataIndex;
5560 * Returns true if the cell is editable.
5561 * @param {Number} colIndex The column index
5562 * @param {Number} rowIndex The row index - this is nto actually used..?
5565 isCellEditable : function(colIndex, rowIndex){
5566 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5570 * Returns the editor defined for the cell/column.
5571 * return false or null to disable editing.
5572 * @param {Number} colIndex The column index
5573 * @param {Number} rowIndex The row index
5576 getCellEditor : function(colIndex, rowIndex){
5577 return this.config[colIndex].editor;
5581 * Sets if a column is editable.
5582 * @param {Number} col The column index
5583 * @param {Boolean} editable True if the column is editable
5585 setEditable : function(col, editable){
5586 this.config[col].editable = editable;
5591 * Returns true if the column is hidden.
5592 * @param {Number} colIndex The column index
5595 isHidden : function(colIndex){
5596 return this.config[colIndex].hidden;
5601 * Returns true if the column width cannot be changed
5603 isFixed : function(colIndex){
5604 return this.config[colIndex].fixed;
5608 * Returns true if the column can be resized
5611 isResizable : function(colIndex){
5612 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5615 * Sets if a column is hidden.
5616 * @param {Number} colIndex The column index
5617 * @param {Boolean} hidden True if the column is hidden
5619 setHidden : function(colIndex, hidden){
5620 this.config[colIndex].hidden = hidden;
5621 this.totalWidth = null;
5622 this.fireEvent("hiddenchange", this, colIndex, hidden);
5626 * Sets the editor for a column.
5627 * @param {Number} col The column index
5628 * @param {Object} editor The editor object
5630 setEditor : function(col, editor){
5631 this.config[col].editor = editor;
5635 Roo.grid.ColumnModel.defaultRenderer = function(value)
5637 if(typeof value == "object") {
5640 if(typeof value == "string" && value.length < 1){
5644 return String.format("{0}", value);
5647 // Alias for backwards compatibility
5648 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5651 * Ext JS Library 1.1.1
5652 * Copyright(c) 2006-2007, Ext JS, LLC.
5654 * Originally Released Under LGPL - original licence link has changed is not relivant.
5657 * <script type="text/javascript">
5661 * @class Roo.LoadMask
5662 * A simple utility class for generically masking elements while loading data. If the element being masked has
5663 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5664 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5665 * element's UpdateManager load indicator and will be destroyed after the initial load.
5667 * Create a new LoadMask
5668 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5669 * @param {Object} config The config object
5671 Roo.LoadMask = function(el, config){
5672 this.el = Roo.get(el);
5673 Roo.apply(this, config);
5675 this.store.on('beforeload', this.onBeforeLoad, this);
5676 this.store.on('load', this.onLoad, this);
5677 this.store.on('loadexception', this.onLoadException, this);
5678 this.removeMask = false;
5680 var um = this.el.getUpdateManager();
5681 um.showLoadIndicator = false; // disable the default indicator
5682 um.on('beforeupdate', this.onBeforeLoad, this);
5683 um.on('update', this.onLoad, this);
5684 um.on('failure', this.onLoad, this);
5685 this.removeMask = true;
5689 Roo.LoadMask.prototype = {
5691 * @cfg {Boolean} removeMask
5692 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5693 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5697 * The text to display in a centered loading message box (defaults to 'Loading...')
5701 * @cfg {String} msgCls
5702 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5704 msgCls : 'x-mask-loading',
5707 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5713 * Disables the mask to prevent it from being displayed
5715 disable : function(){
5716 this.disabled = true;
5720 * Enables the mask so that it can be displayed
5722 enable : function(){
5723 this.disabled = false;
5726 onLoadException : function()
5730 if (typeof(arguments[3]) != 'undefined') {
5731 Roo.MessageBox.alert("Error loading",arguments[3]);
5735 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5736 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5743 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5748 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5752 onBeforeLoad : function(){
5754 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5759 destroy : function(){
5761 this.store.un('beforeload', this.onBeforeLoad, this);
5762 this.store.un('load', this.onLoad, this);
5763 this.store.un('loadexception', this.onLoadException, this);
5765 var um = this.el.getUpdateManager();
5766 um.un('beforeupdate', this.onBeforeLoad, this);
5767 um.un('update', this.onLoad, this);
5768 um.un('failure', this.onLoad, this);
5779 * @class Roo.bootstrap.Table
5780 * @extends Roo.bootstrap.Component
5781 * Bootstrap Table class
5782 * @cfg {String} cls table class
5783 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5784 * @cfg {String} bgcolor Specifies the background color for a table
5785 * @cfg {Number} border Specifies whether the table cells should have borders or not
5786 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5787 * @cfg {Number} cellspacing Specifies the space between cells
5788 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5789 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5790 * @cfg {String} sortable Specifies that the table should be sortable
5791 * @cfg {String} summary Specifies a summary of the content of a table
5792 * @cfg {Number} width Specifies the width of a table
5793 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5795 * @cfg {boolean} striped Should the rows be alternative striped
5796 * @cfg {boolean} bordered Add borders to the table
5797 * @cfg {boolean} hover Add hover highlighting
5798 * @cfg {boolean} condensed Format condensed
5799 * @cfg {boolean} responsive Format condensed
5800 * @cfg {Boolean} loadMask (true|false) default false
5801 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5802 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5803 * @cfg {Boolean} rowSelection (true|false) default false
5804 * @cfg {Boolean} cellSelection (true|false) default false
5805 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5806 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5807 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5811 * Create a new Table
5812 * @param {Object} config The config object
5815 Roo.bootstrap.Table = function(config){
5816 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5821 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5822 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5823 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5824 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5826 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5828 this.sm.grid = this;
5829 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5830 this.sm = this.selModel;
5831 this.sm.xmodule = this.xmodule || false;
5834 if (this.cm && typeof(this.cm.config) == 'undefined') {
5835 this.colModel = new Roo.grid.ColumnModel(this.cm);
5836 this.cm = this.colModel;
5837 this.cm.xmodule = this.xmodule || false;
5840 this.store= Roo.factory(this.store, Roo.data);
5841 this.ds = this.store;
5842 this.ds.xmodule = this.xmodule || false;
5845 if (this.footer && this.store) {
5846 this.footer.dataSource = this.ds;
5847 this.footer = Roo.factory(this.footer);
5854 * Fires when a cell is clicked
5855 * @param {Roo.bootstrap.Table} this
5856 * @param {Roo.Element} el
5857 * @param {Number} rowIndex
5858 * @param {Number} columnIndex
5859 * @param {Roo.EventObject} e
5863 * @event celldblclick
5864 * Fires when a cell is double clicked
5865 * @param {Roo.bootstrap.Table} this
5866 * @param {Roo.Element} el
5867 * @param {Number} rowIndex
5868 * @param {Number} columnIndex
5869 * @param {Roo.EventObject} e
5871 "celldblclick" : true,
5874 * Fires when a row is clicked
5875 * @param {Roo.bootstrap.Table} this
5876 * @param {Roo.Element} el
5877 * @param {Number} rowIndex
5878 * @param {Roo.EventObject} e
5882 * @event rowdblclick
5883 * Fires when a row is double clicked
5884 * @param {Roo.bootstrap.Table} this
5885 * @param {Roo.Element} el
5886 * @param {Number} rowIndex
5887 * @param {Roo.EventObject} e
5889 "rowdblclick" : true,
5892 * Fires when a mouseover occur
5893 * @param {Roo.bootstrap.Table} this
5894 * @param {Roo.Element} el
5895 * @param {Number} rowIndex
5896 * @param {Number} columnIndex
5897 * @param {Roo.EventObject} e
5902 * Fires when a mouseout occur
5903 * @param {Roo.bootstrap.Table} this
5904 * @param {Roo.Element} el
5905 * @param {Number} rowIndex
5906 * @param {Number} columnIndex
5907 * @param {Roo.EventObject} e
5912 * Fires when a row is rendered, so you can change add a style to it.
5913 * @param {Roo.bootstrap.Table} this
5914 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5918 * @event rowsrendered
5919 * Fires when all the rows have been rendered
5920 * @param {Roo.bootstrap.Table} this
5922 'rowsrendered' : true,
5924 * @event contextmenu
5925 * The raw contextmenu event for the entire grid.
5926 * @param {Roo.EventObject} e
5928 "contextmenu" : true,
5930 * @event rowcontextmenu
5931 * Fires when a row is right clicked
5932 * @param {Roo.bootstrap.Table} this
5933 * @param {Number} rowIndex
5934 * @param {Roo.EventObject} e
5936 "rowcontextmenu" : true,
5938 * @event cellcontextmenu
5939 * Fires when a cell is right clicked
5940 * @param {Roo.bootstrap.Table} this
5941 * @param {Number} rowIndex
5942 * @param {Number} cellIndex
5943 * @param {Roo.EventObject} e
5945 "cellcontextmenu" : true,
5947 * @event headercontextmenu
5948 * Fires when a header is right clicked
5949 * @param {Roo.bootstrap.Table} this
5950 * @param {Number} columnIndex
5951 * @param {Roo.EventObject} e
5953 "headercontextmenu" : true
5957 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5983 rowSelection : false,
5984 cellSelection : false,
5987 // Roo.Element - the tbody
5989 // Roo.Element - thead element
5992 container: false, // used by gridpanel...
5996 getAutoCreate : function()
5998 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6005 if (this.scrollBody) {
6006 cfg.cls += ' table-body-fixed';
6009 cfg.cls += ' table-striped';
6013 cfg.cls += ' table-hover';
6015 if (this.bordered) {
6016 cfg.cls += ' table-bordered';
6018 if (this.condensed) {
6019 cfg.cls += ' table-condensed';
6021 if (this.responsive) {
6022 cfg.cls += ' table-responsive';
6026 cfg.cls+= ' ' +this.cls;
6029 // this lot should be simplifed...
6032 cfg.align=this.align;
6035 cfg.bgcolor=this.bgcolor;
6038 cfg.border=this.border;
6040 if (this.cellpadding) {
6041 cfg.cellpadding=this.cellpadding;
6043 if (this.cellspacing) {
6044 cfg.cellspacing=this.cellspacing;
6047 cfg.frame=this.frame;
6050 cfg.rules=this.rules;
6052 if (this.sortable) {
6053 cfg.sortable=this.sortable;
6056 cfg.summary=this.summary;
6059 cfg.width=this.width;
6062 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6065 if(this.store || this.cm){
6066 if(this.headerShow){
6067 cfg.cn.push(this.renderHeader());
6070 cfg.cn.push(this.renderBody());
6072 if(this.footerShow){
6073 cfg.cn.push(this.renderFooter());
6075 // where does this come from?
6076 //cfg.cls+= ' TableGrid';
6079 return { cn : [ cfg ] };
6082 initEvents : function()
6084 if(!this.store || !this.cm){
6087 if (this.selModel) {
6088 this.selModel.initEvents();
6092 //Roo.log('initEvents with ds!!!!');
6094 this.mainBody = this.el.select('tbody', true).first();
6095 this.mainHead = this.el.select('thead', true).first();
6102 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6103 e.on('click', _this.sort, _this);
6106 this.mainBody.on("click", this.onClick, this);
6107 this.mainBody.on("dblclick", this.onDblClick, this);
6109 // why is this done????? = it breaks dialogs??
6110 //this.parent().el.setStyle('position', 'relative');
6114 this.footer.parentId = this.id;
6115 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6118 this.el.select('tfoot tr td').first().addClass('hide');
6122 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6124 this.store.on('load', this.onLoad, this);
6125 this.store.on('beforeload', this.onBeforeLoad, this);
6126 this.store.on('update', this.onUpdate, this);
6127 this.store.on('add', this.onAdd, this);
6128 this.store.on("clear", this.clear, this);
6130 this.el.on("contextmenu", this.onContextMenu, this);
6132 this.mainBody.on('scroll', this.onBodyScroll, this);
6134 this.cm.on("headerchange", this.onHeaderChange, this);
6138 onContextMenu : function(e, t)
6140 this.processEvent("contextmenu", e);
6143 processEvent : function(name, e)
6145 if (name != 'touchstart' ) {
6146 this.fireEvent(name, e);
6149 var t = e.getTarget();
6151 var cell = Roo.get(t);
6157 if(cell.findParent('tfoot', false, true)){
6161 if(cell.findParent('thead', false, true)){
6163 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6164 cell = Roo.get(t).findParent('th', false, true);
6166 Roo.log("failed to find th in thead?");
6167 Roo.log(e.getTarget());
6172 var cellIndex = cell.dom.cellIndex;
6174 var ename = name == 'touchstart' ? 'click' : name;
6175 this.fireEvent("header" + ename, this, cellIndex, e);
6180 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6181 cell = Roo.get(t).findParent('td', false, true);
6183 Roo.log("failed to find th in tbody?");
6184 Roo.log(e.getTarget());
6189 var row = cell.findParent('tr', false, true);
6190 var cellIndex = cell.dom.cellIndex;
6191 var rowIndex = row.dom.rowIndex - 1;
6195 this.fireEvent("row" + name, this, rowIndex, e);
6199 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6205 onMouseover : function(e, el)
6207 var cell = Roo.get(el);
6213 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6214 cell = cell.findParent('td', false, true);
6217 var row = cell.findParent('tr', false, true);
6218 var cellIndex = cell.dom.cellIndex;
6219 var rowIndex = row.dom.rowIndex - 1; // start from 0
6221 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6225 onMouseout : function(e, el)
6227 var cell = Roo.get(el);
6233 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6234 cell = cell.findParent('td', false, true);
6237 var row = cell.findParent('tr', false, true);
6238 var cellIndex = cell.dom.cellIndex;
6239 var rowIndex = row.dom.rowIndex - 1; // start from 0
6241 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6245 onClick : function(e, el)
6247 var cell = Roo.get(el);
6249 if(!cell || (!this.cellSelection && !this.rowSelection)){
6253 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6254 cell = cell.findParent('td', false, true);
6257 if(!cell || typeof(cell) == 'undefined'){
6261 var row = cell.findParent('tr', false, true);
6263 if(!row || typeof(row) == 'undefined'){
6267 var cellIndex = cell.dom.cellIndex;
6268 var rowIndex = this.getRowIndex(row);
6270 // why??? - should these not be based on SelectionModel?
6271 if(this.cellSelection){
6272 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6275 if(this.rowSelection){
6276 this.fireEvent('rowclick', this, row, rowIndex, e);
6282 onDblClick : function(e,el)
6284 var cell = Roo.get(el);
6286 if(!cell || (!this.cellSelection && !this.rowSelection)){
6290 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6291 cell = cell.findParent('td', false, true);
6294 if(!cell || typeof(cell) == 'undefined'){
6298 var row = cell.findParent('tr', false, true);
6300 if(!row || typeof(row) == 'undefined'){
6304 var cellIndex = cell.dom.cellIndex;
6305 var rowIndex = this.getRowIndex(row);
6307 if(this.cellSelection){
6308 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6311 if(this.rowSelection){
6312 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6316 sort : function(e,el)
6318 var col = Roo.get(el);
6320 if(!col.hasClass('sortable')){
6324 var sort = col.attr('sort');
6327 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6331 this.store.sortInfo = {field : sort, direction : dir};
6334 Roo.log("calling footer first");
6335 this.footer.onClick('first');
6338 this.store.load({ params : { start : 0 } });
6342 renderHeader : function()
6350 this.totalWidth = 0;
6352 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6354 var config = cm.config[i];
6359 html: cm.getColumnHeader(i)
6364 if(typeof(config.sortable) != 'undefined' && config.sortable){
6366 c.html = '<i class="glyphicon"></i>' + c.html;
6369 if(typeof(config.lgHeader) != 'undefined'){
6370 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6373 if(typeof(config.mdHeader) != 'undefined'){
6374 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6377 if(typeof(config.smHeader) != 'undefined'){
6378 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6381 if(typeof(config.xsHeader) != 'undefined'){
6382 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6389 if(typeof(config.tooltip) != 'undefined'){
6390 c.tooltip = config.tooltip;
6393 if(typeof(config.colspan) != 'undefined'){
6394 c.colspan = config.colspan;
6397 if(typeof(config.hidden) != 'undefined' && config.hidden){
6398 c.style += ' display:none;';
6401 if(typeof(config.dataIndex) != 'undefined'){
6402 c.sort = config.dataIndex;
6407 if(typeof(config.align) != 'undefined' && config.align.length){
6408 c.style += ' text-align:' + config.align + ';';
6411 if(typeof(config.width) != 'undefined'){
6412 c.style += ' width:' + config.width + 'px;';
6413 this.totalWidth += config.width;
6415 this.totalWidth += 100; // assume minimum of 100 per column?
6418 if(typeof(config.cls) != 'undefined'){
6419 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6422 ['xs','sm','md','lg'].map(function(size){
6424 if(typeof(config[size]) == 'undefined'){
6428 if (!config[size]) { // 0 = hidden
6429 c.cls += ' hidden-' + size;
6433 c.cls += ' col-' + size + '-' + config[size];
6443 renderBody : function()
6453 colspan : this.cm.getColumnCount()
6463 renderFooter : function()
6473 colspan : this.cm.getColumnCount()
6487 // Roo.log('ds onload');
6492 var ds = this.store;
6494 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6495 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6496 if (_this.store.sortInfo) {
6498 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6499 e.select('i', true).addClass(['glyphicon-arrow-up']);
6502 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6503 e.select('i', true).addClass(['glyphicon-arrow-down']);
6508 var tbody = this.mainBody;
6510 if(ds.getCount() > 0){
6511 ds.data.each(function(d,rowIndex){
6512 var row = this.renderRow(cm, ds, rowIndex);
6514 tbody.createChild(row);
6518 if(row.cellObjects.length){
6519 Roo.each(row.cellObjects, function(r){
6520 _this.renderCellObject(r);
6527 Roo.each(this.el.select('tbody td', true).elements, function(e){
6528 e.on('mouseover', _this.onMouseover, _this);
6531 Roo.each(this.el.select('tbody td', true).elements, function(e){
6532 e.on('mouseout', _this.onMouseout, _this);
6534 this.fireEvent('rowsrendered', this);
6535 //if(this.loadMask){
6536 // this.maskEl.hide();
6543 onUpdate : function(ds,record)
6545 this.refreshRow(record);
6549 onRemove : function(ds, record, index, isUpdate){
6550 if(isUpdate !== true){
6551 this.fireEvent("beforerowremoved", this, index, record);
6553 var bt = this.mainBody.dom;
6555 var rows = this.el.select('tbody > tr', true).elements;
6557 if(typeof(rows[index]) != 'undefined'){
6558 bt.removeChild(rows[index].dom);
6561 // if(bt.rows[index]){
6562 // bt.removeChild(bt.rows[index]);
6565 if(isUpdate !== true){
6566 //this.stripeRows(index);
6567 //this.syncRowHeights(index, index);
6569 this.fireEvent("rowremoved", this, index, record);
6573 onAdd : function(ds, records, rowIndex)
6575 //Roo.log('on Add called');
6576 // - note this does not handle multiple adding very well..
6577 var bt = this.mainBody.dom;
6578 for (var i =0 ; i < records.length;i++) {
6579 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6580 //Roo.log(records[i]);
6581 //Roo.log(this.store.getAt(rowIndex+i));
6582 this.insertRow(this.store, rowIndex + i, false);
6589 refreshRow : function(record){
6590 var ds = this.store, index;
6591 if(typeof record == 'number'){
6593 record = ds.getAt(index);
6595 index = ds.indexOf(record);
6597 this.insertRow(ds, index, true);
6599 this.onRemove(ds, record, index+1, true);
6601 //this.syncRowHeights(index, index);
6603 this.fireEvent("rowupdated", this, index, record);
6606 insertRow : function(dm, rowIndex, isUpdate){
6609 this.fireEvent("beforerowsinserted", this, rowIndex);
6611 //var s = this.getScrollState();
6612 var row = this.renderRow(this.cm, this.store, rowIndex);
6613 // insert before rowIndex..
6614 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6618 if(row.cellObjects.length){
6619 Roo.each(row.cellObjects, function(r){
6620 _this.renderCellObject(r);
6625 this.fireEvent("rowsinserted", this, rowIndex);
6626 //this.syncRowHeights(firstRow, lastRow);
6627 //this.stripeRows(firstRow);
6634 getRowDom : function(rowIndex)
6636 var rows = this.el.select('tbody > tr', true).elements;
6638 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6641 // returns the object tree for a tr..
6644 renderRow : function(cm, ds, rowIndex)
6647 var d = ds.getAt(rowIndex);
6654 var cellObjects = [];
6656 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6657 var config = cm.config[i];
6659 var renderer = cm.getRenderer(i);
6663 if(typeof(renderer) !== 'undefined'){
6664 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6666 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6667 // and are rendered into the cells after the row is rendered - using the id for the element.
6669 if(typeof(value) === 'object'){
6679 rowIndex : rowIndex,
6684 this.fireEvent('rowclass', this, rowcfg);
6688 cls : rowcfg.rowClass,
6690 html: (typeof(value) === 'object') ? '' : value
6697 if(typeof(config.colspan) != 'undefined'){
6698 td.colspan = config.colspan;
6701 if(typeof(config.hidden) != 'undefined' && config.hidden){
6702 td.style += ' display:none;';
6705 if(typeof(config.align) != 'undefined' && config.align.length){
6706 td.style += ' text-align:' + config.align + ';';
6709 if(typeof(config.width) != 'undefined'){
6710 td.style += ' width:' + config.width + 'px;';
6713 if(typeof(config.cursor) != 'undefined'){
6714 td.style += ' cursor:' + config.cursor + ';';
6717 if(typeof(config.cls) != 'undefined'){
6718 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6721 ['xs','sm','md','lg'].map(function(size){
6723 if(typeof(config[size]) == 'undefined'){
6727 if (!config[size]) { // 0 = hidden
6728 td.cls += ' hidden-' + size;
6732 td.cls += ' col-' + size + '-' + config[size];
6740 row.cellObjects = cellObjects;
6748 onBeforeLoad : function()
6750 //Roo.log('ds onBeforeLoad');
6754 //if(this.loadMask){
6755 // this.maskEl.show();
6763 this.el.select('tbody', true).first().dom.innerHTML = '';
6766 * Show or hide a row.
6767 * @param {Number} rowIndex to show or hide
6768 * @param {Boolean} state hide
6770 setRowVisibility : function(rowIndex, state)
6772 var bt = this.mainBody.dom;
6774 var rows = this.el.select('tbody > tr', true).elements;
6776 if(typeof(rows[rowIndex]) == 'undefined'){
6779 rows[rowIndex].dom.style.display = state ? '' : 'none';
6783 getSelectionModel : function(){
6785 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6787 return this.selModel;
6790 * Render the Roo.bootstrap object from renderder
6792 renderCellObject : function(r)
6796 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6798 var t = r.cfg.render(r.container);
6801 Roo.each(r.cfg.cn, function(c){
6803 container: t.getChildContainer(),
6806 _this.renderCellObject(child);
6811 getRowIndex : function(row)
6815 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6826 * Returns the grid's underlying element = used by panel.Grid
6827 * @return {Element} The element
6829 getGridEl : function(){
6833 * Forces a resize - used by panel.Grid
6834 * @return {Element} The element
6836 autoSize : function()
6838 //var ctr = Roo.get(this.container.dom.parentElement);
6839 var ctr = Roo.get(this.el.dom);
6841 var thd = this.getGridEl().select('thead',true).first();
6842 var tbd = this.getGridEl().select('tbody', true).first();
6843 var tfd = this.getGridEl().select('tfoot', true).first();
6845 var cw = ctr.getWidth();
6849 tbd.setSize(ctr.getWidth(),
6850 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6852 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6855 cw = Math.max(cw, this.totalWidth);
6856 this.getGridEl().select('tr',true).setWidth(cw);
6857 // resize 'expandable coloumn?
6859 return; // we doe not have a view in this design..
6862 onBodyScroll: function()
6864 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6865 this.mainHead.setStyle({
6866 'position' : 'relative',
6867 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6872 var scrollHeight = this.mainBody.dom.scrollHeight;
6874 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6876 var height = this.mainBody.getHeight();
6878 if(scrollHeight - height == scrollTop) {
6880 var total = this.ds.getTotalCount();
6882 if(this.footer.cursor + this.footer.pageSize < total){
6884 this.footer.ds.load({
6886 start : this.footer.cursor + this.footer.pageSize,
6887 limit : this.footer.pageSize
6897 onHeaderChange : function()
6899 this.updateHeaders.apply(this, arguments);
6902 updateHeaders : function()
6904 var header = this.renderHeader();
6905 var table = this.el.select('table', true).first();
6907 this.mainHead.remove();
6908 this.mainHead = table.createChild(header, this.mainBody, true);
6923 * @class Roo.bootstrap.TableCell
6924 * @extends Roo.bootstrap.Component
6925 * Bootstrap TableCell class
6926 * @cfg {String} html cell contain text
6927 * @cfg {String} cls cell class
6928 * @cfg {String} tag cell tag (td|th) default td
6929 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6930 * @cfg {String} align Aligns the content in a cell
6931 * @cfg {String} axis Categorizes cells
6932 * @cfg {String} bgcolor Specifies the background color of a cell
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {Number} colspan Specifies the number of columns a cell should span
6935 * @cfg {String} headers Specifies one or more header cells a cell is related to
6936 * @cfg {Number} height Sets the height of a cell
6937 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6938 * @cfg {Number} rowspan Sets the number of rows a cell should span
6939 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6940 * @cfg {String} valign Vertical aligns the content in a cell
6941 * @cfg {Number} width Specifies the width of a cell
6944 * Create a new TableCell
6945 * @param {Object} config The config object
6948 Roo.bootstrap.TableCell = function(config){
6949 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6952 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6972 getAutoCreate : function(){
6973 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6993 cfg.align=this.align
6999 cfg.bgcolor=this.bgcolor
7002 cfg.charoff=this.charoff
7005 cfg.colspan=this.colspan
7008 cfg.headers=this.headers
7011 cfg.height=this.height
7014 cfg.nowrap=this.nowrap
7017 cfg.rowspan=this.rowspan
7020 cfg.scope=this.scope
7023 cfg.valign=this.valign
7026 cfg.width=this.width
7045 * @class Roo.bootstrap.TableRow
7046 * @extends Roo.bootstrap.Component
7047 * Bootstrap TableRow class
7048 * @cfg {String} cls row class
7049 * @cfg {String} align Aligns the content in a table row
7050 * @cfg {String} bgcolor Specifies a background color for a table row
7051 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7052 * @cfg {String} valign Vertical aligns the content in a table row
7055 * Create a new TableRow
7056 * @param {Object} config The config object
7059 Roo.bootstrap.TableRow = function(config){
7060 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7063 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7071 getAutoCreate : function(){
7072 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7082 cfg.align = this.align;
7085 cfg.bgcolor = this.bgcolor;
7088 cfg.charoff = this.charoff;
7091 cfg.valign = this.valign;
7109 * @class Roo.bootstrap.TableBody
7110 * @extends Roo.bootstrap.Component
7111 * Bootstrap TableBody class
7112 * @cfg {String} cls element class
7113 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7114 * @cfg {String} align Aligns the content inside the element
7115 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7116 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7119 * Create a new TableBody
7120 * @param {Object} config The config object
7123 Roo.bootstrap.TableBody = function(config){
7124 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7127 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7135 getAutoCreate : function(){
7136 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7150 cfg.align = this.align;
7153 cfg.charoff = this.charoff;
7156 cfg.valign = this.valign;
7163 // initEvents : function()
7170 // this.store = Roo.factory(this.store, Roo.data);
7171 // this.store.on('load', this.onLoad, this);
7173 // this.store.load();
7177 // onLoad: function ()
7179 // this.fireEvent('load', this);
7189 * Ext JS Library 1.1.1
7190 * Copyright(c) 2006-2007, Ext JS, LLC.
7192 * Originally Released Under LGPL - original licence link has changed is not relivant.
7195 * <script type="text/javascript">
7198 // as we use this in bootstrap.
7199 Roo.namespace('Roo.form');
7201 * @class Roo.form.Action
7202 * Internal Class used to handle form actions
7204 * @param {Roo.form.BasicForm} el The form element or its id
7205 * @param {Object} config Configuration options
7210 // define the action interface
7211 Roo.form.Action = function(form, options){
7213 this.options = options || {};
7216 * Client Validation Failed
7219 Roo.form.Action.CLIENT_INVALID = 'client';
7221 * Server Validation Failed
7224 Roo.form.Action.SERVER_INVALID = 'server';
7226 * Connect to Server Failed
7229 Roo.form.Action.CONNECT_FAILURE = 'connect';
7231 * Reading Data from Server Failed
7234 Roo.form.Action.LOAD_FAILURE = 'load';
7236 Roo.form.Action.prototype = {
7238 failureType : undefined,
7239 response : undefined,
7243 run : function(options){
7248 success : function(response){
7253 handleResponse : function(response){
7257 // default connection failure
7258 failure : function(response){
7260 this.response = response;
7261 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7262 this.form.afterAction(this, false);
7265 processResponse : function(response){
7266 this.response = response;
7267 if(!response.responseText){
7270 this.result = this.handleResponse(response);
7274 // utility functions used internally
7275 getUrl : function(appendParams){
7276 var url = this.options.url || this.form.url || this.form.el.dom.action;
7278 var p = this.getParams();
7280 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7286 getMethod : function(){
7287 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7290 getParams : function(){
7291 var bp = this.form.baseParams;
7292 var p = this.options.params;
7294 if(typeof p == "object"){
7295 p = Roo.urlEncode(Roo.applyIf(p, bp));
7296 }else if(typeof p == 'string' && bp){
7297 p += '&' + Roo.urlEncode(bp);
7300 p = Roo.urlEncode(bp);
7305 createCallback : function(){
7307 success: this.success,
7308 failure: this.failure,
7310 timeout: (this.form.timeout*1000),
7311 upload: this.form.fileUpload ? this.success : undefined
7316 Roo.form.Action.Submit = function(form, options){
7317 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7320 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7323 haveProgress : false,
7324 uploadComplete : false,
7326 // uploadProgress indicator.
7327 uploadProgress : function()
7329 if (!this.form.progressUrl) {
7333 if (!this.haveProgress) {
7334 Roo.MessageBox.progress("Uploading", "Uploading");
7336 if (this.uploadComplete) {
7337 Roo.MessageBox.hide();
7341 this.haveProgress = true;
7343 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7345 var c = new Roo.data.Connection();
7347 url : this.form.progressUrl,
7352 success : function(req){
7353 //console.log(data);
7357 rdata = Roo.decode(req.responseText)
7359 Roo.log("Invalid data from server..");
7363 if (!rdata || !rdata.success) {
7365 Roo.MessageBox.alert(Roo.encode(rdata));
7368 var data = rdata.data;
7370 if (this.uploadComplete) {
7371 Roo.MessageBox.hide();
7376 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7377 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7380 this.uploadProgress.defer(2000,this);
7383 failure: function(data) {
7384 Roo.log('progress url failed ');
7395 // run get Values on the form, so it syncs any secondary forms.
7396 this.form.getValues();
7398 var o = this.options;
7399 var method = this.getMethod();
7400 var isPost = method == 'POST';
7401 if(o.clientValidation === false || this.form.isValid()){
7403 if (this.form.progressUrl) {
7404 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7405 (new Date() * 1) + '' + Math.random());
7410 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7411 form:this.form.el.dom,
7412 url:this.getUrl(!isPost),
7414 params:isPost ? this.getParams() : null,
7415 isUpload: this.form.fileUpload
7418 this.uploadProgress();
7420 }else if (o.clientValidation !== false){ // client validation failed
7421 this.failureType = Roo.form.Action.CLIENT_INVALID;
7422 this.form.afterAction(this, false);
7426 success : function(response)
7428 this.uploadComplete= true;
7429 if (this.haveProgress) {
7430 Roo.MessageBox.hide();
7434 var result = this.processResponse(response);
7435 if(result === true || result.success){
7436 this.form.afterAction(this, true);
7440 this.form.markInvalid(result.errors);
7441 this.failureType = Roo.form.Action.SERVER_INVALID;
7443 this.form.afterAction(this, false);
7445 failure : function(response)
7447 this.uploadComplete= true;
7448 if (this.haveProgress) {
7449 Roo.MessageBox.hide();
7452 this.response = response;
7453 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7454 this.form.afterAction(this, false);
7457 handleResponse : function(response){
7458 if(this.form.errorReader){
7459 var rs = this.form.errorReader.read(response);
7462 for(var i = 0, len = rs.records.length; i < len; i++) {
7463 var r = rs.records[i];
7467 if(errors.length < 1){
7471 success : rs.success,
7477 ret = Roo.decode(response.responseText);
7481 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7491 Roo.form.Action.Load = function(form, options){
7492 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7493 this.reader = this.form.reader;
7496 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7501 Roo.Ajax.request(Roo.apply(
7502 this.createCallback(), {
7503 method:this.getMethod(),
7504 url:this.getUrl(false),
7505 params:this.getParams()
7509 success : function(response){
7511 var result = this.processResponse(response);
7512 if(result === true || !result.success || !result.data){
7513 this.failureType = Roo.form.Action.LOAD_FAILURE;
7514 this.form.afterAction(this, false);
7517 this.form.clearInvalid();
7518 this.form.setValues(result.data);
7519 this.form.afterAction(this, true);
7522 handleResponse : function(response){
7523 if(this.form.reader){
7524 var rs = this.form.reader.read(response);
7525 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7527 success : rs.success,
7531 return Roo.decode(response.responseText);
7535 Roo.form.Action.ACTION_TYPES = {
7536 'load' : Roo.form.Action.Load,
7537 'submit' : Roo.form.Action.Submit
7546 * @class Roo.bootstrap.Form
7547 * @extends Roo.bootstrap.Component
7548 * Bootstrap Form class
7549 * @cfg {String} method GET | POST (default POST)
7550 * @cfg {String} labelAlign top | left (default top)
7551 * @cfg {String} align left | right - for navbars
7552 * @cfg {Boolean} loadMask load mask when submit (default true)
7557 * @param {Object} config The config object
7561 Roo.bootstrap.Form = function(config){
7562 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7564 Roo.bootstrap.Form.popover.apply();
7568 * @event clientvalidation
7569 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7570 * @param {Form} this
7571 * @param {Boolean} valid true if the form has passed client-side validation
7573 clientvalidation: true,
7575 * @event beforeaction
7576 * Fires before any action is performed. Return false to cancel the action.
7577 * @param {Form} this
7578 * @param {Action} action The action to be performed
7582 * @event actionfailed
7583 * Fires when an action fails.
7584 * @param {Form} this
7585 * @param {Action} action The action that failed
7587 actionfailed : true,
7589 * @event actioncomplete
7590 * Fires when an action is completed.
7591 * @param {Form} this
7592 * @param {Action} action The action that completed
7594 actioncomplete : true
7599 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7602 * @cfg {String} method
7603 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7608 * The URL to use for form actions if one isn't supplied in the action options.
7611 * @cfg {Boolean} fileUpload
7612 * Set to true if this form is a file upload.
7616 * @cfg {Object} baseParams
7617 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7621 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7625 * @cfg {Sting} align (left|right) for navbar forms
7630 activeAction : null,
7633 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7634 * element by passing it or its id or mask the form itself by passing in true.
7637 waitMsgTarget : false,
7642 * @cfg {Boolean} errorMask (true|false) default false
7647 * @cfg {Number} maskOffset Default 100
7652 * @cfg {Boolean} maskBody
7656 getAutoCreate : function(){
7660 method : this.method || 'POST',
7661 id : this.id || Roo.id(),
7664 if (this.parent().xtype.match(/^Nav/)) {
7665 cfg.cls = 'navbar-form navbar-' + this.align;
7669 if (this.labelAlign == 'left' ) {
7670 cfg.cls += ' form-horizontal';
7676 initEvents : function()
7678 this.el.on('submit', this.onSubmit, this);
7679 // this was added as random key presses on the form where triggering form submit.
7680 this.el.on('keypress', function(e) {
7681 if (e.getCharCode() != 13) {
7684 // we might need to allow it for textareas.. and some other items.
7685 // check e.getTarget().
7687 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7691 Roo.log("keypress blocked");
7699 onSubmit : function(e){
7704 * Returns true if client-side validation on the form is successful.
7707 isValid : function(){
7708 var items = this.getItems();
7712 items.each(function(f){
7718 if(!target && f.el.isVisible(true)){
7724 if(this.errorMask && !valid){
7725 Roo.bootstrap.Form.popover.mask(this, target);
7732 * Returns true if any fields in this form have changed since their original load.
7735 isDirty : function(){
7737 var items = this.getItems();
7738 items.each(function(f){
7748 * Performs a predefined action (submit or load) or custom actions you define on this form.
7749 * @param {String} actionName The name of the action type
7750 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7751 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7752 * accept other config options):
7754 Property Type Description
7755 ---------------- --------------- ----------------------------------------------------------------------------------
7756 url String The url for the action (defaults to the form's url)
7757 method String The form method to use (defaults to the form's method, or POST if not defined)
7758 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7759 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7760 validate the form on the client (defaults to false)
7762 * @return {BasicForm} this
7764 doAction : function(action, options){
7765 if(typeof action == 'string'){
7766 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7768 if(this.fireEvent('beforeaction', this, action) !== false){
7769 this.beforeAction(action);
7770 action.run.defer(100, action);
7776 beforeAction : function(action){
7777 var o = action.options;
7782 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7784 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7787 // not really supported yet.. ??
7789 //if(this.waitMsgTarget === true){
7790 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7791 //}else if(this.waitMsgTarget){
7792 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7793 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7795 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7801 afterAction : function(action, success){
7802 this.activeAction = null;
7803 var o = action.options;
7808 Roo.get(document.body).unmask();
7814 //if(this.waitMsgTarget === true){
7815 // this.el.unmask();
7816 //}else if(this.waitMsgTarget){
7817 // this.waitMsgTarget.unmask();
7819 // Roo.MessageBox.updateProgress(1);
7820 // Roo.MessageBox.hide();
7827 Roo.callback(o.success, o.scope, [this, action]);
7828 this.fireEvent('actioncomplete', this, action);
7832 // failure condition..
7833 // we have a scenario where updates need confirming.
7834 // eg. if a locking scenario exists..
7835 // we look for { errors : { needs_confirm : true }} in the response.
7837 (typeof(action.result) != 'undefined') &&
7838 (typeof(action.result.errors) != 'undefined') &&
7839 (typeof(action.result.errors.needs_confirm) != 'undefined')
7842 Roo.log("not supported yet");
7845 Roo.MessageBox.confirm(
7846 "Change requires confirmation",
7847 action.result.errorMsg,
7852 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7862 Roo.callback(o.failure, o.scope, [this, action]);
7863 // show an error message if no failed handler is set..
7864 if (!this.hasListener('actionfailed')) {
7865 Roo.log("need to add dialog support");
7867 Roo.MessageBox.alert("Error",
7868 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7869 action.result.errorMsg :
7870 "Saving Failed, please check your entries or try again"
7875 this.fireEvent('actionfailed', this, action);
7880 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7881 * @param {String} id The value to search for
7884 findField : function(id){
7885 var items = this.getItems();
7886 var field = items.get(id);
7888 items.each(function(f){
7889 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7896 return field || null;
7899 * Mark fields in this form invalid in bulk.
7900 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7901 * @return {BasicForm} this
7903 markInvalid : function(errors){
7904 if(errors instanceof Array){
7905 for(var i = 0, len = errors.length; i < len; i++){
7906 var fieldError = errors[i];
7907 var f = this.findField(fieldError.id);
7909 f.markInvalid(fieldError.msg);
7915 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7916 field.markInvalid(errors[id]);
7920 //Roo.each(this.childForms || [], function (f) {
7921 // f.markInvalid(errors);
7928 * Set values for fields in this form in bulk.
7929 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7930 * @return {BasicForm} this
7932 setValues : function(values){
7933 if(values instanceof Array){ // array of objects
7934 for(var i = 0, len = values.length; i < len; i++){
7936 var f = this.findField(v.id);
7938 f.setValue(v.value);
7939 if(this.trackResetOnLoad){
7940 f.originalValue = f.getValue();
7944 }else{ // object hash
7947 if(typeof values[id] != 'function' && (field = this.findField(id))){
7949 if (field.setFromData &&
7951 field.displayField &&
7952 // combos' with local stores can
7953 // be queried via setValue()
7954 // to set their value..
7955 (field.store && !field.store.isLocal)
7959 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7960 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7961 field.setFromData(sd);
7963 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7965 field.setFromData(values);
7968 field.setValue(values[id]);
7972 if(this.trackResetOnLoad){
7973 field.originalValue = field.getValue();
7979 //Roo.each(this.childForms || [], function (f) {
7980 // f.setValues(values);
7987 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7988 * they are returned as an array.
7989 * @param {Boolean} asString
7992 getValues : function(asString){
7993 //if (this.childForms) {
7994 // copy values from the child forms
7995 // Roo.each(this.childForms, function (f) {
7996 // this.setValues(f.getValues());
8002 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8003 if(asString === true){
8006 return Roo.urlDecode(fs);
8010 * Returns the fields in this form as an object with key/value pairs.
8011 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8014 getFieldValues : function(with_hidden)
8016 var items = this.getItems();
8018 items.each(function(f){
8024 var v = f.getValue();
8026 if (f.inputType =='radio') {
8027 if (typeof(ret[f.getName()]) == 'undefined') {
8028 ret[f.getName()] = ''; // empty..
8031 if (!f.el.dom.checked) {
8039 if(f.xtype == 'MoneyField'){
8040 ret[f.currencyName] = f.getCurrency();
8043 // not sure if this supported any more..
8044 if ((typeof(v) == 'object') && f.getRawValue) {
8045 v = f.getRawValue() ; // dates..
8047 // combo boxes where name != hiddenName...
8048 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8049 ret[f.name] = f.getRawValue();
8051 ret[f.getName()] = v;
8058 * Clears all invalid messages in this form.
8059 * @return {BasicForm} this
8061 clearInvalid : function(){
8062 var items = this.getItems();
8064 items.each(function(f){
8075 * @return {BasicForm} this
8078 var items = this.getItems();
8079 items.each(function(f){
8083 Roo.each(this.childForms || [], function (f) {
8091 getItems : function()
8093 var r=new Roo.util.MixedCollection(false, function(o){
8094 return o.id || (o.id = Roo.id());
8096 var iter = function(el) {
8103 Roo.each(el.items,function(e) {
8117 Roo.apply(Roo.bootstrap.Form, {
8144 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8145 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8146 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8147 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8150 this.maskEl.top.enableDisplayMode("block");
8151 this.maskEl.left.enableDisplayMode("block");
8152 this.maskEl.bottom.enableDisplayMode("block");
8153 this.maskEl.right.enableDisplayMode("block");
8155 this.toolTip = new Roo.bootstrap.Tooltip({
8156 cls : 'roo-form-error-popover',
8158 'left' : ['r-l', [-2,0], 'right'],
8159 'right' : ['l-r', [2,0], 'left'],
8160 'bottom' : ['tl-bl', [0,2], 'top'],
8161 'top' : [ 'bl-tl', [0,-2], 'bottom']
8165 this.toolTip.render(Roo.get(document.body));
8167 this.toolTip.el.enableDisplayMode("block");
8169 Roo.get(document.body).on('click', function(){
8173 Roo.get(document.body).on('touchstart', function(){
8177 this.isApplied = true
8180 mask : function(form, target)
8184 this.target = target;
8186 if(!this.form.errorMask || !target.el){
8190 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8192 Roo.log(scrollable);
8194 var ot = this.target.el.calcOffsetsTo(scrollable);
8196 var scrollTo = ot[1] - this.form.maskOffset;
8198 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8200 scrollable.scrollTo('top', scrollTo);
8202 var box = this.target.el.getBox();
8204 var zIndex = Roo.bootstrap.Modal.zIndex++;
8207 this.maskEl.top.setStyle('position', 'absolute');
8208 this.maskEl.top.setStyle('z-index', zIndex);
8209 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8210 this.maskEl.top.setLeft(0);
8211 this.maskEl.top.setTop(0);
8212 this.maskEl.top.show();
8214 this.maskEl.left.setStyle('position', 'absolute');
8215 this.maskEl.left.setStyle('z-index', zIndex);
8216 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8217 this.maskEl.left.setLeft(0);
8218 this.maskEl.left.setTop(box.y - this.padding);
8219 this.maskEl.left.show();
8221 this.maskEl.bottom.setStyle('position', 'absolute');
8222 this.maskEl.bottom.setStyle('z-index', zIndex);
8223 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8224 this.maskEl.bottom.setLeft(0);
8225 this.maskEl.bottom.setTop(box.bottom + this.padding);
8226 this.maskEl.bottom.show();
8228 this.maskEl.right.setStyle('position', 'absolute');
8229 this.maskEl.right.setStyle('z-index', zIndex);
8230 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8231 this.maskEl.right.setLeft(box.right + this.padding);
8232 this.maskEl.right.setTop(box.y - this.padding);
8233 this.maskEl.right.show();
8235 this.toolTip.bindEl = this.target.el;
8237 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8239 var tip = this.target.blankText;
8241 if(this.target.getValue() !== '' ) {
8243 if (this.target.invalidText.length) {
8244 tip = this.target.invalidText;
8245 } else if (this.target.regexText.length){
8246 tip = this.target.regexText;
8250 this.toolTip.show(tip);
8252 this.intervalID = window.setInterval(function() {
8253 Roo.bootstrap.Form.popover.unmask();
8256 window.onwheel = function(){ return false;};
8258 (function(){ this.isMasked = true; }).defer(500, this);
8264 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8268 this.maskEl.top.setStyle('position', 'absolute');
8269 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8270 this.maskEl.top.hide();
8272 this.maskEl.left.setStyle('position', 'absolute');
8273 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8274 this.maskEl.left.hide();
8276 this.maskEl.bottom.setStyle('position', 'absolute');
8277 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8278 this.maskEl.bottom.hide();
8280 this.maskEl.right.setStyle('position', 'absolute');
8281 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8282 this.maskEl.right.hide();
8284 this.toolTip.hide();
8286 this.toolTip.el.hide();
8288 window.onwheel = function(){ return true;};
8290 if(this.intervalID){
8291 window.clearInterval(this.intervalID);
8292 this.intervalID = false;
8295 this.isMasked = false;
8305 * Ext JS Library 1.1.1
8306 * Copyright(c) 2006-2007, Ext JS, LLC.
8308 * Originally Released Under LGPL - original licence link has changed is not relivant.
8311 * <script type="text/javascript">
8314 * @class Roo.form.VTypes
8315 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8318 Roo.form.VTypes = function(){
8319 // closure these in so they are only created once.
8320 var alpha = /^[a-zA-Z_]+$/;
8321 var alphanum = /^[a-zA-Z0-9_]+$/;
8322 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8323 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8325 // All these messages and functions are configurable
8328 * The function used to validate email addresses
8329 * @param {String} value The email address
8331 'email' : function(v){
8332 return email.test(v);
8335 * The error text to display when the email validation function returns false
8338 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8340 * The keystroke filter mask to be applied on email input
8343 'emailMask' : /[a-z0-9_\.\-@]/i,
8346 * The function used to validate URLs
8347 * @param {String} value The URL
8349 'url' : function(v){
8353 * The error text to display when the url validation function returns false
8356 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8359 * The function used to validate alpha values
8360 * @param {String} value The value
8362 'alpha' : function(v){
8363 return alpha.test(v);
8366 * The error text to display when the alpha validation function returns false
8369 'alphaText' : 'This field should only contain letters and _',
8371 * The keystroke filter mask to be applied on alpha input
8374 'alphaMask' : /[a-z_]/i,
8377 * The function used to validate alphanumeric values
8378 * @param {String} value The value
8380 'alphanum' : function(v){
8381 return alphanum.test(v);
8384 * The error text to display when the alphanumeric validation function returns false
8387 'alphanumText' : 'This field should only contain letters, numbers and _',
8389 * The keystroke filter mask to be applied on alphanumeric input
8392 'alphanumMask' : /[a-z0-9_]/i
8402 * @class Roo.bootstrap.Input
8403 * @extends Roo.bootstrap.Component
8404 * Bootstrap Input class
8405 * @cfg {Boolean} disabled is it disabled
8406 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8407 * @cfg {String} name name of the input
8408 * @cfg {string} fieldLabel - the label associated
8409 * @cfg {string} placeholder - placeholder to put in text.
8410 * @cfg {string} before - input group add on before
8411 * @cfg {string} after - input group add on after
8412 * @cfg {string} size - (lg|sm) or leave empty..
8413 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8414 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8415 * @cfg {Number} md colspan out of 12 for computer-sized screens
8416 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8417 * @cfg {string} value default value of the input
8418 * @cfg {Number} labelWidth set the width of label
8419 * @cfg {Number} labellg set the width of label (1-12)
8420 * @cfg {Number} labelmd set the width of label (1-12)
8421 * @cfg {Number} labelsm set the width of label (1-12)
8422 * @cfg {Number} labelxs set the width of label (1-12)
8423 * @cfg {String} labelAlign (top|left)
8424 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8425 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8426 * @cfg {String} indicatorpos (left|right) default left
8428 * @cfg {String} align (left|center|right) Default left
8429 * @cfg {Boolean} forceFeedback (true|false) Default false
8435 * Create a new Input
8436 * @param {Object} config The config object
8439 Roo.bootstrap.Input = function(config){
8441 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8446 * Fires when this field receives input focus.
8447 * @param {Roo.form.Field} this
8452 * Fires when this field loses input focus.
8453 * @param {Roo.form.Field} this
8458 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8459 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8460 * @param {Roo.form.Field} this
8461 * @param {Roo.EventObject} e The event object
8466 * Fires just before the field blurs if the field value has changed.
8467 * @param {Roo.form.Field} this
8468 * @param {Mixed} newValue The new value
8469 * @param {Mixed} oldValue The original value
8474 * Fires after the field has been marked as invalid.
8475 * @param {Roo.form.Field} this
8476 * @param {String} msg The validation message
8481 * Fires after the field has been validated with no errors.
8482 * @param {Roo.form.Field} this
8487 * Fires after the key up
8488 * @param {Roo.form.Field} this
8489 * @param {Roo.EventObject} e The event Object
8495 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8497 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8498 automatic validation (defaults to "keyup").
8500 validationEvent : "keyup",
8502 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8504 validateOnBlur : true,
8506 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8508 validationDelay : 250,
8510 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8512 focusClass : "x-form-focus", // not needed???
8516 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8518 invalidClass : "has-warning",
8521 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8523 validClass : "has-success",
8526 * @cfg {Boolean} hasFeedback (true|false) default true
8531 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8533 invalidFeedbackClass : "glyphicon-warning-sign",
8536 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8538 validFeedbackClass : "glyphicon-ok",
8541 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8543 selectOnFocus : false,
8546 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8550 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8555 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8557 disableKeyFilter : false,
8560 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8564 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8568 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8570 blankText : "Please complete this mandatory field",
8573 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8577 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8579 maxLength : Number.MAX_VALUE,
8581 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8583 minLengthText : "The minimum length for this field is {0}",
8585 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8587 maxLengthText : "The maximum length for this field is {0}",
8591 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8592 * If available, this function will be called only after the basic validators all return true, and will be passed the
8593 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8597 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8598 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8599 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8603 * @cfg {String} regexText -- Depricated - use Invalid Text
8608 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8614 autocomplete: false,
8633 formatedValue : false,
8634 forceFeedback : false,
8636 indicatorpos : 'left',
8643 parentLabelAlign : function()
8646 while (parent.parent()) {
8647 parent = parent.parent();
8648 if (typeof(parent.labelAlign) !='undefined') {
8649 return parent.labelAlign;
8656 getAutoCreate : function()
8658 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8664 if(this.inputType != 'hidden'){
8665 cfg.cls = 'form-group' //input-group
8671 type : this.inputType,
8673 cls : 'form-control',
8674 placeholder : this.placeholder || '',
8675 autocomplete : this.autocomplete || 'new-password'
8679 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8682 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8683 input.maxLength = this.maxLength;
8686 if (this.disabled) {
8687 input.disabled=true;
8690 if (this.readOnly) {
8691 input.readonly=true;
8695 input.name = this.name;
8699 input.cls += ' input-' + this.size;
8703 ['xs','sm','md','lg'].map(function(size){
8704 if (settings[size]) {
8705 cfg.cls += ' col-' + size + '-' + settings[size];
8709 var inputblock = input;
8713 cls: 'glyphicon form-control-feedback'
8716 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8719 cls : 'has-feedback',
8727 if (this.before || this.after) {
8730 cls : 'input-group',
8734 if (this.before && typeof(this.before) == 'string') {
8736 inputblock.cn.push({
8738 cls : 'roo-input-before input-group-addon',
8742 if (this.before && typeof(this.before) == 'object') {
8743 this.before = Roo.factory(this.before);
8745 inputblock.cn.push({
8747 cls : 'roo-input-before input-group-' +
8748 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8752 inputblock.cn.push(input);
8754 if (this.after && typeof(this.after) == 'string') {
8755 inputblock.cn.push({
8757 cls : 'roo-input-after input-group-addon',
8761 if (this.after && typeof(this.after) == 'object') {
8762 this.after = Roo.factory(this.after);
8764 inputblock.cn.push({
8766 cls : 'roo-input-after input-group-' +
8767 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8771 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8772 inputblock.cls += ' has-feedback';
8773 inputblock.cn.push(feedback);
8777 if (align ==='left' && this.fieldLabel.length) {
8779 cfg.cls += ' roo-form-group-label-left';
8784 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8785 tooltip : 'This field is required'
8790 cls : 'control-label',
8791 html : this.fieldLabel
8802 var labelCfg = cfg.cn[1];
8803 var contentCfg = cfg.cn[2];
8805 if(this.indicatorpos == 'right'){
8810 cls : 'control-label',
8814 html : this.fieldLabel
8818 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8819 tooltip : 'This field is required'
8832 labelCfg = cfg.cn[0];
8833 contentCfg = cfg.cn[1];
8837 if(this.labelWidth > 12){
8838 labelCfg.style = "width: " + this.labelWidth + 'px';
8841 if(this.labelWidth < 13 && this.labelmd == 0){
8842 this.labelmd = this.labelWidth;
8845 if(this.labellg > 0){
8846 labelCfg.cls += ' col-lg-' + this.labellg;
8847 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8850 if(this.labelmd > 0){
8851 labelCfg.cls += ' col-md-' + this.labelmd;
8852 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8855 if(this.labelsm > 0){
8856 labelCfg.cls += ' col-sm-' + this.labelsm;
8857 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8860 if(this.labelxs > 0){
8861 labelCfg.cls += ' col-xs-' + this.labelxs;
8862 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8866 } else if ( this.fieldLabel.length) {
8871 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8872 tooltip : 'This field is required'
8876 //cls : 'input-group-addon',
8877 html : this.fieldLabel
8885 if(this.indicatorpos == 'right'){
8890 //cls : 'input-group-addon',
8891 html : this.fieldLabel
8896 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8897 tooltip : 'This field is required'
8917 if (this.parentType === 'Navbar' && this.parent().bar) {
8918 cfg.cls += ' navbar-form';
8921 if (this.parentType === 'NavGroup') {
8922 cfg.cls += ' navbar-form';
8930 * return the real input element.
8932 inputEl: function ()
8934 return this.el.select('input.form-control',true).first();
8937 tooltipEl : function()
8939 return this.inputEl();
8942 indicatorEl : function()
8944 var indicator = this.el.select('i.roo-required-indicator',true).first();
8954 setDisabled : function(v)
8956 var i = this.inputEl().dom;
8958 i.removeAttribute('disabled');
8962 i.setAttribute('disabled','true');
8964 initEvents : function()
8967 this.inputEl().on("keydown" , this.fireKey, this);
8968 this.inputEl().on("focus", this.onFocus, this);
8969 this.inputEl().on("blur", this.onBlur, this);
8971 this.inputEl().relayEvent('keyup', this);
8973 this.indicator = this.indicatorEl();
8976 this.indicator.addClass('invisible');
8980 // reference to original value for reset
8981 this.originalValue = this.getValue();
8982 //Roo.form.TextField.superclass.initEvents.call(this);
8983 if(this.validationEvent == 'keyup'){
8984 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8985 this.inputEl().on('keyup', this.filterValidation, this);
8987 else if(this.validationEvent !== false){
8988 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8991 if(this.selectOnFocus){
8992 this.on("focus", this.preFocus, this);
8995 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8996 this.inputEl().on("keypress", this.filterKeys, this);
8998 this.inputEl().relayEvent('keypress', this);
9001 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9002 this.el.on("click", this.autoSize, this);
9005 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9006 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9009 if (typeof(this.before) == 'object') {
9010 this.before.render(this.el.select('.roo-input-before',true).first());
9012 if (typeof(this.after) == 'object') {
9013 this.after.render(this.el.select('.roo-input-after',true).first());
9018 filterValidation : function(e){
9019 if(!e.isNavKeyPress()){
9020 this.validationTask.delay(this.validationDelay);
9024 * Validates the field value
9025 * @return {Boolean} True if the value is valid, else false
9027 validate : function(){
9028 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9029 if(this.disabled || this.validateValue(this.getRawValue())){
9040 * Validates a value according to the field's validation rules and marks the field as invalid
9041 * if the validation fails
9042 * @param {Mixed} value The value to validate
9043 * @return {Boolean} True if the value is valid, else false
9045 validateValue : function(value){
9046 if(value.length < 1) { // if it's blank
9047 if(this.allowBlank){
9050 return this.inputEl().hasClass('hide') ? true : false;
9053 if(value.length < this.minLength){
9056 if(value.length > this.maxLength){
9060 var vt = Roo.form.VTypes;
9061 if(!vt[this.vtype](value, this)){
9065 if(typeof this.validator == "function"){
9066 var msg = this.validator(value);
9070 if (typeof(msg) == 'string') {
9071 this.invalidText = msg;
9075 if(this.regex && !this.regex.test(value)){
9085 fireKey : function(e){
9086 //Roo.log('field ' + e.getKey());
9087 if(e.isNavKeyPress()){
9088 this.fireEvent("specialkey", this, e);
9091 focus : function (selectText){
9093 this.inputEl().focus();
9094 if(selectText === true){
9095 this.inputEl().dom.select();
9101 onFocus : function(){
9102 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9103 // this.el.addClass(this.focusClass);
9106 this.hasFocus = true;
9107 this.startValue = this.getValue();
9108 this.fireEvent("focus", this);
9112 beforeBlur : Roo.emptyFn,
9116 onBlur : function(){
9118 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9119 //this.el.removeClass(this.focusClass);
9121 this.hasFocus = false;
9122 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9125 var v = this.getValue();
9126 if(String(v) !== String(this.startValue)){
9127 this.fireEvent('change', this, v, this.startValue);
9129 this.fireEvent("blur", this);
9133 * Resets the current field value to the originally loaded value and clears any validation messages
9136 this.setValue(this.originalValue);
9140 * Returns the name of the field
9141 * @return {Mixed} name The name field
9143 getName: function(){
9147 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9148 * @return {Mixed} value The field value
9150 getValue : function(){
9152 var v = this.inputEl().getValue();
9157 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9158 * @return {Mixed} value The field value
9160 getRawValue : function(){
9161 var v = this.inputEl().getValue();
9167 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9168 * @param {Mixed} value The value to set
9170 setRawValue : function(v){
9171 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9174 selectText : function(start, end){
9175 var v = this.getRawValue();
9177 start = start === undefined ? 0 : start;
9178 end = end === undefined ? v.length : end;
9179 var d = this.inputEl().dom;
9180 if(d.setSelectionRange){
9181 d.setSelectionRange(start, end);
9182 }else if(d.createTextRange){
9183 var range = d.createTextRange();
9184 range.moveStart("character", start);
9185 range.moveEnd("character", v.length-end);
9192 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9193 * @param {Mixed} value The value to set
9195 setValue : function(v){
9198 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9204 processValue : function(value){
9205 if(this.stripCharsRe){
9206 var newValue = value.replace(this.stripCharsRe, '');
9207 if(newValue !== value){
9208 this.setRawValue(newValue);
9215 preFocus : function(){
9217 if(this.selectOnFocus){
9218 this.inputEl().dom.select();
9221 filterKeys : function(e){
9223 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9226 var c = e.getCharCode(), cc = String.fromCharCode(c);
9227 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9230 if(!this.maskRe.test(cc)){
9235 * Clear any invalid styles/messages for this field
9237 clearInvalid : function(){
9239 if(!this.el || this.preventMark){ // not rendered
9244 this.el.removeClass(this.invalidClass);
9246 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9248 var feedback = this.el.select('.form-control-feedback', true).first();
9251 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9256 this.fireEvent('valid', this);
9260 * Mark this field as valid
9262 markValid : function()
9264 if(!this.el || this.preventMark){ // not rendered...
9268 this.el.removeClass([this.invalidClass, this.validClass]);
9270 var feedback = this.el.select('.form-control-feedback', true).first();
9273 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9277 this.indicator.removeClass('visible');
9278 this.indicator.addClass('invisible');
9285 if(this.allowBlank && !this.getRawValue().length){
9289 this.el.addClass(this.validClass);
9291 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9293 var feedback = this.el.select('.form-control-feedback', true).first();
9296 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9297 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9302 this.fireEvent('valid', this);
9306 * Mark this field as invalid
9307 * @param {String} msg The validation message
9309 markInvalid : function(msg)
9311 if(!this.el || this.preventMark){ // not rendered
9315 this.el.removeClass([this.invalidClass, this.validClass]);
9317 var feedback = this.el.select('.form-control-feedback', true).first();
9320 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9327 if(this.allowBlank && !this.getRawValue().length){
9332 this.indicator.removeClass('invisible');
9333 this.indicator.addClass('visible');
9336 this.el.addClass(this.invalidClass);
9338 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9340 var feedback = this.el.select('.form-control-feedback', true).first();
9343 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9345 if(this.getValue().length || this.forceFeedback){
9346 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9353 this.fireEvent('invalid', this, msg);
9356 SafariOnKeyDown : function(event)
9358 // this is a workaround for a password hang bug on chrome/ webkit.
9359 if (this.inputEl().dom.type != 'password') {
9363 var isSelectAll = false;
9365 if(this.inputEl().dom.selectionEnd > 0){
9366 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9368 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9369 event.preventDefault();
9374 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9376 event.preventDefault();
9377 // this is very hacky as keydown always get's upper case.
9379 var cc = String.fromCharCode(event.getCharCode());
9380 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9384 adjustWidth : function(tag, w){
9385 tag = tag.toLowerCase();
9386 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9387 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9391 if(tag == 'textarea'){
9394 }else if(Roo.isOpera){
9398 if(tag == 'textarea'){
9406 setFieldLabel : function(v)
9413 var ar = this.el.select('label > span',true);
9415 if (ar.elements.length) {
9416 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9417 this.fieldLabel = v;
9421 var br = this.el.select('label',true);
9423 if(br.elements.length) {
9424 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9425 this.fieldLabel = v;
9429 Roo.log('Cannot Found any of label > span || label in input');
9433 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9434 this.fieldLabel = v;
9449 * @class Roo.bootstrap.TextArea
9450 * @extends Roo.bootstrap.Input
9451 * Bootstrap TextArea class
9452 * @cfg {Number} cols Specifies the visible width of a text area
9453 * @cfg {Number} rows Specifies the visible number of lines in a text area
9454 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9455 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9456 * @cfg {string} html text
9459 * Create a new TextArea
9460 * @param {Object} config The config object
9463 Roo.bootstrap.TextArea = function(config){
9464 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9468 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9478 getAutoCreate : function(){
9480 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9486 if(this.inputType != 'hidden'){
9487 cfg.cls = 'form-group' //input-group
9495 value : this.value || '',
9496 html: this.html || '',
9497 cls : 'form-control',
9498 placeholder : this.placeholder || ''
9502 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9503 input.maxLength = this.maxLength;
9507 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9511 input.cols = this.cols;
9514 if (this.readOnly) {
9515 input.readonly = true;
9519 input.name = this.name;
9523 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9527 ['xs','sm','md','lg'].map(function(size){
9528 if (settings[size]) {
9529 cfg.cls += ' col-' + size + '-' + settings[size];
9533 var inputblock = input;
9535 if(this.hasFeedback && !this.allowBlank){
9539 cls: 'glyphicon form-control-feedback'
9543 cls : 'has-feedback',
9552 if (this.before || this.after) {
9555 cls : 'input-group',
9559 inputblock.cn.push({
9561 cls : 'input-group-addon',
9566 inputblock.cn.push(input);
9568 if(this.hasFeedback && !this.allowBlank){
9569 inputblock.cls += ' has-feedback';
9570 inputblock.cn.push(feedback);
9574 inputblock.cn.push({
9576 cls : 'input-group-addon',
9583 if (align ==='left' && this.fieldLabel.length) {
9588 cls : 'control-label',
9589 html : this.fieldLabel
9600 if(this.labelWidth > 12){
9601 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9604 if(this.labelWidth < 13 && this.labelmd == 0){
9605 this.labelmd = this.labelWidth;
9608 if(this.labellg > 0){
9609 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9610 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9613 if(this.labelmd > 0){
9614 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9615 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9618 if(this.labelsm > 0){
9619 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9620 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9623 if(this.labelxs > 0){
9624 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9625 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9628 } else if ( this.fieldLabel.length) {
9633 //cls : 'input-group-addon',
9634 html : this.fieldLabel
9652 if (this.disabled) {
9653 input.disabled=true;
9660 * return the real textarea element.
9662 inputEl: function ()
9664 return this.el.select('textarea.form-control',true).first();
9668 * Clear any invalid styles/messages for this field
9670 clearInvalid : function()
9673 if(!this.el || this.preventMark){ // not rendered
9677 var label = this.el.select('label', true).first();
9678 var icon = this.el.select('i.fa-star', true).first();
9684 this.el.removeClass(this.invalidClass);
9686 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9688 var feedback = this.el.select('.form-control-feedback', true).first();
9691 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9696 this.fireEvent('valid', this);
9700 * Mark this field as valid
9702 markValid : function()
9704 if(!this.el || this.preventMark){ // not rendered
9708 this.el.removeClass([this.invalidClass, this.validClass]);
9710 var feedback = this.el.select('.form-control-feedback', true).first();
9713 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9716 if(this.disabled || this.allowBlank){
9720 var label = this.el.select('label', true).first();
9721 var icon = this.el.select('i.fa-star', true).first();
9727 this.el.addClass(this.validClass);
9729 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9731 var feedback = this.el.select('.form-control-feedback', true).first();
9734 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9735 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9740 this.fireEvent('valid', this);
9744 * Mark this field as invalid
9745 * @param {String} msg The validation message
9747 markInvalid : function(msg)
9749 if(!this.el || this.preventMark){ // not rendered
9753 this.el.removeClass([this.invalidClass, this.validClass]);
9755 var feedback = this.el.select('.form-control-feedback', true).first();
9758 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9761 if(this.disabled || this.allowBlank){
9765 var label = this.el.select('label', true).first();
9766 var icon = this.el.select('i.fa-star', true).first();
9768 if(!this.getValue().length && label && !icon){
9769 this.el.createChild({
9771 cls : 'text-danger fa fa-lg fa-star',
9772 tooltip : 'This field is required',
9773 style : 'margin-right:5px;'
9777 this.el.addClass(this.invalidClass);
9779 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9781 var feedback = this.el.select('.form-control-feedback', true).first();
9784 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9786 if(this.getValue().length || this.forceFeedback){
9787 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9794 this.fireEvent('invalid', this, msg);
9802 * trigger field - base class for combo..
9807 * @class Roo.bootstrap.TriggerField
9808 * @extends Roo.bootstrap.Input
9809 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9810 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9811 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9812 * for which you can provide a custom implementation. For example:
9814 var trigger = new Roo.bootstrap.TriggerField();
9815 trigger.onTriggerClick = myTriggerFn;
9816 trigger.applyTo('my-field');
9819 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9820 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9821 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9822 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9823 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9826 * Create a new TriggerField.
9827 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9828 * to the base TextField)
9830 Roo.bootstrap.TriggerField = function(config){
9831 this.mimicing = false;
9832 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9835 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9837 * @cfg {String} triggerClass A CSS class to apply to the trigger
9840 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9845 * @cfg {Boolean} removable (true|false) special filter default false
9849 /** @cfg {Boolean} grow @hide */
9850 /** @cfg {Number} growMin @hide */
9851 /** @cfg {Number} growMax @hide */
9857 autoSize: Roo.emptyFn,
9864 actionMode : 'wrap',
9869 getAutoCreate : function(){
9871 var align = this.labelAlign || this.parentLabelAlign();
9876 cls: 'form-group' //input-group
9883 type : this.inputType,
9884 cls : 'form-control',
9885 autocomplete: 'new-password',
9886 placeholder : this.placeholder || ''
9890 input.name = this.name;
9893 input.cls += ' input-' + this.size;
9896 if (this.disabled) {
9897 input.disabled=true;
9900 var inputblock = input;
9902 if(this.hasFeedback && !this.allowBlank){
9906 cls: 'glyphicon form-control-feedback'
9909 if(this.removable && !this.editable && !this.tickable){
9911 cls : 'has-feedback',
9917 cls : 'roo-combo-removable-btn close'
9924 cls : 'has-feedback',
9933 if(this.removable && !this.editable && !this.tickable){
9935 cls : 'roo-removable',
9941 cls : 'roo-combo-removable-btn close'
9948 if (this.before || this.after) {
9951 cls : 'input-group',
9955 inputblock.cn.push({
9957 cls : 'input-group-addon',
9962 inputblock.cn.push(input);
9964 if(this.hasFeedback && !this.allowBlank){
9965 inputblock.cls += ' has-feedback';
9966 inputblock.cn.push(feedback);
9970 inputblock.cn.push({
9972 cls : 'input-group-addon',
9985 cls: 'form-hidden-field'
9999 cls: 'form-hidden-field'
10003 cls: 'roo-select2-choices',
10007 cls: 'roo-select2-search-field',
10020 cls: 'roo-select2-container input-group',
10025 // cls: 'typeahead typeahead-long dropdown-menu',
10026 // style: 'display:none'
10031 if(!this.multiple && this.showToggleBtn){
10037 if (this.caret != false) {
10040 cls: 'fa fa-' + this.caret
10047 cls : 'input-group-addon btn dropdown-toggle',
10052 cls: 'combobox-clear',
10066 combobox.cls += ' roo-select2-container-multi';
10069 if (align ==='left' && this.fieldLabel.length) {
10071 cfg.cls += ' roo-form-group-label-left';
10076 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10077 tooltip : 'This field is required'
10082 cls : 'control-label',
10083 html : this.fieldLabel
10095 var labelCfg = cfg.cn[1];
10096 var contentCfg = cfg.cn[2];
10098 if(this.indicatorpos == 'right'){
10103 cls : 'control-label',
10107 html : this.fieldLabel
10111 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10112 tooltip : 'This field is required'
10125 labelCfg = cfg.cn[0];
10126 contentCfg = cfg.cn[1];
10129 if(this.labelWidth > 12){
10130 labelCfg.style = "width: " + this.labelWidth + 'px';
10133 if(this.labelWidth < 13 && this.labelmd == 0){
10134 this.labelmd = this.labelWidth;
10137 if(this.labellg > 0){
10138 labelCfg.cls += ' col-lg-' + this.labellg;
10139 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10142 if(this.labelmd > 0){
10143 labelCfg.cls += ' col-md-' + this.labelmd;
10144 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10147 if(this.labelsm > 0){
10148 labelCfg.cls += ' col-sm-' + this.labelsm;
10149 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10152 if(this.labelxs > 0){
10153 labelCfg.cls += ' col-xs-' + this.labelxs;
10154 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10157 } else if ( this.fieldLabel.length) {
10158 // Roo.log(" label");
10162 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10163 tooltip : 'This field is required'
10167 //cls : 'input-group-addon',
10168 html : this.fieldLabel
10176 if(this.indicatorpos == 'right'){
10184 html : this.fieldLabel
10188 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10189 tooltip : 'This field is required'
10202 // Roo.log(" no label && no align");
10209 ['xs','sm','md','lg'].map(function(size){
10210 if (settings[size]) {
10211 cfg.cls += ' col-' + size + '-' + settings[size];
10222 onResize : function(w, h){
10223 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10224 // if(typeof w == 'number'){
10225 // var x = w - this.trigger.getWidth();
10226 // this.inputEl().setWidth(this.adjustWidth('input', x));
10227 // this.trigger.setStyle('left', x+'px');
10232 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10235 getResizeEl : function(){
10236 return this.inputEl();
10240 getPositionEl : function(){
10241 return this.inputEl();
10245 alignErrorIcon : function(){
10246 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10250 initEvents : function(){
10254 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10255 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10256 if(!this.multiple && this.showToggleBtn){
10257 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10258 if(this.hideTrigger){
10259 this.trigger.setDisplayed(false);
10261 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10265 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10268 if(this.removable && !this.editable && !this.tickable){
10269 var close = this.closeTriggerEl();
10272 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10273 close.on('click', this.removeBtnClick, this, close);
10277 //this.trigger.addClassOnOver('x-form-trigger-over');
10278 //this.trigger.addClassOnClick('x-form-trigger-click');
10281 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10285 closeTriggerEl : function()
10287 var close = this.el.select('.roo-combo-removable-btn', true).first();
10288 return close ? close : false;
10291 removeBtnClick : function(e, h, el)
10293 e.preventDefault();
10295 if(this.fireEvent("remove", this) !== false){
10297 this.fireEvent("afterremove", this)
10301 createList : function()
10303 this.list = Roo.get(document.body).createChild({
10305 cls: 'typeahead typeahead-long dropdown-menu',
10306 style: 'display:none'
10309 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10314 initTrigger : function(){
10319 onDestroy : function(){
10321 this.trigger.removeAllListeners();
10322 // this.trigger.remove();
10325 // this.wrap.remove();
10327 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10331 onFocus : function(){
10332 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10334 if(!this.mimicing){
10335 this.wrap.addClass('x-trigger-wrap-focus');
10336 this.mimicing = true;
10337 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10338 if(this.monitorTab){
10339 this.el.on("keydown", this.checkTab, this);
10346 checkTab : function(e){
10347 if(e.getKey() == e.TAB){
10348 this.triggerBlur();
10353 onBlur : function(){
10358 mimicBlur : function(e, t){
10360 if(!this.wrap.contains(t) && this.validateBlur()){
10361 this.triggerBlur();
10367 triggerBlur : function(){
10368 this.mimicing = false;
10369 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10370 if(this.monitorTab){
10371 this.el.un("keydown", this.checkTab, this);
10373 //this.wrap.removeClass('x-trigger-wrap-focus');
10374 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10378 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10379 validateBlur : function(e, t){
10384 onDisable : function(){
10385 this.inputEl().dom.disabled = true;
10386 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10388 // this.wrap.addClass('x-item-disabled');
10393 onEnable : function(){
10394 this.inputEl().dom.disabled = false;
10395 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10397 // this.el.removeClass('x-item-disabled');
10402 onShow : function(){
10403 var ae = this.getActionEl();
10406 ae.dom.style.display = '';
10407 ae.dom.style.visibility = 'visible';
10413 onHide : function(){
10414 var ae = this.getActionEl();
10415 ae.dom.style.display = 'none';
10419 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10420 * by an implementing function.
10422 * @param {EventObject} e
10424 onTriggerClick : Roo.emptyFn
10428 * Ext JS Library 1.1.1
10429 * Copyright(c) 2006-2007, Ext JS, LLC.
10431 * Originally Released Under LGPL - original licence link has changed is not relivant.
10434 * <script type="text/javascript">
10439 * @class Roo.data.SortTypes
10441 * Defines the default sorting (casting?) comparison functions used when sorting data.
10443 Roo.data.SortTypes = {
10445 * Default sort that does nothing
10446 * @param {Mixed} s The value being converted
10447 * @return {Mixed} The comparison value
10449 none : function(s){
10454 * The regular expression used to strip tags
10458 stripTagsRE : /<\/?[^>]+>/gi,
10461 * Strips all HTML tags to sort on text only
10462 * @param {Mixed} s The value being converted
10463 * @return {String} The comparison value
10465 asText : function(s){
10466 return String(s).replace(this.stripTagsRE, "");
10470 * Strips all HTML tags to sort on text only - Case insensitive
10471 * @param {Mixed} s The value being converted
10472 * @return {String} The comparison value
10474 asUCText : function(s){
10475 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10479 * Case insensitive string
10480 * @param {Mixed} s The value being converted
10481 * @return {String} The comparison value
10483 asUCString : function(s) {
10484 return String(s).toUpperCase();
10489 * @param {Mixed} s The value being converted
10490 * @return {Number} The comparison value
10492 asDate : function(s) {
10496 if(s instanceof Date){
10497 return s.getTime();
10499 return Date.parse(String(s));
10504 * @param {Mixed} s The value being converted
10505 * @return {Float} The comparison value
10507 asFloat : function(s) {
10508 var val = parseFloat(String(s).replace(/,/g, ""));
10517 * @param {Mixed} s The value being converted
10518 * @return {Number} The comparison value
10520 asInt : function(s) {
10521 var val = parseInt(String(s).replace(/,/g, ""));
10529 * Ext JS Library 1.1.1
10530 * Copyright(c) 2006-2007, Ext JS, LLC.
10532 * Originally Released Under LGPL - original licence link has changed is not relivant.
10535 * <script type="text/javascript">
10539 * @class Roo.data.Record
10540 * Instances of this class encapsulate both record <em>definition</em> information, and record
10541 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10542 * to access Records cached in an {@link Roo.data.Store} object.<br>
10544 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10545 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10548 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10550 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10551 * {@link #create}. The parameters are the same.
10552 * @param {Array} data An associative Array of data values keyed by the field name.
10553 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10554 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10555 * not specified an integer id is generated.
10557 Roo.data.Record = function(data, id){
10558 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10563 * Generate a constructor for a specific record layout.
10564 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10565 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10566 * Each field definition object may contain the following properties: <ul>
10567 * <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,
10568 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10569 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10570 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10571 * is being used, then this is a string containing the javascript expression to reference the data relative to
10572 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10573 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10574 * this may be omitted.</p></li>
10575 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10576 * <ul><li>auto (Default, implies no conversion)</li>
10581 * <li>date</li></ul></p></li>
10582 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10583 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10584 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10585 * by the Reader into an object that will be stored in the Record. It is passed the
10586 * following parameters:<ul>
10587 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10589 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10591 * <br>usage:<br><pre><code>
10592 var TopicRecord = Roo.data.Record.create(
10593 {name: 'title', mapping: 'topic_title'},
10594 {name: 'author', mapping: 'username'},
10595 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10596 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10597 {name: 'lastPoster', mapping: 'user2'},
10598 {name: 'excerpt', mapping: 'post_text'}
10601 var myNewRecord = new TopicRecord({
10602 title: 'Do my job please',
10605 lastPost: new Date(),
10606 lastPoster: 'Animal',
10607 excerpt: 'No way dude!'
10609 myStore.add(myNewRecord);
10614 Roo.data.Record.create = function(o){
10615 var f = function(){
10616 f.superclass.constructor.apply(this, arguments);
10618 Roo.extend(f, Roo.data.Record);
10619 var p = f.prototype;
10620 p.fields = new Roo.util.MixedCollection(false, function(field){
10623 for(var i = 0, len = o.length; i < len; i++){
10624 p.fields.add(new Roo.data.Field(o[i]));
10626 f.getField = function(name){
10627 return p.fields.get(name);
10632 Roo.data.Record.AUTO_ID = 1000;
10633 Roo.data.Record.EDIT = 'edit';
10634 Roo.data.Record.REJECT = 'reject';
10635 Roo.data.Record.COMMIT = 'commit';
10637 Roo.data.Record.prototype = {
10639 * Readonly flag - true if this record has been modified.
10648 join : function(store){
10649 this.store = store;
10653 * Set the named field to the specified value.
10654 * @param {String} name The name of the field to set.
10655 * @param {Object} value The value to set the field to.
10657 set : function(name, value){
10658 if(this.data[name] == value){
10662 if(!this.modified){
10663 this.modified = {};
10665 if(typeof this.modified[name] == 'undefined'){
10666 this.modified[name] = this.data[name];
10668 this.data[name] = value;
10669 if(!this.editing && this.store){
10670 this.store.afterEdit(this);
10675 * Get the value of the named field.
10676 * @param {String} name The name of the field to get the value of.
10677 * @return {Object} The value of the field.
10679 get : function(name){
10680 return this.data[name];
10684 beginEdit : function(){
10685 this.editing = true;
10686 this.modified = {};
10690 cancelEdit : function(){
10691 this.editing = false;
10692 delete this.modified;
10696 endEdit : function(){
10697 this.editing = false;
10698 if(this.dirty && this.store){
10699 this.store.afterEdit(this);
10704 * Usually called by the {@link Roo.data.Store} which owns the Record.
10705 * Rejects all changes made to the Record since either creation, or the last commit operation.
10706 * Modified fields are reverted to their original values.
10708 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10709 * of reject operations.
10711 reject : function(){
10712 var m = this.modified;
10714 if(typeof m[n] != "function"){
10715 this.data[n] = m[n];
10718 this.dirty = false;
10719 delete this.modified;
10720 this.editing = false;
10722 this.store.afterReject(this);
10727 * Usually called by the {@link Roo.data.Store} which owns the Record.
10728 * Commits all changes made to the Record since either creation, or the last commit operation.
10730 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10731 * of commit operations.
10733 commit : function(){
10734 this.dirty = false;
10735 delete this.modified;
10736 this.editing = false;
10738 this.store.afterCommit(this);
10743 hasError : function(){
10744 return this.error != null;
10748 clearError : function(){
10753 * Creates a copy of this record.
10754 * @param {String} id (optional) A new record id if you don't want to use this record's id
10757 copy : function(newId) {
10758 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10762 * Ext JS Library 1.1.1
10763 * Copyright(c) 2006-2007, Ext JS, LLC.
10765 * Originally Released Under LGPL - original licence link has changed is not relivant.
10768 * <script type="text/javascript">
10774 * @class Roo.data.Store
10775 * @extends Roo.util.Observable
10776 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10777 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10779 * 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
10780 * has no knowledge of the format of the data returned by the Proxy.<br>
10782 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10783 * instances from the data object. These records are cached and made available through accessor functions.
10785 * Creates a new Store.
10786 * @param {Object} config A config object containing the objects needed for the Store to access data,
10787 * and read the data into Records.
10789 Roo.data.Store = function(config){
10790 this.data = new Roo.util.MixedCollection(false);
10791 this.data.getKey = function(o){
10794 this.baseParams = {};
10796 this.paramNames = {
10801 "multisort" : "_multisort"
10804 if(config && config.data){
10805 this.inlineData = config.data;
10806 delete config.data;
10809 Roo.apply(this, config);
10811 if(this.reader){ // reader passed
10812 this.reader = Roo.factory(this.reader, Roo.data);
10813 this.reader.xmodule = this.xmodule || false;
10814 if(!this.recordType){
10815 this.recordType = this.reader.recordType;
10817 if(this.reader.onMetaChange){
10818 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10822 if(this.recordType){
10823 this.fields = this.recordType.prototype.fields;
10825 this.modified = [];
10829 * @event datachanged
10830 * Fires when the data cache has changed, and a widget which is using this Store
10831 * as a Record cache should refresh its view.
10832 * @param {Store} this
10834 datachanged : true,
10836 * @event metachange
10837 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10838 * @param {Store} this
10839 * @param {Object} meta The JSON metadata
10844 * Fires when Records have been added to the Store
10845 * @param {Store} this
10846 * @param {Roo.data.Record[]} records The array of Records added
10847 * @param {Number} index The index at which the record(s) were added
10852 * Fires when a Record has been removed from the Store
10853 * @param {Store} this
10854 * @param {Roo.data.Record} record The Record that was removed
10855 * @param {Number} index The index at which the record was removed
10860 * Fires when a Record has been updated
10861 * @param {Store} this
10862 * @param {Roo.data.Record} record The Record that was updated
10863 * @param {String} operation The update operation being performed. Value may be one of:
10865 Roo.data.Record.EDIT
10866 Roo.data.Record.REJECT
10867 Roo.data.Record.COMMIT
10873 * Fires when the data cache has been cleared.
10874 * @param {Store} this
10878 * @event beforeload
10879 * Fires before a request is made for a new data object. If the beforeload handler returns false
10880 * the load action will be canceled.
10881 * @param {Store} this
10882 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10886 * @event beforeloadadd
10887 * Fires after a new set of Records has been loaded.
10888 * @param {Store} this
10889 * @param {Roo.data.Record[]} records The Records that were loaded
10890 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10892 beforeloadadd : true,
10895 * Fires after a new set of Records has been loaded, before they are added to the store.
10896 * @param {Store} this
10897 * @param {Roo.data.Record[]} records The Records that were loaded
10898 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10899 * @params {Object} return from reader
10903 * @event loadexception
10904 * Fires if an exception occurs in the Proxy during loading.
10905 * Called with the signature of the Proxy's "loadexception" event.
10906 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10909 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10910 * @param {Object} load options
10911 * @param {Object} jsonData from your request (normally this contains the Exception)
10913 loadexception : true
10917 this.proxy = Roo.factory(this.proxy, Roo.data);
10918 this.proxy.xmodule = this.xmodule || false;
10919 this.relayEvents(this.proxy, ["loadexception"]);
10921 this.sortToggle = {};
10922 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10924 Roo.data.Store.superclass.constructor.call(this);
10926 if(this.inlineData){
10927 this.loadData(this.inlineData);
10928 delete this.inlineData;
10932 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10934 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10935 * without a remote query - used by combo/forms at present.
10939 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10942 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10945 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10946 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10949 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10950 * on any HTTP request
10953 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10956 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10960 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10961 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10963 remoteSort : false,
10966 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10967 * loaded or when a record is removed. (defaults to false).
10969 pruneModifiedRecords : false,
10972 lastOptions : null,
10975 * Add Records to the Store and fires the add event.
10976 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10978 add : function(records){
10979 records = [].concat(records);
10980 for(var i = 0, len = records.length; i < len; i++){
10981 records[i].join(this);
10983 var index = this.data.length;
10984 this.data.addAll(records);
10985 this.fireEvent("add", this, records, index);
10989 * Remove a Record from the Store and fires the remove event.
10990 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10992 remove : function(record){
10993 var index = this.data.indexOf(record);
10994 this.data.removeAt(index);
10995 if(this.pruneModifiedRecords){
10996 this.modified.remove(record);
10998 this.fireEvent("remove", this, record, index);
11002 * Remove all Records from the Store and fires the clear event.
11004 removeAll : function(){
11006 if(this.pruneModifiedRecords){
11007 this.modified = [];
11009 this.fireEvent("clear", this);
11013 * Inserts Records to the Store at the given index and fires the add event.
11014 * @param {Number} index The start index at which to insert the passed Records.
11015 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11017 insert : function(index, records){
11018 records = [].concat(records);
11019 for(var i = 0, len = records.length; i < len; i++){
11020 this.data.insert(index, records[i]);
11021 records[i].join(this);
11023 this.fireEvent("add", this, records, index);
11027 * Get the index within the cache of the passed Record.
11028 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11029 * @return {Number} The index of the passed Record. Returns -1 if not found.
11031 indexOf : function(record){
11032 return this.data.indexOf(record);
11036 * Get the index within the cache of the Record with the passed id.
11037 * @param {String} id The id of the Record to find.
11038 * @return {Number} The index of the Record. Returns -1 if not found.
11040 indexOfId : function(id){
11041 return this.data.indexOfKey(id);
11045 * Get the Record with the specified id.
11046 * @param {String} id The id of the Record to find.
11047 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11049 getById : function(id){
11050 return this.data.key(id);
11054 * Get the Record at the specified index.
11055 * @param {Number} index The index of the Record to find.
11056 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11058 getAt : function(index){
11059 return this.data.itemAt(index);
11063 * Returns a range of Records between specified indices.
11064 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11065 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11066 * @return {Roo.data.Record[]} An array of Records
11068 getRange : function(start, end){
11069 return this.data.getRange(start, end);
11073 storeOptions : function(o){
11074 o = Roo.apply({}, o);
11077 this.lastOptions = o;
11081 * Loads the Record cache from the configured Proxy using the configured Reader.
11083 * If using remote paging, then the first load call must specify the <em>start</em>
11084 * and <em>limit</em> properties in the options.params property to establish the initial
11085 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11087 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11088 * and this call will return before the new data has been loaded. Perform any post-processing
11089 * in a callback function, or in a "load" event handler.</strong>
11091 * @param {Object} options An object containing properties which control loading options:<ul>
11092 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11093 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11094 * passed the following arguments:<ul>
11095 * <li>r : Roo.data.Record[]</li>
11096 * <li>options: Options object from the load call</li>
11097 * <li>success: Boolean success indicator</li></ul></li>
11098 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11099 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11102 load : function(options){
11103 options = options || {};
11104 if(this.fireEvent("beforeload", this, options) !== false){
11105 this.storeOptions(options);
11106 var p = Roo.apply(options.params || {}, this.baseParams);
11107 // if meta was not loaded from remote source.. try requesting it.
11108 if (!this.reader.metaFromRemote) {
11109 p._requestMeta = 1;
11111 if(this.sortInfo && this.remoteSort){
11112 var pn = this.paramNames;
11113 p[pn["sort"]] = this.sortInfo.field;
11114 p[pn["dir"]] = this.sortInfo.direction;
11116 if (this.multiSort) {
11117 var pn = this.paramNames;
11118 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11121 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11126 * Reloads the Record cache from the configured Proxy using the configured Reader and
11127 * the options from the last load operation performed.
11128 * @param {Object} options (optional) An object containing properties which may override the options
11129 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11130 * the most recently used options are reused).
11132 reload : function(options){
11133 this.load(Roo.applyIf(options||{}, this.lastOptions));
11137 // Called as a callback by the Reader during a load operation.
11138 loadRecords : function(o, options, success){
11139 if(!o || success === false){
11140 if(success !== false){
11141 this.fireEvent("load", this, [], options, o);
11143 if(options.callback){
11144 options.callback.call(options.scope || this, [], options, false);
11148 // if data returned failure - throw an exception.
11149 if (o.success === false) {
11150 // show a message if no listener is registered.
11151 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11152 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11154 // loadmask wil be hooked into this..
11155 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11158 var r = o.records, t = o.totalRecords || r.length;
11160 this.fireEvent("beforeloadadd", this, r, options, o);
11162 if(!options || options.add !== true){
11163 if(this.pruneModifiedRecords){
11164 this.modified = [];
11166 for(var i = 0, len = r.length; i < len; i++){
11170 this.data = this.snapshot;
11171 delete this.snapshot;
11174 this.data.addAll(r);
11175 this.totalLength = t;
11177 this.fireEvent("datachanged", this);
11179 this.totalLength = Math.max(t, this.data.length+r.length);
11183 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11185 var e = new Roo.data.Record({});
11187 e.set(this.parent.displayField, this.parent.emptyTitle);
11188 e.set(this.parent.valueField, '');
11193 this.fireEvent("load", this, r, options, o);
11194 if(options.callback){
11195 options.callback.call(options.scope || this, r, options, true);
11201 * Loads data from a passed data block. A Reader which understands the format of the data
11202 * must have been configured in the constructor.
11203 * @param {Object} data The data block from which to read the Records. The format of the data expected
11204 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11205 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11207 loadData : function(o, append){
11208 var r = this.reader.readRecords(o);
11209 this.loadRecords(r, {add: append}, true);
11213 * Gets the number of cached records.
11215 * <em>If using paging, this may not be the total size of the dataset. If the data object
11216 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11217 * the data set size</em>
11219 getCount : function(){
11220 return this.data.length || 0;
11224 * Gets the total number of records in the dataset as returned by the server.
11226 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11227 * the dataset size</em>
11229 getTotalCount : function(){
11230 return this.totalLength || 0;
11234 * Returns the sort state of the Store as an object with two properties:
11236 field {String} The name of the field by which the Records are sorted
11237 direction {String} The sort order, "ASC" or "DESC"
11240 getSortState : function(){
11241 return this.sortInfo;
11245 applySort : function(){
11246 if(this.sortInfo && !this.remoteSort){
11247 var s = this.sortInfo, f = s.field;
11248 var st = this.fields.get(f).sortType;
11249 var fn = function(r1, r2){
11250 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11251 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11253 this.data.sort(s.direction, fn);
11254 if(this.snapshot && this.snapshot != this.data){
11255 this.snapshot.sort(s.direction, fn);
11261 * Sets the default sort column and order to be used by the next load operation.
11262 * @param {String} fieldName The name of the field to sort by.
11263 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11265 setDefaultSort : function(field, dir){
11266 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11270 * Sort the Records.
11271 * If remote sorting is used, the sort is performed on the server, and the cache is
11272 * reloaded. If local sorting is used, the cache is sorted internally.
11273 * @param {String} fieldName The name of the field to sort by.
11274 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11276 sort : function(fieldName, dir){
11277 var f = this.fields.get(fieldName);
11279 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11281 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11282 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11287 this.sortToggle[f.name] = dir;
11288 this.sortInfo = {field: f.name, direction: dir};
11289 if(!this.remoteSort){
11291 this.fireEvent("datachanged", this);
11293 this.load(this.lastOptions);
11298 * Calls the specified function for each of the Records in the cache.
11299 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11300 * Returning <em>false</em> aborts and exits the iteration.
11301 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11303 each : function(fn, scope){
11304 this.data.each(fn, scope);
11308 * Gets all records modified since the last commit. Modified records are persisted across load operations
11309 * (e.g., during paging).
11310 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11312 getModifiedRecords : function(){
11313 return this.modified;
11317 createFilterFn : function(property, value, anyMatch){
11318 if(!value.exec){ // not a regex
11319 value = String(value);
11320 if(value.length == 0){
11323 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11325 return function(r){
11326 return value.test(r.data[property]);
11331 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11332 * @param {String} property A field on your records
11333 * @param {Number} start The record index to start at (defaults to 0)
11334 * @param {Number} end The last record index to include (defaults to length - 1)
11335 * @return {Number} The sum
11337 sum : function(property, start, end){
11338 var rs = this.data.items, v = 0;
11339 start = start || 0;
11340 end = (end || end === 0) ? end : rs.length-1;
11342 for(var i = start; i <= end; i++){
11343 v += (rs[i].data[property] || 0);
11349 * Filter the records by a specified property.
11350 * @param {String} field A field on your records
11351 * @param {String/RegExp} value Either a string that the field
11352 * should start with or a RegExp to test against the field
11353 * @param {Boolean} anyMatch True to match any part not just the beginning
11355 filter : function(property, value, anyMatch){
11356 var fn = this.createFilterFn(property, value, anyMatch);
11357 return fn ? this.filterBy(fn) : this.clearFilter();
11361 * Filter by a function. The specified function will be called with each
11362 * record in this data source. If the function returns true the record is included,
11363 * otherwise it is filtered.
11364 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11365 * @param {Object} scope (optional) The scope of the function (defaults to this)
11367 filterBy : function(fn, scope){
11368 this.snapshot = this.snapshot || this.data;
11369 this.data = this.queryBy(fn, scope||this);
11370 this.fireEvent("datachanged", this);
11374 * Query the records by a specified property.
11375 * @param {String} field A field on your records
11376 * @param {String/RegExp} value Either a string that the field
11377 * should start with or a RegExp to test against the field
11378 * @param {Boolean} anyMatch True to match any part not just the beginning
11379 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11381 query : function(property, value, anyMatch){
11382 var fn = this.createFilterFn(property, value, anyMatch);
11383 return fn ? this.queryBy(fn) : this.data.clone();
11387 * Query by a function. The specified function will be called with each
11388 * record in this data source. If the function returns true the record is included
11390 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11391 * @param {Object} scope (optional) The scope of the function (defaults to this)
11392 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11394 queryBy : function(fn, scope){
11395 var data = this.snapshot || this.data;
11396 return data.filterBy(fn, scope||this);
11400 * Collects unique values for a particular dataIndex from this store.
11401 * @param {String} dataIndex The property to collect
11402 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11403 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11404 * @return {Array} An array of the unique values
11406 collect : function(dataIndex, allowNull, bypassFilter){
11407 var d = (bypassFilter === true && this.snapshot) ?
11408 this.snapshot.items : this.data.items;
11409 var v, sv, r = [], l = {};
11410 for(var i = 0, len = d.length; i < len; i++){
11411 v = d[i].data[dataIndex];
11413 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11422 * Revert to a view of the Record cache with no filtering applied.
11423 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11425 clearFilter : function(suppressEvent){
11426 if(this.snapshot && this.snapshot != this.data){
11427 this.data = this.snapshot;
11428 delete this.snapshot;
11429 if(suppressEvent !== true){
11430 this.fireEvent("datachanged", this);
11436 afterEdit : function(record){
11437 if(this.modified.indexOf(record) == -1){
11438 this.modified.push(record);
11440 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11444 afterReject : function(record){
11445 this.modified.remove(record);
11446 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11450 afterCommit : function(record){
11451 this.modified.remove(record);
11452 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11456 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11457 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11459 commitChanges : function(){
11460 var m = this.modified.slice(0);
11461 this.modified = [];
11462 for(var i = 0, len = m.length; i < len; i++){
11468 * Cancel outstanding changes on all changed records.
11470 rejectChanges : function(){
11471 var m = this.modified.slice(0);
11472 this.modified = [];
11473 for(var i = 0, len = m.length; i < len; i++){
11478 onMetaChange : function(meta, rtype, o){
11479 this.recordType = rtype;
11480 this.fields = rtype.prototype.fields;
11481 delete this.snapshot;
11482 this.sortInfo = meta.sortInfo || this.sortInfo;
11483 this.modified = [];
11484 this.fireEvent('metachange', this, this.reader.meta);
11487 moveIndex : function(data, type)
11489 var index = this.indexOf(data);
11491 var newIndex = index + type;
11495 this.insert(newIndex, data);
11500 * Ext JS Library 1.1.1
11501 * Copyright(c) 2006-2007, Ext JS, LLC.
11503 * Originally Released Under LGPL - original licence link has changed is not relivant.
11506 * <script type="text/javascript">
11510 * @class Roo.data.SimpleStore
11511 * @extends Roo.data.Store
11512 * Small helper class to make creating Stores from Array data easier.
11513 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11514 * @cfg {Array} fields An array of field definition objects, or field name strings.
11515 * @cfg {Array} data The multi-dimensional array of data
11517 * @param {Object} config
11519 Roo.data.SimpleStore = function(config){
11520 Roo.data.SimpleStore.superclass.constructor.call(this, {
11522 reader: new Roo.data.ArrayReader({
11525 Roo.data.Record.create(config.fields)
11527 proxy : new Roo.data.MemoryProxy(config.data)
11531 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11533 * Ext JS Library 1.1.1
11534 * Copyright(c) 2006-2007, Ext JS, LLC.
11536 * Originally Released Under LGPL - original licence link has changed is not relivant.
11539 * <script type="text/javascript">
11544 * @extends Roo.data.Store
11545 * @class Roo.data.JsonStore
11546 * Small helper class to make creating Stores for JSON data easier. <br/>
11548 var store = new Roo.data.JsonStore({
11549 url: 'get-images.php',
11551 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11554 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11555 * JsonReader and HttpProxy (unless inline data is provided).</b>
11556 * @cfg {Array} fields An array of field definition objects, or field name strings.
11558 * @param {Object} config
11560 Roo.data.JsonStore = function(c){
11561 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11562 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11563 reader: new Roo.data.JsonReader(c, c.fields)
11566 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11568 * Ext JS Library 1.1.1
11569 * Copyright(c) 2006-2007, Ext JS, LLC.
11571 * Originally Released Under LGPL - original licence link has changed is not relivant.
11574 * <script type="text/javascript">
11578 Roo.data.Field = function(config){
11579 if(typeof config == "string"){
11580 config = {name: config};
11582 Roo.apply(this, config);
11585 this.type = "auto";
11588 var st = Roo.data.SortTypes;
11589 // named sortTypes are supported, here we look them up
11590 if(typeof this.sortType == "string"){
11591 this.sortType = st[this.sortType];
11594 // set default sortType for strings and dates
11595 if(!this.sortType){
11598 this.sortType = st.asUCString;
11601 this.sortType = st.asDate;
11604 this.sortType = st.none;
11609 var stripRe = /[\$,%]/g;
11611 // prebuilt conversion function for this field, instead of
11612 // switching every time we're reading a value
11614 var cv, dateFormat = this.dateFormat;
11619 cv = function(v){ return v; };
11622 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11626 return v !== undefined && v !== null && v !== '' ?
11627 parseInt(String(v).replace(stripRe, ""), 10) : '';
11632 return v !== undefined && v !== null && v !== '' ?
11633 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11638 cv = function(v){ return v === true || v === "true" || v == 1; };
11645 if(v instanceof Date){
11649 if(dateFormat == "timestamp"){
11650 return new Date(v*1000);
11652 return Date.parseDate(v, dateFormat);
11654 var parsed = Date.parse(v);
11655 return parsed ? new Date(parsed) : null;
11664 Roo.data.Field.prototype = {
11672 * Ext JS Library 1.1.1
11673 * Copyright(c) 2006-2007, Ext JS, LLC.
11675 * Originally Released Under LGPL - original licence link has changed is not relivant.
11678 * <script type="text/javascript">
11681 // Base class for reading structured data from a data source. This class is intended to be
11682 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11685 * @class Roo.data.DataReader
11686 * Base class for reading structured data from a data source. This class is intended to be
11687 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11690 Roo.data.DataReader = function(meta, recordType){
11694 this.recordType = recordType instanceof Array ?
11695 Roo.data.Record.create(recordType) : recordType;
11698 Roo.data.DataReader.prototype = {
11700 * Create an empty record
11701 * @param {Object} data (optional) - overlay some values
11702 * @return {Roo.data.Record} record created.
11704 newRow : function(d) {
11706 this.recordType.prototype.fields.each(function(c) {
11708 case 'int' : da[c.name] = 0; break;
11709 case 'date' : da[c.name] = new Date(); break;
11710 case 'float' : da[c.name] = 0.0; break;
11711 case 'boolean' : da[c.name] = false; break;
11712 default : da[c.name] = ""; break;
11716 return new this.recordType(Roo.apply(da, d));
11721 * Ext JS Library 1.1.1
11722 * Copyright(c) 2006-2007, Ext JS, LLC.
11724 * Originally Released Under LGPL - original licence link has changed is not relivant.
11727 * <script type="text/javascript">
11731 * @class Roo.data.DataProxy
11732 * @extends Roo.data.Observable
11733 * This class is an abstract base class for implementations which provide retrieval of
11734 * unformatted data objects.<br>
11736 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11737 * (of the appropriate type which knows how to parse the data object) to provide a block of
11738 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11740 * Custom implementations must implement the load method as described in
11741 * {@link Roo.data.HttpProxy#load}.
11743 Roo.data.DataProxy = function(){
11746 * @event beforeload
11747 * Fires before a network request is made to retrieve a data object.
11748 * @param {Object} This DataProxy object.
11749 * @param {Object} params The params parameter to the load function.
11754 * Fires before the load method's callback is called.
11755 * @param {Object} This DataProxy object.
11756 * @param {Object} o The data object.
11757 * @param {Object} arg The callback argument object passed to the load function.
11761 * @event loadexception
11762 * Fires if an Exception occurs during data retrieval.
11763 * @param {Object} This DataProxy object.
11764 * @param {Object} o The data object.
11765 * @param {Object} arg The callback argument object passed to the load function.
11766 * @param {Object} e The Exception.
11768 loadexception : true
11770 Roo.data.DataProxy.superclass.constructor.call(this);
11773 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11776 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11780 * Ext JS Library 1.1.1
11781 * Copyright(c) 2006-2007, Ext JS, LLC.
11783 * Originally Released Under LGPL - original licence link has changed is not relivant.
11786 * <script type="text/javascript">
11789 * @class Roo.data.MemoryProxy
11790 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11791 * to the Reader when its load method is called.
11793 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11795 Roo.data.MemoryProxy = function(data){
11799 Roo.data.MemoryProxy.superclass.constructor.call(this);
11803 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11806 * Load data from the requested source (in this case an in-memory
11807 * data object passed to the constructor), read the data object into
11808 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11809 * process that block using the passed callback.
11810 * @param {Object} params This parameter is not used by the MemoryProxy class.
11811 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11812 * object into a block of Roo.data.Records.
11813 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11814 * The function must be passed <ul>
11815 * <li>The Record block object</li>
11816 * <li>The "arg" argument from the load function</li>
11817 * <li>A boolean success indicator</li>
11819 * @param {Object} scope The scope in which to call the callback
11820 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11822 load : function(params, reader, callback, scope, arg){
11823 params = params || {};
11826 result = reader.readRecords(this.data);
11828 this.fireEvent("loadexception", this, arg, null, e);
11829 callback.call(scope, null, arg, false);
11832 callback.call(scope, result, arg, true);
11836 update : function(params, records){
11841 * Ext JS Library 1.1.1
11842 * Copyright(c) 2006-2007, Ext JS, LLC.
11844 * Originally Released Under LGPL - original licence link has changed is not relivant.
11847 * <script type="text/javascript">
11850 * @class Roo.data.HttpProxy
11851 * @extends Roo.data.DataProxy
11852 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11853 * configured to reference a certain URL.<br><br>
11855 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11856 * from which the running page was served.<br><br>
11858 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11860 * Be aware that to enable the browser to parse an XML document, the server must set
11861 * the Content-Type header in the HTTP response to "text/xml".
11863 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11864 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11865 * will be used to make the request.
11867 Roo.data.HttpProxy = function(conn){
11868 Roo.data.HttpProxy.superclass.constructor.call(this);
11869 // is conn a conn config or a real conn?
11871 this.useAjax = !conn || !conn.events;
11875 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11876 // thse are take from connection...
11879 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11882 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11883 * extra parameters to each request made by this object. (defaults to undefined)
11886 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11887 * to each request made by this object. (defaults to undefined)
11890 * @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)
11893 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11896 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11902 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11906 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11907 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11908 * a finer-grained basis than the DataProxy events.
11910 getConnection : function(){
11911 return this.useAjax ? Roo.Ajax : this.conn;
11915 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11916 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11917 * process that block using the passed callback.
11918 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11919 * for the request to the remote server.
11920 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11921 * object into a block of Roo.data.Records.
11922 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11923 * The function must be passed <ul>
11924 * <li>The Record block object</li>
11925 * <li>The "arg" argument from the load function</li>
11926 * <li>A boolean success indicator</li>
11928 * @param {Object} scope The scope in which to call the callback
11929 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11931 load : function(params, reader, callback, scope, arg){
11932 if(this.fireEvent("beforeload", this, params) !== false){
11934 params : params || {},
11936 callback : callback,
11941 callback : this.loadResponse,
11945 Roo.applyIf(o, this.conn);
11946 if(this.activeRequest){
11947 Roo.Ajax.abort(this.activeRequest);
11949 this.activeRequest = Roo.Ajax.request(o);
11951 this.conn.request(o);
11954 callback.call(scope||this, null, arg, false);
11959 loadResponse : function(o, success, response){
11960 delete this.activeRequest;
11962 this.fireEvent("loadexception", this, o, response);
11963 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11968 result = o.reader.read(response);
11970 this.fireEvent("loadexception", this, o, response, e);
11971 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11975 this.fireEvent("load", this, o, o.request.arg);
11976 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11980 update : function(dataSet){
11985 updateResponse : function(dataSet){
11990 * Ext JS Library 1.1.1
11991 * Copyright(c) 2006-2007, Ext JS, LLC.
11993 * Originally Released Under LGPL - original licence link has changed is not relivant.
11996 * <script type="text/javascript">
12000 * @class Roo.data.ScriptTagProxy
12001 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12002 * other than the originating domain of the running page.<br><br>
12004 * <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
12005 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12007 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12008 * source code that is used as the source inside a <script> tag.<br><br>
12010 * In order for the browser to process the returned data, the server must wrap the data object
12011 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12012 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12013 * depending on whether the callback name was passed:
12016 boolean scriptTag = false;
12017 String cb = request.getParameter("callback");
12020 response.setContentType("text/javascript");
12022 response.setContentType("application/x-json");
12024 Writer out = response.getWriter();
12026 out.write(cb + "(");
12028 out.print(dataBlock.toJsonString());
12035 * @param {Object} config A configuration object.
12037 Roo.data.ScriptTagProxy = function(config){
12038 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12039 Roo.apply(this, config);
12040 this.head = document.getElementsByTagName("head")[0];
12043 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12045 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12047 * @cfg {String} url The URL from which to request the data object.
12050 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12054 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12055 * the server the name of the callback function set up by the load call to process the returned data object.
12056 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12057 * javascript output which calls this named function passing the data object as its only parameter.
12059 callbackParam : "callback",
12061 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12062 * name to the request.
12067 * Load data from the configured URL, read the data object into
12068 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12069 * process that block using the passed callback.
12070 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12071 * for the request to the remote server.
12072 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12073 * object into a block of Roo.data.Records.
12074 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12075 * The function must be passed <ul>
12076 * <li>The Record block object</li>
12077 * <li>The "arg" argument from the load function</li>
12078 * <li>A boolean success indicator</li>
12080 * @param {Object} scope The scope in which to call the callback
12081 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12083 load : function(params, reader, callback, scope, arg){
12084 if(this.fireEvent("beforeload", this, params) !== false){
12086 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12088 var url = this.url;
12089 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12091 url += "&_dc=" + (new Date().getTime());
12093 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12096 cb : "stcCallback"+transId,
12097 scriptId : "stcScript"+transId,
12101 callback : callback,
12107 window[trans.cb] = function(o){
12108 conn.handleResponse(o, trans);
12111 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12113 if(this.autoAbort !== false){
12117 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12119 var script = document.createElement("script");
12120 script.setAttribute("src", url);
12121 script.setAttribute("type", "text/javascript");
12122 script.setAttribute("id", trans.scriptId);
12123 this.head.appendChild(script);
12125 this.trans = trans;
12127 callback.call(scope||this, null, arg, false);
12132 isLoading : function(){
12133 return this.trans ? true : false;
12137 * Abort the current server request.
12139 abort : function(){
12140 if(this.isLoading()){
12141 this.destroyTrans(this.trans);
12146 destroyTrans : function(trans, isLoaded){
12147 this.head.removeChild(document.getElementById(trans.scriptId));
12148 clearTimeout(trans.timeoutId);
12150 window[trans.cb] = undefined;
12152 delete window[trans.cb];
12155 // if hasn't been loaded, wait for load to remove it to prevent script error
12156 window[trans.cb] = function(){
12157 window[trans.cb] = undefined;
12159 delete window[trans.cb];
12166 handleResponse : function(o, trans){
12167 this.trans = false;
12168 this.destroyTrans(trans, true);
12171 result = trans.reader.readRecords(o);
12173 this.fireEvent("loadexception", this, o, trans.arg, e);
12174 trans.callback.call(trans.scope||window, null, trans.arg, false);
12177 this.fireEvent("load", this, o, trans.arg);
12178 trans.callback.call(trans.scope||window, result, trans.arg, true);
12182 handleFailure : function(trans){
12183 this.trans = false;
12184 this.destroyTrans(trans, false);
12185 this.fireEvent("loadexception", this, null, trans.arg);
12186 trans.callback.call(trans.scope||window, null, trans.arg, false);
12190 * Ext JS Library 1.1.1
12191 * Copyright(c) 2006-2007, Ext JS, LLC.
12193 * Originally Released Under LGPL - original licence link has changed is not relivant.
12196 * <script type="text/javascript">
12200 * @class Roo.data.JsonReader
12201 * @extends Roo.data.DataReader
12202 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12203 * based on mappings in a provided Roo.data.Record constructor.
12205 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12206 * in the reply previously.
12211 var RecordDef = Roo.data.Record.create([
12212 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12213 {name: 'occupation'} // This field will use "occupation" as the mapping.
12215 var myReader = new Roo.data.JsonReader({
12216 totalProperty: "results", // The property which contains the total dataset size (optional)
12217 root: "rows", // The property which contains an Array of row objects
12218 id: "id" // The property within each row object that provides an ID for the record (optional)
12222 * This would consume a JSON file like this:
12224 { 'results': 2, 'rows': [
12225 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12226 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12229 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12230 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12231 * paged from the remote server.
12232 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12233 * @cfg {String} root name of the property which contains the Array of row objects.
12234 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12235 * @cfg {Array} fields Array of field definition objects
12237 * Create a new JsonReader
12238 * @param {Object} meta Metadata configuration options
12239 * @param {Object} recordType Either an Array of field definition objects,
12240 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12242 Roo.data.JsonReader = function(meta, recordType){
12245 // set some defaults:
12246 Roo.applyIf(meta, {
12247 totalProperty: 'total',
12248 successProperty : 'success',
12253 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12255 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12258 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12259 * Used by Store query builder to append _requestMeta to params.
12262 metaFromRemote : false,
12264 * This method is only used by a DataProxy which has retrieved data from a remote server.
12265 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12266 * @return {Object} data A data block which is used by an Roo.data.Store object as
12267 * a cache of Roo.data.Records.
12269 read : function(response){
12270 var json = response.responseText;
12272 var o = /* eval:var:o */ eval("("+json+")");
12274 throw {message: "JsonReader.read: Json object not found"};
12280 this.metaFromRemote = true;
12281 this.meta = o.metaData;
12282 this.recordType = Roo.data.Record.create(o.metaData.fields);
12283 this.onMetaChange(this.meta, this.recordType, o);
12285 return this.readRecords(o);
12288 // private function a store will implement
12289 onMetaChange : function(meta, recordType, o){
12296 simpleAccess: function(obj, subsc) {
12303 getJsonAccessor: function(){
12305 return function(expr) {
12307 return(re.test(expr))
12308 ? new Function("obj", "return obj." + expr)
12313 return Roo.emptyFn;
12318 * Create a data block containing Roo.data.Records from an XML document.
12319 * @param {Object} o An object which contains an Array of row objects in the property specified
12320 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12321 * which contains the total size of the dataset.
12322 * @return {Object} data A data block which is used by an Roo.data.Store object as
12323 * a cache of Roo.data.Records.
12325 readRecords : function(o){
12327 * After any data loads, the raw JSON data is available for further custom processing.
12331 var s = this.meta, Record = this.recordType,
12332 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12334 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12336 if(s.totalProperty) {
12337 this.getTotal = this.getJsonAccessor(s.totalProperty);
12339 if(s.successProperty) {
12340 this.getSuccess = this.getJsonAccessor(s.successProperty);
12342 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12344 var g = this.getJsonAccessor(s.id);
12345 this.getId = function(rec) {
12347 return (r === undefined || r === "") ? null : r;
12350 this.getId = function(){return null;};
12353 for(var jj = 0; jj < fl; jj++){
12355 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12356 this.ef[jj] = this.getJsonAccessor(map);
12360 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12361 if(s.totalProperty){
12362 var vt = parseInt(this.getTotal(o), 10);
12367 if(s.successProperty){
12368 var vs = this.getSuccess(o);
12369 if(vs === false || vs === 'false'){
12374 for(var i = 0; i < c; i++){
12377 var id = this.getId(n);
12378 for(var j = 0; j < fl; j++){
12380 var v = this.ef[j](n);
12382 Roo.log('missing convert for ' + f.name);
12386 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12388 var record = new Record(values, id);
12390 records[i] = record;
12396 totalRecords : totalRecords
12401 * Ext JS Library 1.1.1
12402 * Copyright(c) 2006-2007, Ext JS, LLC.
12404 * Originally Released Under LGPL - original licence link has changed is not relivant.
12407 * <script type="text/javascript">
12411 * @class Roo.data.ArrayReader
12412 * @extends Roo.data.DataReader
12413 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12414 * Each element of that Array represents a row of data fields. The
12415 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12416 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12420 var RecordDef = Roo.data.Record.create([
12421 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12422 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12424 var myReader = new Roo.data.ArrayReader({
12425 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12429 * This would consume an Array like this:
12431 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12433 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12435 * Create a new JsonReader
12436 * @param {Object} meta Metadata configuration options.
12437 * @param {Object} recordType Either an Array of field definition objects
12438 * as specified to {@link Roo.data.Record#create},
12439 * or an {@link Roo.data.Record} object
12440 * created using {@link Roo.data.Record#create}.
12442 Roo.data.ArrayReader = function(meta, recordType){
12443 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12446 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12448 * Create a data block containing Roo.data.Records from an XML document.
12449 * @param {Object} o An Array of row objects which represents the dataset.
12450 * @return {Object} data A data block which is used by an Roo.data.Store object as
12451 * a cache of Roo.data.Records.
12453 readRecords : function(o){
12454 var sid = this.meta ? this.meta.id : null;
12455 var recordType = this.recordType, fields = recordType.prototype.fields;
12458 for(var i = 0; i < root.length; i++){
12461 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12462 for(var j = 0, jlen = fields.length; j < jlen; j++){
12463 var f = fields.items[j];
12464 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12465 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12467 values[f.name] = v;
12469 var record = new recordType(values, id);
12471 records[records.length] = record;
12475 totalRecords : records.length
12484 * @class Roo.bootstrap.ComboBox
12485 * @extends Roo.bootstrap.TriggerField
12486 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12487 * @cfg {Boolean} append (true|false) default false
12488 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12489 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12490 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12491 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12492 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12493 * @cfg {Boolean} animate default true
12494 * @cfg {Boolean} emptyResultText only for touch device
12495 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12496 * @cfg {String} emptyTitle default ''
12498 * Create a new ComboBox.
12499 * @param {Object} config Configuration options
12501 Roo.bootstrap.ComboBox = function(config){
12502 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12506 * Fires when the dropdown list is expanded
12507 * @param {Roo.bootstrap.ComboBox} combo This combo box
12512 * Fires when the dropdown list is collapsed
12513 * @param {Roo.bootstrap.ComboBox} combo This combo box
12517 * @event beforeselect
12518 * Fires before a list item is selected. Return false to cancel the selection.
12519 * @param {Roo.bootstrap.ComboBox} combo This combo box
12520 * @param {Roo.data.Record} record The data record returned from the underlying store
12521 * @param {Number} index The index of the selected item in the dropdown list
12523 'beforeselect' : true,
12526 * Fires when a list item is selected
12527 * @param {Roo.bootstrap.ComboBox} combo This combo box
12528 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12529 * @param {Number} index The index of the selected item in the dropdown list
12533 * @event beforequery
12534 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12535 * The event object passed has these properties:
12536 * @param {Roo.bootstrap.ComboBox} combo This combo box
12537 * @param {String} query The query
12538 * @param {Boolean} forceAll true to force "all" query
12539 * @param {Boolean} cancel true to cancel the query
12540 * @param {Object} e The query event object
12542 'beforequery': true,
12545 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12546 * @param {Roo.bootstrap.ComboBox} combo This combo box
12551 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12552 * @param {Roo.bootstrap.ComboBox} combo This combo box
12553 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12558 * Fires when the remove value from the combobox array
12559 * @param {Roo.bootstrap.ComboBox} combo This combo box
12563 * @event afterremove
12564 * Fires when the remove value from the combobox array
12565 * @param {Roo.bootstrap.ComboBox} combo This combo box
12567 'afterremove' : true,
12569 * @event specialfilter
12570 * Fires when specialfilter
12571 * @param {Roo.bootstrap.ComboBox} combo This combo box
12573 'specialfilter' : true,
12576 * Fires when tick the element
12577 * @param {Roo.bootstrap.ComboBox} combo This combo box
12581 * @event touchviewdisplay
12582 * Fires when touch view require special display (default is using displayField)
12583 * @param {Roo.bootstrap.ComboBox} combo This combo box
12584 * @param {Object} cfg set html .
12586 'touchviewdisplay' : true
12591 this.tickItems = [];
12593 this.selectedIndex = -1;
12594 if(this.mode == 'local'){
12595 if(config.queryDelay === undefined){
12596 this.queryDelay = 10;
12598 if(config.minChars === undefined){
12604 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12607 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12608 * rendering into an Roo.Editor, defaults to false)
12611 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12612 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12615 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12618 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12619 * the dropdown list (defaults to undefined, with no header element)
12623 * @cfg {String/Roo.Template} tpl The template to use to render the output
12627 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12629 listWidth: undefined,
12631 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12632 * mode = 'remote' or 'text' if mode = 'local')
12634 displayField: undefined,
12637 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12638 * mode = 'remote' or 'value' if mode = 'local').
12639 * Note: use of a valueField requires the user make a selection
12640 * in order for a value to be mapped.
12642 valueField: undefined,
12644 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12649 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12650 * field's data value (defaults to the underlying DOM element's name)
12652 hiddenName: undefined,
12654 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12658 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12660 selectedClass: 'active',
12663 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12667 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12668 * anchor positions (defaults to 'tl-bl')
12670 listAlign: 'tl-bl?',
12672 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12676 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12677 * query specified by the allQuery config option (defaults to 'query')
12679 triggerAction: 'query',
12681 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12682 * (defaults to 4, does not apply if editable = false)
12686 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12687 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12691 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12692 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12696 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12697 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12701 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12702 * when editable = true (defaults to false)
12704 selectOnFocus:false,
12706 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12708 queryParam: 'query',
12710 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12711 * when mode = 'remote' (defaults to 'Loading...')
12713 loadingText: 'Loading...',
12715 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12719 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12723 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12724 * traditional select (defaults to true)
12728 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12732 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12736 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12737 * listWidth has a higher value)
12741 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12742 * allow the user to set arbitrary text into the field (defaults to false)
12744 forceSelection:false,
12746 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12747 * if typeAhead = true (defaults to 250)
12749 typeAheadDelay : 250,
12751 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12752 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12754 valueNotFoundText : undefined,
12756 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12758 blockFocus : false,
12761 * @cfg {Boolean} disableClear Disable showing of clear button.
12763 disableClear : false,
12765 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12767 alwaysQuery : false,
12770 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12775 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12777 invalidClass : "has-warning",
12780 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12782 validClass : "has-success",
12785 * @cfg {Boolean} specialFilter (true|false) special filter default false
12787 specialFilter : false,
12790 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12792 mobileTouchView : true,
12795 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12797 useNativeIOS : false,
12799 ios_options : false,
12811 btnPosition : 'right',
12812 triggerList : true,
12813 showToggleBtn : true,
12815 emptyResultText: 'Empty',
12816 triggerText : 'Select',
12819 // element that contains real text value.. (when hidden is used..)
12821 getAutoCreate : function()
12826 * Render classic select for iso
12829 if(Roo.isIOS && this.useNativeIOS){
12830 cfg = this.getAutoCreateNativeIOS();
12838 if(Roo.isTouch && this.mobileTouchView){
12839 cfg = this.getAutoCreateTouchView();
12846 if(!this.tickable){
12847 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12852 * ComboBox with tickable selections
12855 var align = this.labelAlign || this.parentLabelAlign();
12858 cls : 'form-group roo-combobox-tickable' //input-group
12861 var btn_text_select = '';
12862 var btn_text_done = '';
12863 var btn_text_cancel = '';
12865 if (this.btn_text_show) {
12866 btn_text_select = 'Select';
12867 btn_text_done = 'Done';
12868 btn_text_cancel = 'Cancel';
12873 cls : 'tickable-buttons',
12878 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12879 //html : this.triggerText
12880 html: btn_text_select
12886 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12888 html: btn_text_done
12894 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12896 html: btn_text_cancel
12902 buttons.cn.unshift({
12904 cls: 'roo-select2-search-field-input'
12910 Roo.each(buttons.cn, function(c){
12912 c.cls += ' btn-' + _this.size;
12915 if (_this.disabled) {
12926 cls: 'form-hidden-field'
12930 cls: 'roo-select2-choices',
12934 cls: 'roo-select2-search-field',
12945 cls: 'roo-select2-container input-group roo-select2-container-multi',
12950 // cls: 'typeahead typeahead-long dropdown-menu',
12951 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12956 if(this.hasFeedback && !this.allowBlank){
12960 cls: 'glyphicon form-control-feedback'
12963 combobox.cn.push(feedback);
12967 if (align ==='left' && this.fieldLabel.length) {
12969 cfg.cls += ' roo-form-group-label-left';
12974 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12975 tooltip : 'This field is required'
12980 cls : 'control-label',
12981 html : this.fieldLabel
12993 var labelCfg = cfg.cn[1];
12994 var contentCfg = cfg.cn[2];
12997 if(this.indicatorpos == 'right'){
13003 cls : 'control-label',
13007 html : this.fieldLabel
13011 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13012 tooltip : 'This field is required'
13027 labelCfg = cfg.cn[0];
13028 contentCfg = cfg.cn[1];
13032 if(this.labelWidth > 12){
13033 labelCfg.style = "width: " + this.labelWidth + 'px';
13036 if(this.labelWidth < 13 && this.labelmd == 0){
13037 this.labelmd = this.labelWidth;
13040 if(this.labellg > 0){
13041 labelCfg.cls += ' col-lg-' + this.labellg;
13042 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13045 if(this.labelmd > 0){
13046 labelCfg.cls += ' col-md-' + this.labelmd;
13047 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13050 if(this.labelsm > 0){
13051 labelCfg.cls += ' col-sm-' + this.labelsm;
13052 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13055 if(this.labelxs > 0){
13056 labelCfg.cls += ' col-xs-' + this.labelxs;
13057 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13061 } else if ( this.fieldLabel.length) {
13062 // Roo.log(" label");
13066 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13067 tooltip : 'This field is required'
13071 //cls : 'input-group-addon',
13072 html : this.fieldLabel
13077 if(this.indicatorpos == 'right'){
13081 //cls : 'input-group-addon',
13082 html : this.fieldLabel
13086 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13087 tooltip : 'This field is required'
13096 // Roo.log(" no label && no align");
13103 ['xs','sm','md','lg'].map(function(size){
13104 if (settings[size]) {
13105 cfg.cls += ' col-' + size + '-' + settings[size];
13113 _initEventsCalled : false,
13116 initEvents: function()
13118 if (this._initEventsCalled) { // as we call render... prevent looping...
13121 this._initEventsCalled = true;
13124 throw "can not find store for combo";
13127 this.indicator = this.indicatorEl();
13129 this.store = Roo.factory(this.store, Roo.data);
13130 this.store.parent = this;
13132 // if we are building from html. then this element is so complex, that we can not really
13133 // use the rendered HTML.
13134 // so we have to trash and replace the previous code.
13135 if (Roo.XComponent.build_from_html) {
13136 // remove this element....
13137 var e = this.el.dom, k=0;
13138 while (e ) { e = e.previousSibling; ++k;}
13143 this.rendered = false;
13145 this.render(this.parent().getChildContainer(true), k);
13148 if(Roo.isIOS && this.useNativeIOS){
13149 this.initIOSView();
13157 if(Roo.isTouch && this.mobileTouchView){
13158 this.initTouchView();
13163 this.initTickableEvents();
13167 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13169 if(this.hiddenName){
13171 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13173 this.hiddenField.dom.value =
13174 this.hiddenValue !== undefined ? this.hiddenValue :
13175 this.value !== undefined ? this.value : '';
13177 // prevent input submission
13178 this.el.dom.removeAttribute('name');
13179 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13184 // this.el.dom.setAttribute('autocomplete', 'off');
13187 var cls = 'x-combo-list';
13189 //this.list = new Roo.Layer({
13190 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13196 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13197 _this.list.setWidth(lw);
13200 this.list.on('mouseover', this.onViewOver, this);
13201 this.list.on('mousemove', this.onViewMove, this);
13202 this.list.on('scroll', this.onViewScroll, this);
13205 this.list.swallowEvent('mousewheel');
13206 this.assetHeight = 0;
13209 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13210 this.assetHeight += this.header.getHeight();
13213 this.innerList = this.list.createChild({cls:cls+'-inner'});
13214 this.innerList.on('mouseover', this.onViewOver, this);
13215 this.innerList.on('mousemove', this.onViewMove, this);
13216 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13218 if(this.allowBlank && !this.pageSize && !this.disableClear){
13219 this.footer = this.list.createChild({cls:cls+'-ft'});
13220 this.pageTb = new Roo.Toolbar(this.footer);
13224 this.footer = this.list.createChild({cls:cls+'-ft'});
13225 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13226 {pageSize: this.pageSize});
13230 if (this.pageTb && this.allowBlank && !this.disableClear) {
13232 this.pageTb.add(new Roo.Toolbar.Fill(), {
13233 cls: 'x-btn-icon x-btn-clear',
13235 handler: function()
13238 _this.clearValue();
13239 _this.onSelect(false, -1);
13244 this.assetHeight += this.footer.getHeight();
13249 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13252 this.view = new Roo.View(this.list, this.tpl, {
13253 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13255 //this.view.wrapEl.setDisplayed(false);
13256 this.view.on('click', this.onViewClick, this);
13259 this.store.on('beforeload', this.onBeforeLoad, this);
13260 this.store.on('load', this.onLoad, this);
13261 this.store.on('loadexception', this.onLoadException, this);
13263 if(this.resizable){
13264 this.resizer = new Roo.Resizable(this.list, {
13265 pinned:true, handles:'se'
13267 this.resizer.on('resize', function(r, w, h){
13268 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13269 this.listWidth = w;
13270 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13271 this.restrictHeight();
13273 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13276 if(!this.editable){
13277 this.editable = true;
13278 this.setEditable(false);
13283 if (typeof(this.events.add.listeners) != 'undefined') {
13285 this.addicon = this.wrap.createChild(
13286 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13288 this.addicon.on('click', function(e) {
13289 this.fireEvent('add', this);
13292 if (typeof(this.events.edit.listeners) != 'undefined') {
13294 this.editicon = this.wrap.createChild(
13295 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13296 if (this.addicon) {
13297 this.editicon.setStyle('margin-left', '40px');
13299 this.editicon.on('click', function(e) {
13301 // we fire even if inothing is selected..
13302 this.fireEvent('edit', this, this.lastData );
13308 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13309 "up" : function(e){
13310 this.inKeyMode = true;
13314 "down" : function(e){
13315 if(!this.isExpanded()){
13316 this.onTriggerClick();
13318 this.inKeyMode = true;
13323 "enter" : function(e){
13324 // this.onViewClick();
13328 if(this.fireEvent("specialkey", this, e)){
13329 this.onViewClick(false);
13335 "esc" : function(e){
13339 "tab" : function(e){
13342 if(this.fireEvent("specialkey", this, e)){
13343 this.onViewClick(false);
13351 doRelay : function(foo, bar, hname){
13352 if(hname == 'down' || this.scope.isExpanded()){
13353 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13362 this.queryDelay = Math.max(this.queryDelay || 10,
13363 this.mode == 'local' ? 10 : 250);
13366 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13368 if(this.typeAhead){
13369 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13371 if(this.editable !== false){
13372 this.inputEl().on("keyup", this.onKeyUp, this);
13374 if(this.forceSelection){
13375 this.inputEl().on('blur', this.doForce, this);
13379 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13380 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13384 initTickableEvents: function()
13388 if(this.hiddenName){
13390 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13392 this.hiddenField.dom.value =
13393 this.hiddenValue !== undefined ? this.hiddenValue :
13394 this.value !== undefined ? this.value : '';
13396 // prevent input submission
13397 this.el.dom.removeAttribute('name');
13398 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13403 // this.list = this.el.select('ul.dropdown-menu',true).first();
13405 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13406 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13407 if(this.triggerList){
13408 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13411 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13412 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13414 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13415 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13417 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13418 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13420 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13421 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13422 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13425 this.cancelBtn.hide();
13430 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13431 _this.list.setWidth(lw);
13434 this.list.on('mouseover', this.onViewOver, this);
13435 this.list.on('mousemove', this.onViewMove, this);
13437 this.list.on('scroll', this.onViewScroll, this);
13440 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>';
13443 this.view = new Roo.View(this.list, this.tpl, {
13444 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13447 //this.view.wrapEl.setDisplayed(false);
13448 this.view.on('click', this.onViewClick, this);
13452 this.store.on('beforeload', this.onBeforeLoad, this);
13453 this.store.on('load', this.onLoad, this);
13454 this.store.on('loadexception', this.onLoadException, this);
13457 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13458 "up" : function(e){
13459 this.inKeyMode = true;
13463 "down" : function(e){
13464 this.inKeyMode = true;
13468 "enter" : function(e){
13469 if(this.fireEvent("specialkey", this, e)){
13470 this.onViewClick(false);
13476 "esc" : function(e){
13477 this.onTickableFooterButtonClick(e, false, false);
13480 "tab" : function(e){
13481 this.fireEvent("specialkey", this, e);
13483 this.onTickableFooterButtonClick(e, false, false);
13490 doRelay : function(e, fn, key){
13491 if(this.scope.isExpanded()){
13492 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13501 this.queryDelay = Math.max(this.queryDelay || 10,
13502 this.mode == 'local' ? 10 : 250);
13505 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13507 if(this.typeAhead){
13508 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13511 if(this.editable !== false){
13512 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13515 this.indicator = this.indicatorEl();
13517 if(this.indicator){
13518 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13519 this.indicator.hide();
13524 onDestroy : function(){
13526 this.view.setStore(null);
13527 this.view.el.removeAllListeners();
13528 this.view.el.remove();
13529 this.view.purgeListeners();
13532 this.list.dom.innerHTML = '';
13536 this.store.un('beforeload', this.onBeforeLoad, this);
13537 this.store.un('load', this.onLoad, this);
13538 this.store.un('loadexception', this.onLoadException, this);
13540 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13544 fireKey : function(e){
13545 if(e.isNavKeyPress() && !this.list.isVisible()){
13546 this.fireEvent("specialkey", this, e);
13551 onResize: function(w, h){
13552 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13554 // if(typeof w != 'number'){
13555 // // we do not handle it!?!?
13558 // var tw = this.trigger.getWidth();
13559 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13560 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13562 // this.inputEl().setWidth( this.adjustWidth('input', x));
13564 // //this.trigger.setStyle('left', x+'px');
13566 // if(this.list && this.listWidth === undefined){
13567 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13568 // this.list.setWidth(lw);
13569 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13577 * Allow or prevent the user from directly editing the field text. If false is passed,
13578 * the user will only be able to select from the items defined in the dropdown list. This method
13579 * is the runtime equivalent of setting the 'editable' config option at config time.
13580 * @param {Boolean} value True to allow the user to directly edit the field text
13582 setEditable : function(value){
13583 if(value == this.editable){
13586 this.editable = value;
13588 this.inputEl().dom.setAttribute('readOnly', true);
13589 this.inputEl().on('mousedown', this.onTriggerClick, this);
13590 this.inputEl().addClass('x-combo-noedit');
13592 this.inputEl().dom.setAttribute('readOnly', false);
13593 this.inputEl().un('mousedown', this.onTriggerClick, this);
13594 this.inputEl().removeClass('x-combo-noedit');
13600 onBeforeLoad : function(combo,opts){
13601 if(!this.hasFocus){
13605 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13607 this.restrictHeight();
13608 this.selectedIndex = -1;
13612 onLoad : function(){
13614 this.hasQuery = false;
13616 if(!this.hasFocus){
13620 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13621 this.loading.hide();
13624 if(this.store.getCount() > 0){
13627 this.restrictHeight();
13628 if(this.lastQuery == this.allQuery){
13629 if(this.editable && !this.tickable){
13630 this.inputEl().dom.select();
13634 !this.selectByValue(this.value, true) &&
13637 !this.store.lastOptions ||
13638 typeof(this.store.lastOptions.add) == 'undefined' ||
13639 this.store.lastOptions.add != true
13642 this.select(0, true);
13645 if(this.autoFocus){
13648 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13649 this.taTask.delay(this.typeAheadDelay);
13653 this.onEmptyResults();
13659 onLoadException : function()
13661 this.hasQuery = false;
13663 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13664 this.loading.hide();
13667 if(this.tickable && this.editable){
13672 // only causes errors at present
13673 //Roo.log(this.store.reader.jsonData);
13674 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13676 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13682 onTypeAhead : function(){
13683 if(this.store.getCount() > 0){
13684 var r = this.store.getAt(0);
13685 var newValue = r.data[this.displayField];
13686 var len = newValue.length;
13687 var selStart = this.getRawValue().length;
13689 if(selStart != len){
13690 this.setRawValue(newValue);
13691 this.selectText(selStart, newValue.length);
13697 onSelect : function(record, index){
13699 if(this.fireEvent('beforeselect', this, record, index) !== false){
13701 this.setFromData(index > -1 ? record.data : false);
13704 this.fireEvent('select', this, record, index);
13709 * Returns the currently selected field value or empty string if no value is set.
13710 * @return {String} value The selected value
13712 getValue : function()
13714 if(Roo.isIOS && this.useNativeIOS){
13715 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13719 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13722 if(this.valueField){
13723 return typeof this.value != 'undefined' ? this.value : '';
13725 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13729 getRawValue : function()
13731 if(Roo.isIOS && this.useNativeIOS){
13732 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13735 var v = this.inputEl().getValue();
13741 * Clears any text/value currently set in the field
13743 clearValue : function(){
13745 if(this.hiddenField){
13746 this.hiddenField.dom.value = '';
13749 this.setRawValue('');
13750 this.lastSelectionText = '';
13751 this.lastData = false;
13753 var close = this.closeTriggerEl();
13764 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13765 * will be displayed in the field. If the value does not match the data value of an existing item,
13766 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13767 * Otherwise the field will be blank (although the value will still be set).
13768 * @param {String} value The value to match
13770 setValue : function(v)
13772 if(Roo.isIOS && this.useNativeIOS){
13773 this.setIOSValue(v);
13783 if(this.valueField){
13784 var r = this.findRecord(this.valueField, v);
13786 text = r.data[this.displayField];
13787 }else if(this.valueNotFoundText !== undefined){
13788 text = this.valueNotFoundText;
13791 this.lastSelectionText = text;
13792 if(this.hiddenField){
13793 this.hiddenField.dom.value = v;
13795 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13798 var close = this.closeTriggerEl();
13801 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13807 * @property {Object} the last set data for the element
13812 * Sets the value of the field based on a object which is related to the record format for the store.
13813 * @param {Object} value the value to set as. or false on reset?
13815 setFromData : function(o){
13822 var dv = ''; // display value
13823 var vv = ''; // value value..
13825 if (this.displayField) {
13826 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13828 // this is an error condition!!!
13829 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13832 if(this.valueField){
13833 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13836 var close = this.closeTriggerEl();
13839 if(dv.length || vv * 1 > 0){
13841 this.blockFocus=true;
13847 if(this.hiddenField){
13848 this.hiddenField.dom.value = vv;
13850 this.lastSelectionText = dv;
13851 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13855 // no hidden field.. - we store the value in 'value', but still display
13856 // display field!!!!
13857 this.lastSelectionText = dv;
13858 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13865 reset : function(){
13866 // overridden so that last data is reset..
13873 this.setValue(this.originalValue);
13874 //this.clearInvalid();
13875 this.lastData = false;
13877 this.view.clearSelections();
13883 findRecord : function(prop, value){
13885 if(this.store.getCount() > 0){
13886 this.store.each(function(r){
13887 if(r.data[prop] == value){
13897 getName: function()
13899 // returns hidden if it's set..
13900 if (!this.rendered) {return ''};
13901 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13905 onViewMove : function(e, t){
13906 this.inKeyMode = false;
13910 onViewOver : function(e, t){
13911 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13914 var item = this.view.findItemFromChild(t);
13917 var index = this.view.indexOf(item);
13918 this.select(index, false);
13923 onViewClick : function(view, doFocus, el, e)
13925 var index = this.view.getSelectedIndexes()[0];
13927 var r = this.store.getAt(index);
13931 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13938 Roo.each(this.tickItems, function(v,k){
13940 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13942 _this.tickItems.splice(k, 1);
13944 if(typeof(e) == 'undefined' && view == false){
13945 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13957 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13958 this.tickItems.push(r.data);
13961 if(typeof(e) == 'undefined' && view == false){
13962 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13969 this.onSelect(r, index);
13971 if(doFocus !== false && !this.blockFocus){
13972 this.inputEl().focus();
13977 restrictHeight : function(){
13978 //this.innerList.dom.style.height = '';
13979 //var inner = this.innerList.dom;
13980 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13981 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13982 //this.list.beginUpdate();
13983 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13984 this.list.alignTo(this.inputEl(), this.listAlign);
13985 this.list.alignTo(this.inputEl(), this.listAlign);
13986 //this.list.endUpdate();
13990 onEmptyResults : function(){
13992 if(this.tickable && this.editable){
13993 this.hasFocus = false;
13994 this.restrictHeight();
14002 * Returns true if the dropdown list is expanded, else false.
14004 isExpanded : function(){
14005 return this.list.isVisible();
14009 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14010 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14011 * @param {String} value The data value of the item to select
14012 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14013 * selected item if it is not currently in view (defaults to true)
14014 * @return {Boolean} True if the value matched an item in the list, else false
14016 selectByValue : function(v, scrollIntoView){
14017 if(v !== undefined && v !== null){
14018 var r = this.findRecord(this.valueField || this.displayField, v);
14020 this.select(this.store.indexOf(r), scrollIntoView);
14028 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14029 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14030 * @param {Number} index The zero-based index of the list item to select
14031 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14032 * selected item if it is not currently in view (defaults to true)
14034 select : function(index, scrollIntoView){
14035 this.selectedIndex = index;
14036 this.view.select(index);
14037 if(scrollIntoView !== false){
14038 var el = this.view.getNode(index);
14040 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14043 this.list.scrollChildIntoView(el, false);
14049 selectNext : function(){
14050 var ct = this.store.getCount();
14052 if(this.selectedIndex == -1){
14054 }else if(this.selectedIndex < ct-1){
14055 this.select(this.selectedIndex+1);
14061 selectPrev : function(){
14062 var ct = this.store.getCount();
14064 if(this.selectedIndex == -1){
14066 }else if(this.selectedIndex != 0){
14067 this.select(this.selectedIndex-1);
14073 onKeyUp : function(e){
14074 if(this.editable !== false && !e.isSpecialKey()){
14075 this.lastKey = e.getKey();
14076 this.dqTask.delay(this.queryDelay);
14081 validateBlur : function(){
14082 return !this.list || !this.list.isVisible();
14086 initQuery : function(){
14088 var v = this.getRawValue();
14090 if(this.tickable && this.editable){
14091 v = this.tickableInputEl().getValue();
14098 doForce : function(){
14099 if(this.inputEl().dom.value.length > 0){
14100 this.inputEl().dom.value =
14101 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14107 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14108 * query allowing the query action to be canceled if needed.
14109 * @param {String} query The SQL query to execute
14110 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14111 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14112 * saved in the current store (defaults to false)
14114 doQuery : function(q, forceAll){
14116 if(q === undefined || q === null){
14121 forceAll: forceAll,
14125 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14130 forceAll = qe.forceAll;
14131 if(forceAll === true || (q.length >= this.minChars)){
14133 this.hasQuery = true;
14135 if(this.lastQuery != q || this.alwaysQuery){
14136 this.lastQuery = q;
14137 if(this.mode == 'local'){
14138 this.selectedIndex = -1;
14140 this.store.clearFilter();
14143 if(this.specialFilter){
14144 this.fireEvent('specialfilter', this);
14149 this.store.filter(this.displayField, q);
14152 this.store.fireEvent("datachanged", this.store);
14159 this.store.baseParams[this.queryParam] = q;
14161 var options = {params : this.getParams(q)};
14164 options.add = true;
14165 options.params.start = this.page * this.pageSize;
14168 this.store.load(options);
14171 * this code will make the page width larger, at the beginning, the list not align correctly,
14172 * we should expand the list on onLoad
14173 * so command out it
14178 this.selectedIndex = -1;
14183 this.loadNext = false;
14187 getParams : function(q){
14189 //p[this.queryParam] = q;
14193 p.limit = this.pageSize;
14199 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14201 collapse : function(){
14202 if(!this.isExpanded()){
14208 this.hasFocus = false;
14212 this.cancelBtn.hide();
14213 this.trigger.show();
14216 this.tickableInputEl().dom.value = '';
14217 this.tickableInputEl().blur();
14222 Roo.get(document).un('mousedown', this.collapseIf, this);
14223 Roo.get(document).un('mousewheel', this.collapseIf, this);
14224 if (!this.editable) {
14225 Roo.get(document).un('keydown', this.listKeyPress, this);
14227 this.fireEvent('collapse', this);
14233 collapseIf : function(e){
14234 var in_combo = e.within(this.el);
14235 var in_list = e.within(this.list);
14236 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14238 if (in_combo || in_list || is_list) {
14239 //e.stopPropagation();
14244 this.onTickableFooterButtonClick(e, false, false);
14252 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14254 expand : function(){
14256 if(this.isExpanded() || !this.hasFocus){
14260 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14261 this.list.setWidth(lw);
14267 this.restrictHeight();
14271 this.tickItems = Roo.apply([], this.item);
14274 this.cancelBtn.show();
14275 this.trigger.hide();
14278 this.tickableInputEl().focus();
14283 Roo.get(document).on('mousedown', this.collapseIf, this);
14284 Roo.get(document).on('mousewheel', this.collapseIf, this);
14285 if (!this.editable) {
14286 Roo.get(document).on('keydown', this.listKeyPress, this);
14289 this.fireEvent('expand', this);
14293 // Implements the default empty TriggerField.onTriggerClick function
14294 onTriggerClick : function(e)
14296 Roo.log('trigger click');
14298 if(this.disabled || !this.triggerList){
14303 this.loadNext = false;
14305 if(this.isExpanded()){
14307 if (!this.blockFocus) {
14308 this.inputEl().focus();
14312 this.hasFocus = true;
14313 if(this.triggerAction == 'all') {
14314 this.doQuery(this.allQuery, true);
14316 this.doQuery(this.getRawValue());
14318 if (!this.blockFocus) {
14319 this.inputEl().focus();
14324 onTickableTriggerClick : function(e)
14331 this.loadNext = false;
14332 this.hasFocus = true;
14334 if(this.triggerAction == 'all') {
14335 this.doQuery(this.allQuery, true);
14337 this.doQuery(this.getRawValue());
14341 onSearchFieldClick : function(e)
14343 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14344 this.onTickableFooterButtonClick(e, false, false);
14348 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14353 this.loadNext = false;
14354 this.hasFocus = true;
14356 if(this.triggerAction == 'all') {
14357 this.doQuery(this.allQuery, true);
14359 this.doQuery(this.getRawValue());
14363 listKeyPress : function(e)
14365 //Roo.log('listkeypress');
14366 // scroll to first matching element based on key pres..
14367 if (e.isSpecialKey()) {
14370 var k = String.fromCharCode(e.getKey()).toUpperCase();
14373 var csel = this.view.getSelectedNodes();
14374 var cselitem = false;
14376 var ix = this.view.indexOf(csel[0]);
14377 cselitem = this.store.getAt(ix);
14378 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14384 this.store.each(function(v) {
14386 // start at existing selection.
14387 if (cselitem.id == v.id) {
14393 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14394 match = this.store.indexOf(v);
14400 if (match === false) {
14401 return true; // no more action?
14404 this.view.select(match);
14405 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14406 sn.scrollIntoView(sn.dom.parentNode, false);
14409 onViewScroll : function(e, t){
14411 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){
14415 this.hasQuery = true;
14417 this.loading = this.list.select('.loading', true).first();
14419 if(this.loading === null){
14420 this.list.createChild({
14422 cls: 'loading roo-select2-more-results roo-select2-active',
14423 html: 'Loading more results...'
14426 this.loading = this.list.select('.loading', true).first();
14428 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14430 this.loading.hide();
14433 this.loading.show();
14438 this.loadNext = true;
14440 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14445 addItem : function(o)
14447 var dv = ''; // display value
14449 if (this.displayField) {
14450 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14452 // this is an error condition!!!
14453 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14460 var choice = this.choices.createChild({
14462 cls: 'roo-select2-search-choice',
14471 cls: 'roo-select2-search-choice-close fa fa-times',
14476 }, this.searchField);
14478 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14480 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14488 this.inputEl().dom.value = '';
14493 onRemoveItem : function(e, _self, o)
14495 e.preventDefault();
14497 this.lastItem = Roo.apply([], this.item);
14499 var index = this.item.indexOf(o.data) * 1;
14502 Roo.log('not this item?!');
14506 this.item.splice(index, 1);
14511 this.fireEvent('remove', this, e);
14517 syncValue : function()
14519 if(!this.item.length){
14526 Roo.each(this.item, function(i){
14527 if(_this.valueField){
14528 value.push(i[_this.valueField]);
14535 this.value = value.join(',');
14537 if(this.hiddenField){
14538 this.hiddenField.dom.value = this.value;
14541 this.store.fireEvent("datachanged", this.store);
14546 clearItem : function()
14548 if(!this.multiple){
14554 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14562 if(this.tickable && !Roo.isTouch){
14563 this.view.refresh();
14567 inputEl: function ()
14569 if(Roo.isIOS && this.useNativeIOS){
14570 return this.el.select('select.roo-ios-select', true).first();
14573 if(Roo.isTouch && this.mobileTouchView){
14574 return this.el.select('input.form-control',true).first();
14578 return this.searchField;
14581 return this.el.select('input.form-control',true).first();
14584 onTickableFooterButtonClick : function(e, btn, el)
14586 e.preventDefault();
14588 this.lastItem = Roo.apply([], this.item);
14590 if(btn && btn.name == 'cancel'){
14591 this.tickItems = Roo.apply([], this.item);
14600 Roo.each(this.tickItems, function(o){
14608 validate : function()
14610 var v = this.getRawValue();
14613 v = this.getValue();
14616 if(this.disabled || this.allowBlank || v.length){
14621 this.markInvalid();
14625 tickableInputEl : function()
14627 if(!this.tickable || !this.editable){
14628 return this.inputEl();
14631 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14635 getAutoCreateTouchView : function()
14640 cls: 'form-group' //input-group
14646 type : this.inputType,
14647 cls : 'form-control x-combo-noedit',
14648 autocomplete: 'new-password',
14649 placeholder : this.placeholder || '',
14654 input.name = this.name;
14658 input.cls += ' input-' + this.size;
14661 if (this.disabled) {
14662 input.disabled = true;
14673 inputblock.cls += ' input-group';
14675 inputblock.cn.unshift({
14677 cls : 'input-group-addon',
14682 if(this.removable && !this.multiple){
14683 inputblock.cls += ' roo-removable';
14685 inputblock.cn.push({
14688 cls : 'roo-combo-removable-btn close'
14692 if(this.hasFeedback && !this.allowBlank){
14694 inputblock.cls += ' has-feedback';
14696 inputblock.cn.push({
14698 cls: 'glyphicon form-control-feedback'
14705 inputblock.cls += (this.before) ? '' : ' input-group';
14707 inputblock.cn.push({
14709 cls : 'input-group-addon',
14720 cls: 'form-hidden-field'
14734 cls: 'form-hidden-field'
14738 cls: 'roo-select2-choices',
14742 cls: 'roo-select2-search-field',
14755 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14761 if(!this.multiple && this.showToggleBtn){
14768 if (this.caret != false) {
14771 cls: 'fa fa-' + this.caret
14778 cls : 'input-group-addon btn dropdown-toggle',
14783 cls: 'combobox-clear',
14797 combobox.cls += ' roo-select2-container-multi';
14800 var align = this.labelAlign || this.parentLabelAlign();
14802 if (align ==='left' && this.fieldLabel.length) {
14807 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14808 tooltip : 'This field is required'
14812 cls : 'control-label',
14813 html : this.fieldLabel
14824 var labelCfg = cfg.cn[1];
14825 var contentCfg = cfg.cn[2];
14828 if(this.indicatorpos == 'right'){
14833 cls : 'control-label',
14837 html : this.fieldLabel
14841 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14842 tooltip : 'This field is required'
14855 labelCfg = cfg.cn[0];
14856 contentCfg = cfg.cn[1];
14861 if(this.labelWidth > 12){
14862 labelCfg.style = "width: " + this.labelWidth + 'px';
14865 if(this.labelWidth < 13 && this.labelmd == 0){
14866 this.labelmd = this.labelWidth;
14869 if(this.labellg > 0){
14870 labelCfg.cls += ' col-lg-' + this.labellg;
14871 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14874 if(this.labelmd > 0){
14875 labelCfg.cls += ' col-md-' + this.labelmd;
14876 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14879 if(this.labelsm > 0){
14880 labelCfg.cls += ' col-sm-' + this.labelsm;
14881 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14884 if(this.labelxs > 0){
14885 labelCfg.cls += ' col-xs-' + this.labelxs;
14886 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14890 } else if ( this.fieldLabel.length) {
14894 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14895 tooltip : 'This field is required'
14899 cls : 'control-label',
14900 html : this.fieldLabel
14911 if(this.indicatorpos == 'right'){
14915 cls : 'control-label',
14916 html : this.fieldLabel,
14920 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14921 tooltip : 'This field is required'
14938 var settings = this;
14940 ['xs','sm','md','lg'].map(function(size){
14941 if (settings[size]) {
14942 cfg.cls += ' col-' + size + '-' + settings[size];
14949 initTouchView : function()
14951 this.renderTouchView();
14953 this.touchViewEl.on('scroll', function(){
14954 this.el.dom.scrollTop = 0;
14957 this.originalValue = this.getValue();
14959 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14961 this.inputEl().on("click", this.showTouchView, this);
14962 if (this.triggerEl) {
14963 this.triggerEl.on("click", this.showTouchView, this);
14967 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14968 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14970 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14972 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14973 this.store.on('load', this.onTouchViewLoad, this);
14974 this.store.on('loadexception', this.onTouchViewLoadException, this);
14976 if(this.hiddenName){
14978 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14980 this.hiddenField.dom.value =
14981 this.hiddenValue !== undefined ? this.hiddenValue :
14982 this.value !== undefined ? this.value : '';
14984 this.el.dom.removeAttribute('name');
14985 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14989 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14990 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14993 if(this.removable && !this.multiple){
14994 var close = this.closeTriggerEl();
14996 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14997 close.on('click', this.removeBtnClick, this, close);
15001 * fix the bug in Safari iOS8
15003 this.inputEl().on("focus", function(e){
15004 document.activeElement.blur();
15012 renderTouchView : function()
15014 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15015 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15017 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15018 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15020 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15021 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15022 this.touchViewBodyEl.setStyle('overflow', 'auto');
15024 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15025 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15027 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15028 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15032 showTouchView : function()
15038 this.touchViewHeaderEl.hide();
15040 if(this.modalTitle.length){
15041 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15042 this.touchViewHeaderEl.show();
15045 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15046 this.touchViewEl.show();
15048 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15050 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15051 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15053 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15055 if(this.modalTitle.length){
15056 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15059 this.touchViewBodyEl.setHeight(bodyHeight);
15063 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15065 this.touchViewEl.addClass('in');
15068 this.doTouchViewQuery();
15072 hideTouchView : function()
15074 this.touchViewEl.removeClass('in');
15078 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15080 this.touchViewEl.setStyle('display', 'none');
15085 setTouchViewValue : function()
15092 Roo.each(this.tickItems, function(o){
15097 this.hideTouchView();
15100 doTouchViewQuery : function()
15109 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15113 if(!this.alwaysQuery || this.mode == 'local'){
15114 this.onTouchViewLoad();
15121 onTouchViewBeforeLoad : function(combo,opts)
15127 onTouchViewLoad : function()
15129 if(this.store.getCount() < 1){
15130 this.onTouchViewEmptyResults();
15134 this.clearTouchView();
15136 var rawValue = this.getRawValue();
15138 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15140 this.tickItems = [];
15142 this.store.data.each(function(d, rowIndex){
15143 var row = this.touchViewListGroup.createChild(template);
15145 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15146 row.addClass(d.data.cls);
15149 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15152 html : d.data[this.displayField]
15155 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15156 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15159 row.removeClass('selected');
15160 if(!this.multiple && this.valueField &&
15161 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15164 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15165 row.addClass('selected');
15168 if(this.multiple && this.valueField &&
15169 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15173 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15174 this.tickItems.push(d.data);
15177 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15181 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15183 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15185 if(this.modalTitle.length){
15186 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15189 var listHeight = this.touchViewListGroup.getHeight();
15193 if(firstChecked && listHeight > bodyHeight){
15194 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15199 onTouchViewLoadException : function()
15201 this.hideTouchView();
15204 onTouchViewEmptyResults : function()
15206 this.clearTouchView();
15208 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15210 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15214 clearTouchView : function()
15216 this.touchViewListGroup.dom.innerHTML = '';
15219 onTouchViewClick : function(e, el, o)
15221 e.preventDefault();
15224 var rowIndex = o.rowIndex;
15226 var r = this.store.getAt(rowIndex);
15228 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15230 if(!this.multiple){
15231 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15232 c.dom.removeAttribute('checked');
15235 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15237 this.setFromData(r.data);
15239 var close = this.closeTriggerEl();
15245 this.hideTouchView();
15247 this.fireEvent('select', this, r, rowIndex);
15252 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15253 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15254 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15258 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15259 this.addItem(r.data);
15260 this.tickItems.push(r.data);
15264 getAutoCreateNativeIOS : function()
15267 cls: 'form-group' //input-group,
15272 cls : 'roo-ios-select'
15276 combobox.name = this.name;
15279 if (this.disabled) {
15280 combobox.disabled = true;
15283 var settings = this;
15285 ['xs','sm','md','lg'].map(function(size){
15286 if (settings[size]) {
15287 cfg.cls += ' col-' + size + '-' + settings[size];
15297 initIOSView : function()
15299 this.store.on('load', this.onIOSViewLoad, this);
15304 onIOSViewLoad : function()
15306 if(this.store.getCount() < 1){
15310 this.clearIOSView();
15312 if(this.allowBlank) {
15314 var default_text = '-- SELECT --';
15316 if(this.placeholder.length){
15317 default_text = this.placeholder;
15320 if(this.emptyTitle.length){
15321 default_text += ' - ' + this.emptyTitle + ' -';
15324 var opt = this.inputEl().createChild({
15327 html : default_text
15331 o[this.valueField] = 0;
15332 o[this.displayField] = default_text;
15334 this.ios_options.push({
15341 this.store.data.each(function(d, rowIndex){
15345 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15346 html = d.data[this.displayField];
15351 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15352 value = d.data[this.valueField];
15361 if(this.value == d.data[this.valueField]){
15362 option['selected'] = true;
15365 var opt = this.inputEl().createChild(option);
15367 this.ios_options.push({
15374 this.inputEl().on('change', function(){
15375 this.fireEvent('select', this);
15380 clearIOSView: function()
15382 this.inputEl().dom.innerHTML = '';
15384 this.ios_options = [];
15387 setIOSValue: function(v)
15391 if(!this.ios_options){
15395 Roo.each(this.ios_options, function(opts){
15397 opts.el.dom.removeAttribute('selected');
15399 if(opts.data[this.valueField] != v){
15403 opts.el.dom.setAttribute('selected', true);
15409 * @cfg {Boolean} grow
15413 * @cfg {Number} growMin
15417 * @cfg {Number} growMax
15426 Roo.apply(Roo.bootstrap.ComboBox, {
15430 cls: 'modal-header',
15452 cls: 'list-group-item',
15456 cls: 'roo-combobox-list-group-item-value'
15460 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15474 listItemCheckbox : {
15476 cls: 'list-group-item',
15480 cls: 'roo-combobox-list-group-item-value'
15484 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15500 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15505 cls: 'modal-footer',
15513 cls: 'col-xs-6 text-left',
15516 cls: 'btn btn-danger roo-touch-view-cancel',
15522 cls: 'col-xs-6 text-right',
15525 cls: 'btn btn-success roo-touch-view-ok',
15536 Roo.apply(Roo.bootstrap.ComboBox, {
15538 touchViewTemplate : {
15540 cls: 'modal fade roo-combobox-touch-view',
15544 cls: 'modal-dialog',
15545 style : 'position:fixed', // we have to fix position....
15549 cls: 'modal-content',
15551 Roo.bootstrap.ComboBox.header,
15552 Roo.bootstrap.ComboBox.body,
15553 Roo.bootstrap.ComboBox.footer
15562 * Ext JS Library 1.1.1
15563 * Copyright(c) 2006-2007, Ext JS, LLC.
15565 * Originally Released Under LGPL - original licence link has changed is not relivant.
15568 * <script type="text/javascript">
15573 * @extends Roo.util.Observable
15574 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15575 * This class also supports single and multi selection modes. <br>
15576 * Create a data model bound view:
15578 var store = new Roo.data.Store(...);
15580 var view = new Roo.View({
15582 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15584 singleSelect: true,
15585 selectedClass: "ydataview-selected",
15589 // listen for node click?
15590 view.on("click", function(vw, index, node, e){
15591 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15595 dataModel.load("foobar.xml");
15597 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15599 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15600 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15602 * Note: old style constructor is still suported (container, template, config)
15605 * Create a new View
15606 * @param {Object} config The config object
15609 Roo.View = function(config, depreciated_tpl, depreciated_config){
15611 this.parent = false;
15613 if (typeof(depreciated_tpl) == 'undefined') {
15614 // new way.. - universal constructor.
15615 Roo.apply(this, config);
15616 this.el = Roo.get(this.el);
15619 this.el = Roo.get(config);
15620 this.tpl = depreciated_tpl;
15621 Roo.apply(this, depreciated_config);
15623 this.wrapEl = this.el.wrap().wrap();
15624 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15627 if(typeof(this.tpl) == "string"){
15628 this.tpl = new Roo.Template(this.tpl);
15630 // support xtype ctors..
15631 this.tpl = new Roo.factory(this.tpl, Roo);
15635 this.tpl.compile();
15640 * @event beforeclick
15641 * Fires before a click is processed. Returns false to cancel the default action.
15642 * @param {Roo.View} this
15643 * @param {Number} index The index of the target node
15644 * @param {HTMLElement} node The target node
15645 * @param {Roo.EventObject} e The raw event object
15647 "beforeclick" : true,
15650 * Fires when a template node is clicked.
15651 * @param {Roo.View} this
15652 * @param {Number} index The index of the target node
15653 * @param {HTMLElement} node The target node
15654 * @param {Roo.EventObject} e The raw event object
15659 * Fires when a template node is double clicked.
15660 * @param {Roo.View} this
15661 * @param {Number} index The index of the target node
15662 * @param {HTMLElement} node The target node
15663 * @param {Roo.EventObject} e The raw event object
15667 * @event contextmenu
15668 * Fires when a template node is right clicked.
15669 * @param {Roo.View} this
15670 * @param {Number} index The index of the target node
15671 * @param {HTMLElement} node The target node
15672 * @param {Roo.EventObject} e The raw event object
15674 "contextmenu" : true,
15676 * @event selectionchange
15677 * Fires when the selected nodes change.
15678 * @param {Roo.View} this
15679 * @param {Array} selections Array of the selected nodes
15681 "selectionchange" : true,
15684 * @event beforeselect
15685 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15686 * @param {Roo.View} this
15687 * @param {HTMLElement} node The node to be selected
15688 * @param {Array} selections Array of currently selected nodes
15690 "beforeselect" : true,
15692 * @event preparedata
15693 * Fires on every row to render, to allow you to change the data.
15694 * @param {Roo.View} this
15695 * @param {Object} data to be rendered (change this)
15697 "preparedata" : true
15705 "click": this.onClick,
15706 "dblclick": this.onDblClick,
15707 "contextmenu": this.onContextMenu,
15711 this.selections = [];
15713 this.cmp = new Roo.CompositeElementLite([]);
15715 this.store = Roo.factory(this.store, Roo.data);
15716 this.setStore(this.store, true);
15719 if ( this.footer && this.footer.xtype) {
15721 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15723 this.footer.dataSource = this.store;
15724 this.footer.container = fctr;
15725 this.footer = Roo.factory(this.footer, Roo);
15726 fctr.insertFirst(this.el);
15728 // this is a bit insane - as the paging toolbar seems to detach the el..
15729 // dom.parentNode.parentNode.parentNode
15730 // they get detached?
15734 Roo.View.superclass.constructor.call(this);
15739 Roo.extend(Roo.View, Roo.util.Observable, {
15742 * @cfg {Roo.data.Store} store Data store to load data from.
15747 * @cfg {String|Roo.Element} el The container element.
15752 * @cfg {String|Roo.Template} tpl The template used by this View
15756 * @cfg {String} dataName the named area of the template to use as the data area
15757 * Works with domtemplates roo-name="name"
15761 * @cfg {String} selectedClass The css class to add to selected nodes
15763 selectedClass : "x-view-selected",
15765 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15770 * @cfg {String} text to display on mask (default Loading)
15774 * @cfg {Boolean} multiSelect Allow multiple selection
15776 multiSelect : false,
15778 * @cfg {Boolean} singleSelect Allow single selection
15780 singleSelect: false,
15783 * @cfg {Boolean} toggleSelect - selecting
15785 toggleSelect : false,
15788 * @cfg {Boolean} tickable - selecting
15793 * Returns the element this view is bound to.
15794 * @return {Roo.Element}
15796 getEl : function(){
15797 return this.wrapEl;
15803 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15805 refresh : function(){
15806 //Roo.log('refresh');
15809 // if we are using something like 'domtemplate', then
15810 // the what gets used is:
15811 // t.applySubtemplate(NAME, data, wrapping data..)
15812 // the outer template then get' applied with
15813 // the store 'extra data'
15814 // and the body get's added to the
15815 // roo-name="data" node?
15816 // <span class='roo-tpl-{name}'></span> ?????
15820 this.clearSelections();
15821 this.el.update("");
15823 var records = this.store.getRange();
15824 if(records.length < 1) {
15826 // is this valid?? = should it render a template??
15828 this.el.update(this.emptyText);
15832 if (this.dataName) {
15833 this.el.update(t.apply(this.store.meta)); //????
15834 el = this.el.child('.roo-tpl-' + this.dataName);
15837 for(var i = 0, len = records.length; i < len; i++){
15838 var data = this.prepareData(records[i].data, i, records[i]);
15839 this.fireEvent("preparedata", this, data, i, records[i]);
15841 var d = Roo.apply({}, data);
15844 Roo.apply(d, {'roo-id' : Roo.id()});
15848 Roo.each(this.parent.item, function(item){
15849 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15852 Roo.apply(d, {'roo-data-checked' : 'checked'});
15856 html[html.length] = Roo.util.Format.trim(
15858 t.applySubtemplate(this.dataName, d, this.store.meta) :
15865 el.update(html.join(""));
15866 this.nodes = el.dom.childNodes;
15867 this.updateIndexes(0);
15872 * Function to override to reformat the data that is sent to
15873 * the template for each node.
15874 * DEPRICATED - use the preparedata event handler.
15875 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15876 * a JSON object for an UpdateManager bound view).
15878 prepareData : function(data, index, record)
15880 this.fireEvent("preparedata", this, data, index, record);
15884 onUpdate : function(ds, record){
15885 // Roo.log('on update');
15886 this.clearSelections();
15887 var index = this.store.indexOf(record);
15888 var n = this.nodes[index];
15889 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15890 n.parentNode.removeChild(n);
15891 this.updateIndexes(index, index);
15897 onAdd : function(ds, records, index)
15899 //Roo.log(['on Add', ds, records, index] );
15900 this.clearSelections();
15901 if(this.nodes.length == 0){
15905 var n = this.nodes[index];
15906 for(var i = 0, len = records.length; i < len; i++){
15907 var d = this.prepareData(records[i].data, i, records[i]);
15909 this.tpl.insertBefore(n, d);
15912 this.tpl.append(this.el, d);
15915 this.updateIndexes(index);
15918 onRemove : function(ds, record, index){
15919 // Roo.log('onRemove');
15920 this.clearSelections();
15921 var el = this.dataName ?
15922 this.el.child('.roo-tpl-' + this.dataName) :
15925 el.dom.removeChild(this.nodes[index]);
15926 this.updateIndexes(index);
15930 * Refresh an individual node.
15931 * @param {Number} index
15933 refreshNode : function(index){
15934 this.onUpdate(this.store, this.store.getAt(index));
15937 updateIndexes : function(startIndex, endIndex){
15938 var ns = this.nodes;
15939 startIndex = startIndex || 0;
15940 endIndex = endIndex || ns.length - 1;
15941 for(var i = startIndex; i <= endIndex; i++){
15942 ns[i].nodeIndex = i;
15947 * Changes the data store this view uses and refresh the view.
15948 * @param {Store} store
15950 setStore : function(store, initial){
15951 if(!initial && this.store){
15952 this.store.un("datachanged", this.refresh);
15953 this.store.un("add", this.onAdd);
15954 this.store.un("remove", this.onRemove);
15955 this.store.un("update", this.onUpdate);
15956 this.store.un("clear", this.refresh);
15957 this.store.un("beforeload", this.onBeforeLoad);
15958 this.store.un("load", this.onLoad);
15959 this.store.un("loadexception", this.onLoad);
15963 store.on("datachanged", this.refresh, this);
15964 store.on("add", this.onAdd, this);
15965 store.on("remove", this.onRemove, this);
15966 store.on("update", this.onUpdate, this);
15967 store.on("clear", this.refresh, this);
15968 store.on("beforeload", this.onBeforeLoad, this);
15969 store.on("load", this.onLoad, this);
15970 store.on("loadexception", this.onLoad, this);
15978 * onbeforeLoad - masks the loading area.
15981 onBeforeLoad : function(store,opts)
15983 //Roo.log('onBeforeLoad');
15985 this.el.update("");
15987 this.el.mask(this.mask ? this.mask : "Loading" );
15989 onLoad : function ()
15996 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15997 * @param {HTMLElement} node
15998 * @return {HTMLElement} The template node
16000 findItemFromChild : function(node){
16001 var el = this.dataName ?
16002 this.el.child('.roo-tpl-' + this.dataName,true) :
16005 if(!node || node.parentNode == el){
16008 var p = node.parentNode;
16009 while(p && p != el){
16010 if(p.parentNode == el){
16019 onClick : function(e){
16020 var item = this.findItemFromChild(e.getTarget());
16022 var index = this.indexOf(item);
16023 if(this.onItemClick(item, index, e) !== false){
16024 this.fireEvent("click", this, index, item, e);
16027 this.clearSelections();
16032 onContextMenu : function(e){
16033 var item = this.findItemFromChild(e.getTarget());
16035 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16040 onDblClick : function(e){
16041 var item = this.findItemFromChild(e.getTarget());
16043 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16047 onItemClick : function(item, index, e)
16049 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16052 if (this.toggleSelect) {
16053 var m = this.isSelected(item) ? 'unselect' : 'select';
16056 _t[m](item, true, false);
16059 if(this.multiSelect || this.singleSelect){
16060 if(this.multiSelect && e.shiftKey && this.lastSelection){
16061 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16063 this.select(item, this.multiSelect && e.ctrlKey);
16064 this.lastSelection = item;
16067 if(!this.tickable){
16068 e.preventDefault();
16076 * Get the number of selected nodes.
16079 getSelectionCount : function(){
16080 return this.selections.length;
16084 * Get the currently selected nodes.
16085 * @return {Array} An array of HTMLElements
16087 getSelectedNodes : function(){
16088 return this.selections;
16092 * Get the indexes of the selected nodes.
16095 getSelectedIndexes : function(){
16096 var indexes = [], s = this.selections;
16097 for(var i = 0, len = s.length; i < len; i++){
16098 indexes.push(s[i].nodeIndex);
16104 * Clear all selections
16105 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16107 clearSelections : function(suppressEvent){
16108 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16109 this.cmp.elements = this.selections;
16110 this.cmp.removeClass(this.selectedClass);
16111 this.selections = [];
16112 if(!suppressEvent){
16113 this.fireEvent("selectionchange", this, this.selections);
16119 * Returns true if the passed node is selected
16120 * @param {HTMLElement/Number} node The node or node index
16121 * @return {Boolean}
16123 isSelected : function(node){
16124 var s = this.selections;
16128 node = this.getNode(node);
16129 return s.indexOf(node) !== -1;
16134 * @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
16135 * @param {Boolean} keepExisting (optional) true to keep existing selections
16136 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16138 select : function(nodeInfo, keepExisting, suppressEvent){
16139 if(nodeInfo instanceof Array){
16141 this.clearSelections(true);
16143 for(var i = 0, len = nodeInfo.length; i < len; i++){
16144 this.select(nodeInfo[i], true, true);
16148 var node = this.getNode(nodeInfo);
16149 if(!node || this.isSelected(node)){
16150 return; // already selected.
16153 this.clearSelections(true);
16156 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16157 Roo.fly(node).addClass(this.selectedClass);
16158 this.selections.push(node);
16159 if(!suppressEvent){
16160 this.fireEvent("selectionchange", this, this.selections);
16168 * @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
16169 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16170 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16172 unselect : function(nodeInfo, keepExisting, suppressEvent)
16174 if(nodeInfo instanceof Array){
16175 Roo.each(this.selections, function(s) {
16176 this.unselect(s, nodeInfo);
16180 var node = this.getNode(nodeInfo);
16181 if(!node || !this.isSelected(node)){
16182 //Roo.log("not selected");
16183 return; // not selected.
16187 Roo.each(this.selections, function(s) {
16189 Roo.fly(node).removeClass(this.selectedClass);
16196 this.selections= ns;
16197 this.fireEvent("selectionchange", this, this.selections);
16201 * Gets a template node.
16202 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16203 * @return {HTMLElement} The node or null if it wasn't found
16205 getNode : function(nodeInfo){
16206 if(typeof nodeInfo == "string"){
16207 return document.getElementById(nodeInfo);
16208 }else if(typeof nodeInfo == "number"){
16209 return this.nodes[nodeInfo];
16215 * Gets a range template nodes.
16216 * @param {Number} startIndex
16217 * @param {Number} endIndex
16218 * @return {Array} An array of nodes
16220 getNodes : function(start, end){
16221 var ns = this.nodes;
16222 start = start || 0;
16223 end = typeof end == "undefined" ? ns.length - 1 : end;
16226 for(var i = start; i <= end; i++){
16230 for(var i = start; i >= end; i--){
16238 * Finds the index of the passed node
16239 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16240 * @return {Number} The index of the node or -1
16242 indexOf : function(node){
16243 node = this.getNode(node);
16244 if(typeof node.nodeIndex == "number"){
16245 return node.nodeIndex;
16247 var ns = this.nodes;
16248 for(var i = 0, len = ns.length; i < len; i++){
16259 * based on jquery fullcalendar
16263 Roo.bootstrap = Roo.bootstrap || {};
16265 * @class Roo.bootstrap.Calendar
16266 * @extends Roo.bootstrap.Component
16267 * Bootstrap Calendar class
16268 * @cfg {Boolean} loadMask (true|false) default false
16269 * @cfg {Object} header generate the user specific header of the calendar, default false
16272 * Create a new Container
16273 * @param {Object} config The config object
16278 Roo.bootstrap.Calendar = function(config){
16279 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16283 * Fires when a date is selected
16284 * @param {DatePicker} this
16285 * @param {Date} date The selected date
16289 * @event monthchange
16290 * Fires when the displayed month changes
16291 * @param {DatePicker} this
16292 * @param {Date} date The selected month
16294 'monthchange': true,
16296 * @event evententer
16297 * Fires when mouse over an event
16298 * @param {Calendar} this
16299 * @param {event} Event
16301 'evententer': true,
16303 * @event eventleave
16304 * Fires when the mouse leaves an
16305 * @param {Calendar} this
16308 'eventleave': true,
16310 * @event eventclick
16311 * Fires when the mouse click an
16312 * @param {Calendar} this
16321 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16324 * @cfg {Number} startDay
16325 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16333 getAutoCreate : function(){
16336 var fc_button = function(name, corner, style, content ) {
16337 return Roo.apply({},{
16339 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16341 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16344 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16355 style : 'width:100%',
16362 cls : 'fc-header-left',
16364 fc_button('prev', 'left', 'arrow', '‹' ),
16365 fc_button('next', 'right', 'arrow', '›' ),
16366 { tag: 'span', cls: 'fc-header-space' },
16367 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16375 cls : 'fc-header-center',
16379 cls: 'fc-header-title',
16382 html : 'month / year'
16390 cls : 'fc-header-right',
16392 /* fc_button('month', 'left', '', 'month' ),
16393 fc_button('week', '', '', 'week' ),
16394 fc_button('day', 'right', '', 'day' )
16406 header = this.header;
16409 var cal_heads = function() {
16411 // fixme - handle this.
16413 for (var i =0; i < Date.dayNames.length; i++) {
16414 var d = Date.dayNames[i];
16417 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16418 html : d.substring(0,3)
16422 ret[0].cls += ' fc-first';
16423 ret[6].cls += ' fc-last';
16426 var cal_cell = function(n) {
16429 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16434 cls: 'fc-day-number',
16438 cls: 'fc-day-content',
16442 style: 'position: relative;' // height: 17px;
16454 var cal_rows = function() {
16457 for (var r = 0; r < 6; r++) {
16464 for (var i =0; i < Date.dayNames.length; i++) {
16465 var d = Date.dayNames[i];
16466 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16469 row.cn[0].cls+=' fc-first';
16470 row.cn[0].cn[0].style = 'min-height:90px';
16471 row.cn[6].cls+=' fc-last';
16475 ret[0].cls += ' fc-first';
16476 ret[4].cls += ' fc-prev-last';
16477 ret[5].cls += ' fc-last';
16484 cls: 'fc-border-separate',
16485 style : 'width:100%',
16493 cls : 'fc-first fc-last',
16511 cls : 'fc-content',
16512 style : "position: relative;",
16515 cls : 'fc-view fc-view-month fc-grid',
16516 style : 'position: relative',
16517 unselectable : 'on',
16520 cls : 'fc-event-container',
16521 style : 'position:absolute;z-index:8;top:0;left:0;'
16539 initEvents : function()
16542 throw "can not find store for calendar";
16548 style: "text-align:center",
16552 style: "background-color:white;width:50%;margin:250 auto",
16556 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16567 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16569 var size = this.el.select('.fc-content', true).first().getSize();
16570 this.maskEl.setSize(size.width, size.height);
16571 this.maskEl.enableDisplayMode("block");
16572 if(!this.loadMask){
16573 this.maskEl.hide();
16576 this.store = Roo.factory(this.store, Roo.data);
16577 this.store.on('load', this.onLoad, this);
16578 this.store.on('beforeload', this.onBeforeLoad, this);
16582 this.cells = this.el.select('.fc-day',true);
16583 //Roo.log(this.cells);
16584 this.textNodes = this.el.query('.fc-day-number');
16585 this.cells.addClassOnOver('fc-state-hover');
16587 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16588 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16589 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16590 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16592 this.on('monthchange', this.onMonthChange, this);
16594 this.update(new Date().clearTime());
16597 resize : function() {
16598 var sz = this.el.getSize();
16600 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16601 this.el.select('.fc-day-content div',true).setHeight(34);
16606 showPrevMonth : function(e){
16607 this.update(this.activeDate.add("mo", -1));
16609 showToday : function(e){
16610 this.update(new Date().clearTime());
16613 showNextMonth : function(e){
16614 this.update(this.activeDate.add("mo", 1));
16618 showPrevYear : function(){
16619 this.update(this.activeDate.add("y", -1));
16623 showNextYear : function(){
16624 this.update(this.activeDate.add("y", 1));
16629 update : function(date)
16631 var vd = this.activeDate;
16632 this.activeDate = date;
16633 // if(vd && this.el){
16634 // var t = date.getTime();
16635 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16636 // Roo.log('using add remove');
16638 // this.fireEvent('monthchange', this, date);
16640 // this.cells.removeClass("fc-state-highlight");
16641 // this.cells.each(function(c){
16642 // if(c.dateValue == t){
16643 // c.addClass("fc-state-highlight");
16644 // setTimeout(function(){
16645 // try{c.dom.firstChild.focus();}catch(e){}
16655 var days = date.getDaysInMonth();
16657 var firstOfMonth = date.getFirstDateOfMonth();
16658 var startingPos = firstOfMonth.getDay()-this.startDay;
16660 if(startingPos < this.startDay){
16664 var pm = date.add(Date.MONTH, -1);
16665 var prevStart = pm.getDaysInMonth()-startingPos;
16667 this.cells = this.el.select('.fc-day',true);
16668 this.textNodes = this.el.query('.fc-day-number');
16669 this.cells.addClassOnOver('fc-state-hover');
16671 var cells = this.cells.elements;
16672 var textEls = this.textNodes;
16674 Roo.each(cells, function(cell){
16675 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16678 days += startingPos;
16680 // convert everything to numbers so it's fast
16681 var day = 86400000;
16682 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16685 //Roo.log(prevStart);
16687 var today = new Date().clearTime().getTime();
16688 var sel = date.clearTime().getTime();
16689 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16690 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16691 var ddMatch = this.disabledDatesRE;
16692 var ddText = this.disabledDatesText;
16693 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16694 var ddaysText = this.disabledDaysText;
16695 var format = this.format;
16697 var setCellClass = function(cal, cell){
16701 //Roo.log('set Cell Class');
16703 var t = d.getTime();
16707 cell.dateValue = t;
16709 cell.className += " fc-today";
16710 cell.className += " fc-state-highlight";
16711 cell.title = cal.todayText;
16714 // disable highlight in other month..
16715 //cell.className += " fc-state-highlight";
16720 cell.className = " fc-state-disabled";
16721 cell.title = cal.minText;
16725 cell.className = " fc-state-disabled";
16726 cell.title = cal.maxText;
16730 if(ddays.indexOf(d.getDay()) != -1){
16731 cell.title = ddaysText;
16732 cell.className = " fc-state-disabled";
16735 if(ddMatch && format){
16736 var fvalue = d.dateFormat(format);
16737 if(ddMatch.test(fvalue)){
16738 cell.title = ddText.replace("%0", fvalue);
16739 cell.className = " fc-state-disabled";
16743 if (!cell.initialClassName) {
16744 cell.initialClassName = cell.dom.className;
16747 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16752 for(; i < startingPos; i++) {
16753 textEls[i].innerHTML = (++prevStart);
16754 d.setDate(d.getDate()+1);
16756 cells[i].className = "fc-past fc-other-month";
16757 setCellClass(this, cells[i]);
16762 for(; i < days; i++){
16763 intDay = i - startingPos + 1;
16764 textEls[i].innerHTML = (intDay);
16765 d.setDate(d.getDate()+1);
16767 cells[i].className = ''; // "x-date-active";
16768 setCellClass(this, cells[i]);
16772 for(; i < 42; i++) {
16773 textEls[i].innerHTML = (++extraDays);
16774 d.setDate(d.getDate()+1);
16776 cells[i].className = "fc-future fc-other-month";
16777 setCellClass(this, cells[i]);
16780 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16782 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16784 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16785 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16787 if(totalRows != 6){
16788 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16789 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16792 this.fireEvent('monthchange', this, date);
16796 if(!this.internalRender){
16797 var main = this.el.dom.firstChild;
16798 var w = main.offsetWidth;
16799 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16800 Roo.fly(main).setWidth(w);
16801 this.internalRender = true;
16802 // opera does not respect the auto grow header center column
16803 // then, after it gets a width opera refuses to recalculate
16804 // without a second pass
16805 if(Roo.isOpera && !this.secondPass){
16806 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16807 this.secondPass = true;
16808 this.update.defer(10, this, [date]);
16815 findCell : function(dt) {
16816 dt = dt.clearTime().getTime();
16818 this.cells.each(function(c){
16819 //Roo.log("check " +c.dateValue + '?=' + dt);
16820 if(c.dateValue == dt){
16830 findCells : function(ev) {
16831 var s = ev.start.clone().clearTime().getTime();
16833 var e= ev.end.clone().clearTime().getTime();
16836 this.cells.each(function(c){
16837 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16839 if(c.dateValue > e){
16842 if(c.dateValue < s){
16851 // findBestRow: function(cells)
16855 // for (var i =0 ; i < cells.length;i++) {
16856 // ret = Math.max(cells[i].rows || 0,ret);
16863 addItem : function(ev)
16865 // look for vertical location slot in
16866 var cells = this.findCells(ev);
16868 // ev.row = this.findBestRow(cells);
16870 // work out the location.
16874 for(var i =0; i < cells.length; i++) {
16876 cells[i].row = cells[0].row;
16879 cells[i].row = cells[i].row + 1;
16889 if (crow.start.getY() == cells[i].getY()) {
16891 crow.end = cells[i];
16908 cells[0].events.push(ev);
16910 this.calevents.push(ev);
16913 clearEvents: function() {
16915 if(!this.calevents){
16919 Roo.each(this.cells.elements, function(c){
16925 Roo.each(this.calevents, function(e) {
16926 Roo.each(e.els, function(el) {
16927 el.un('mouseenter' ,this.onEventEnter, this);
16928 el.un('mouseleave' ,this.onEventLeave, this);
16933 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16939 renderEvents: function()
16943 this.cells.each(function(c) {
16952 if(c.row != c.events.length){
16953 r = 4 - (4 - (c.row - c.events.length));
16956 c.events = ev.slice(0, r);
16957 c.more = ev.slice(r);
16959 if(c.more.length && c.more.length == 1){
16960 c.events.push(c.more.pop());
16963 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16967 this.cells.each(function(c) {
16969 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16972 for (var e = 0; e < c.events.length; e++){
16973 var ev = c.events[e];
16974 var rows = ev.rows;
16976 for(var i = 0; i < rows.length; i++) {
16978 // how many rows should it span..
16981 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16982 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16984 unselectable : "on",
16987 cls: 'fc-event-inner',
16991 // cls: 'fc-event-time',
16992 // html : cells.length > 1 ? '' : ev.time
16996 cls: 'fc-event-title',
16997 html : String.format('{0}', ev.title)
17004 cls: 'ui-resizable-handle ui-resizable-e',
17005 html : '  '
17012 cfg.cls += ' fc-event-start';
17014 if ((i+1) == rows.length) {
17015 cfg.cls += ' fc-event-end';
17018 var ctr = _this.el.select('.fc-event-container',true).first();
17019 var cg = ctr.createChild(cfg);
17021 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17022 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17024 var r = (c.more.length) ? 1 : 0;
17025 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17026 cg.setWidth(ebox.right - sbox.x -2);
17028 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17029 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17030 cg.on('click', _this.onEventClick, _this, ev);
17041 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17042 style : 'position: absolute',
17043 unselectable : "on",
17046 cls: 'fc-event-inner',
17050 cls: 'fc-event-title',
17058 cls: 'ui-resizable-handle ui-resizable-e',
17059 html : '  '
17065 var ctr = _this.el.select('.fc-event-container',true).first();
17066 var cg = ctr.createChild(cfg);
17068 var sbox = c.select('.fc-day-content',true).first().getBox();
17069 var ebox = c.select('.fc-day-content',true).first().getBox();
17071 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17072 cg.setWidth(ebox.right - sbox.x -2);
17074 cg.on('click', _this.onMoreEventClick, _this, c.more);
17084 onEventEnter: function (e, el,event,d) {
17085 this.fireEvent('evententer', this, el, event);
17088 onEventLeave: function (e, el,event,d) {
17089 this.fireEvent('eventleave', this, el, event);
17092 onEventClick: function (e, el,event,d) {
17093 this.fireEvent('eventclick', this, el, event);
17096 onMonthChange: function () {
17100 onMoreEventClick: function(e, el, more)
17104 this.calpopover.placement = 'right';
17105 this.calpopover.setTitle('More');
17107 this.calpopover.setContent('');
17109 var ctr = this.calpopover.el.select('.popover-content', true).first();
17111 Roo.each(more, function(m){
17113 cls : 'fc-event-hori fc-event-draggable',
17116 var cg = ctr.createChild(cfg);
17118 cg.on('click', _this.onEventClick, _this, m);
17121 this.calpopover.show(el);
17126 onLoad: function ()
17128 this.calevents = [];
17131 if(this.store.getCount() > 0){
17132 this.store.data.each(function(d){
17135 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17136 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17137 time : d.data.start_time,
17138 title : d.data.title,
17139 description : d.data.description,
17140 venue : d.data.venue
17145 this.renderEvents();
17147 if(this.calevents.length && this.loadMask){
17148 this.maskEl.hide();
17152 onBeforeLoad: function()
17154 this.clearEvents();
17156 this.maskEl.show();
17170 * @class Roo.bootstrap.Popover
17171 * @extends Roo.bootstrap.Component
17172 * Bootstrap Popover class
17173 * @cfg {String} html contents of the popover (or false to use children..)
17174 * @cfg {String} title of popover (or false to hide)
17175 * @cfg {String} placement how it is placed
17176 * @cfg {String} trigger click || hover (or false to trigger manually)
17177 * @cfg {String} over what (parent or false to trigger manually.)
17178 * @cfg {Number} delay - delay before showing
17181 * Create a new Popover
17182 * @param {Object} config The config object
17185 Roo.bootstrap.Popover = function(config){
17186 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17192 * After the popover show
17194 * @param {Roo.bootstrap.Popover} this
17199 * After the popover hide
17201 * @param {Roo.bootstrap.Popover} this
17207 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17209 title: 'Fill in a title',
17212 placement : 'right',
17213 trigger : 'hover', // hover
17219 can_build_overlaid : false,
17221 getChildContainer : function()
17223 return this.el.select('.popover-content',true).first();
17226 getAutoCreate : function(){
17229 cls : 'popover roo-dynamic',
17230 style: 'display:block',
17236 cls : 'popover-inner',
17240 cls: 'popover-title',
17244 cls : 'popover-content',
17255 setTitle: function(str)
17258 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17260 setContent: function(str)
17263 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17265 // as it get's added to the bottom of the page.
17266 onRender : function(ct, position)
17268 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17270 var cfg = Roo.apply({}, this.getAutoCreate());
17274 cfg.cls += ' ' + this.cls;
17277 cfg.style = this.style;
17279 //Roo.log("adding to ");
17280 this.el = Roo.get(document.body).createChild(cfg, position);
17281 // Roo.log(this.el);
17286 initEvents : function()
17288 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17289 this.el.enableDisplayMode('block');
17291 if (this.over === false) {
17294 if (this.triggers === false) {
17297 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17298 var triggers = this.trigger ? this.trigger.split(' ') : [];
17299 Roo.each(triggers, function(trigger) {
17301 if (trigger == 'click') {
17302 on_el.on('click', this.toggle, this);
17303 } else if (trigger != 'manual') {
17304 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17305 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17307 on_el.on(eventIn ,this.enter, this);
17308 on_el.on(eventOut, this.leave, this);
17319 toggle : function () {
17320 this.hoverState == 'in' ? this.leave() : this.enter();
17323 enter : function () {
17325 clearTimeout(this.timeout);
17327 this.hoverState = 'in';
17329 if (!this.delay || !this.delay.show) {
17334 this.timeout = setTimeout(function () {
17335 if (_t.hoverState == 'in') {
17338 }, this.delay.show)
17341 leave : function() {
17342 clearTimeout(this.timeout);
17344 this.hoverState = 'out';
17346 if (!this.delay || !this.delay.hide) {
17351 this.timeout = setTimeout(function () {
17352 if (_t.hoverState == 'out') {
17355 }, this.delay.hide)
17358 show : function (on_el)
17361 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17365 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17366 if (this.html !== false) {
17367 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17369 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17370 if (!this.title.length) {
17371 this.el.select('.popover-title',true).hide();
17374 var placement = typeof this.placement == 'function' ?
17375 this.placement.call(this, this.el, on_el) :
17378 var autoToken = /\s?auto?\s?/i;
17379 var autoPlace = autoToken.test(placement);
17381 placement = placement.replace(autoToken, '') || 'top';
17385 //this.el.setXY([0,0]);
17387 this.el.dom.style.display='block';
17388 this.el.addClass(placement);
17390 //this.el.appendTo(on_el);
17392 var p = this.getPosition();
17393 var box = this.el.getBox();
17398 var align = Roo.bootstrap.Popover.alignment[placement];
17401 this.el.alignTo(on_el, align[0],align[1]);
17402 //var arrow = this.el.select('.arrow',true).first();
17403 //arrow.set(align[2],
17405 this.el.addClass('in');
17408 if (this.el.hasClass('fade')) {
17412 this.hoverState = 'in';
17414 this.fireEvent('show', this);
17419 this.el.setXY([0,0]);
17420 this.el.removeClass('in');
17422 this.hoverState = null;
17424 this.fireEvent('hide', this);
17429 Roo.bootstrap.Popover.alignment = {
17430 'left' : ['r-l', [-10,0], 'right'],
17431 'right' : ['l-r', [10,0], 'left'],
17432 'bottom' : ['t-b', [0,10], 'top'],
17433 'top' : [ 'b-t', [0,-10], 'bottom']
17444 * @class Roo.bootstrap.Progress
17445 * @extends Roo.bootstrap.Component
17446 * Bootstrap Progress class
17447 * @cfg {Boolean} striped striped of the progress bar
17448 * @cfg {Boolean} active animated of the progress bar
17452 * Create a new Progress
17453 * @param {Object} config The config object
17456 Roo.bootstrap.Progress = function(config){
17457 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17460 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17465 getAutoCreate : function(){
17473 cfg.cls += ' progress-striped';
17477 cfg.cls += ' active';
17496 * @class Roo.bootstrap.ProgressBar
17497 * @extends Roo.bootstrap.Component
17498 * Bootstrap ProgressBar class
17499 * @cfg {Number} aria_valuenow aria-value now
17500 * @cfg {Number} aria_valuemin aria-value min
17501 * @cfg {Number} aria_valuemax aria-value max
17502 * @cfg {String} label label for the progress bar
17503 * @cfg {String} panel (success | info | warning | danger )
17504 * @cfg {String} role role of the progress bar
17505 * @cfg {String} sr_only text
17509 * Create a new ProgressBar
17510 * @param {Object} config The config object
17513 Roo.bootstrap.ProgressBar = function(config){
17514 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17517 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17521 aria_valuemax : 100,
17527 getAutoCreate : function()
17532 cls: 'progress-bar',
17533 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17545 cfg.role = this.role;
17548 if(this.aria_valuenow){
17549 cfg['aria-valuenow'] = this.aria_valuenow;
17552 if(this.aria_valuemin){
17553 cfg['aria-valuemin'] = this.aria_valuemin;
17556 if(this.aria_valuemax){
17557 cfg['aria-valuemax'] = this.aria_valuemax;
17560 if(this.label && !this.sr_only){
17561 cfg.html = this.label;
17565 cfg.cls += ' progress-bar-' + this.panel;
17571 update : function(aria_valuenow)
17573 this.aria_valuenow = aria_valuenow;
17575 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17590 * @class Roo.bootstrap.TabGroup
17591 * @extends Roo.bootstrap.Column
17592 * Bootstrap Column class
17593 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17594 * @cfg {Boolean} carousel true to make the group behave like a carousel
17595 * @cfg {Boolean} bullets show bullets for the panels
17596 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17597 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17598 * @cfg {Boolean} showarrow (true|false) show arrow default true
17601 * Create a new TabGroup
17602 * @param {Object} config The config object
17605 Roo.bootstrap.TabGroup = function(config){
17606 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17608 this.navId = Roo.id();
17611 Roo.bootstrap.TabGroup.register(this);
17615 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17618 transition : false,
17623 slideOnTouch : false,
17626 getAutoCreate : function()
17628 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17630 cfg.cls += ' tab-content';
17632 if (this.carousel) {
17633 cfg.cls += ' carousel slide';
17636 cls : 'carousel-inner',
17640 if(this.bullets && !Roo.isTouch){
17643 cls : 'carousel-bullets',
17647 if(this.bullets_cls){
17648 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17655 cfg.cn[0].cn.push(bullets);
17658 if(this.showarrow){
17659 cfg.cn[0].cn.push({
17661 class : 'carousel-arrow',
17665 class : 'carousel-prev',
17669 class : 'fa fa-chevron-left'
17675 class : 'carousel-next',
17679 class : 'fa fa-chevron-right'
17692 initEvents: function()
17694 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17695 // this.el.on("touchstart", this.onTouchStart, this);
17698 if(this.autoslide){
17701 this.slideFn = window.setInterval(function() {
17702 _this.showPanelNext();
17706 if(this.showarrow){
17707 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17708 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17714 // onTouchStart : function(e, el, o)
17716 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17720 // this.showPanelNext();
17724 getChildContainer : function()
17726 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17730 * register a Navigation item
17731 * @param {Roo.bootstrap.NavItem} the navitem to add
17733 register : function(item)
17735 this.tabs.push( item);
17736 item.navId = this.navId; // not really needed..
17741 getActivePanel : function()
17744 Roo.each(this.tabs, function(t) {
17754 getPanelByName : function(n)
17757 Roo.each(this.tabs, function(t) {
17758 if (t.tabId == n) {
17766 indexOfPanel : function(p)
17769 Roo.each(this.tabs, function(t,i) {
17770 if (t.tabId == p.tabId) {
17779 * show a specific panel
17780 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17781 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17783 showPanel : function (pan)
17785 if(this.transition || typeof(pan) == 'undefined'){
17786 Roo.log("waiting for the transitionend");
17790 if (typeof(pan) == 'number') {
17791 pan = this.tabs[pan];
17794 if (typeof(pan) == 'string') {
17795 pan = this.getPanelByName(pan);
17798 var cur = this.getActivePanel();
17801 Roo.log('pan or acitve pan is undefined');
17805 if (pan.tabId == this.getActivePanel().tabId) {
17809 if (false === cur.fireEvent('beforedeactivate')) {
17813 if(this.bullets > 0 && !Roo.isTouch){
17814 this.setActiveBullet(this.indexOfPanel(pan));
17817 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17819 this.transition = true;
17820 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17821 var lr = dir == 'next' ? 'left' : 'right';
17822 pan.el.addClass(dir); // or prev
17823 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17824 cur.el.addClass(lr); // or right
17825 pan.el.addClass(lr);
17828 cur.el.on('transitionend', function() {
17829 Roo.log("trans end?");
17831 pan.el.removeClass([lr,dir]);
17832 pan.setActive(true);
17834 cur.el.removeClass([lr]);
17835 cur.setActive(false);
17837 _this.transition = false;
17839 }, this, { single: true } );
17844 cur.setActive(false);
17845 pan.setActive(true);
17850 showPanelNext : function()
17852 var i = this.indexOfPanel(this.getActivePanel());
17854 if (i >= this.tabs.length - 1 && !this.autoslide) {
17858 if (i >= this.tabs.length - 1 && this.autoslide) {
17862 this.showPanel(this.tabs[i+1]);
17865 showPanelPrev : function()
17867 var i = this.indexOfPanel(this.getActivePanel());
17869 if (i < 1 && !this.autoslide) {
17873 if (i < 1 && this.autoslide) {
17874 i = this.tabs.length;
17877 this.showPanel(this.tabs[i-1]);
17881 addBullet: function()
17883 if(!this.bullets || Roo.isTouch){
17886 var ctr = this.el.select('.carousel-bullets',true).first();
17887 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17888 var bullet = ctr.createChild({
17889 cls : 'bullet bullet-' + i
17890 },ctr.dom.lastChild);
17895 bullet.on('click', (function(e, el, o, ii, t){
17897 e.preventDefault();
17899 this.showPanel(ii);
17901 if(this.autoslide && this.slideFn){
17902 clearInterval(this.slideFn);
17903 this.slideFn = window.setInterval(function() {
17904 _this.showPanelNext();
17908 }).createDelegate(this, [i, bullet], true));
17913 setActiveBullet : function(i)
17919 Roo.each(this.el.select('.bullet', true).elements, function(el){
17920 el.removeClass('selected');
17923 var bullet = this.el.select('.bullet-' + i, true).first();
17929 bullet.addClass('selected');
17940 Roo.apply(Roo.bootstrap.TabGroup, {
17944 * register a Navigation Group
17945 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17947 register : function(navgrp)
17949 this.groups[navgrp.navId] = navgrp;
17953 * fetch a Navigation Group based on the navigation ID
17954 * if one does not exist , it will get created.
17955 * @param {string} the navgroup to add
17956 * @returns {Roo.bootstrap.NavGroup} the navgroup
17958 get: function(navId) {
17959 if (typeof(this.groups[navId]) == 'undefined') {
17960 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17962 return this.groups[navId] ;
17977 * @class Roo.bootstrap.TabPanel
17978 * @extends Roo.bootstrap.Component
17979 * Bootstrap TabPanel class
17980 * @cfg {Boolean} active panel active
17981 * @cfg {String} html panel content
17982 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17983 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17984 * @cfg {String} href click to link..
17988 * Create a new TabPanel
17989 * @param {Object} config The config object
17992 Roo.bootstrap.TabPanel = function(config){
17993 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17997 * Fires when the active status changes
17998 * @param {Roo.bootstrap.TabPanel} this
17999 * @param {Boolean} state the new state
18004 * @event beforedeactivate
18005 * Fires before a tab is de-activated - can be used to do validation on a form.
18006 * @param {Roo.bootstrap.TabPanel} this
18007 * @return {Boolean} false if there is an error
18010 'beforedeactivate': true
18013 this.tabId = this.tabId || Roo.id();
18017 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18025 getAutoCreate : function(){
18028 // item is needed for carousel - not sure if it has any effect otherwise
18029 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18030 html: this.html || ''
18034 cfg.cls += ' active';
18038 cfg.tabId = this.tabId;
18045 initEvents: function()
18047 var p = this.parent();
18049 this.navId = this.navId || p.navId;
18051 if (typeof(this.navId) != 'undefined') {
18052 // not really needed.. but just in case.. parent should be a NavGroup.
18053 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18057 var i = tg.tabs.length - 1;
18059 if(this.active && tg.bullets > 0 && i < tg.bullets){
18060 tg.setActiveBullet(i);
18064 this.el.on('click', this.onClick, this);
18067 this.el.on("touchstart", this.onTouchStart, this);
18068 this.el.on("touchmove", this.onTouchMove, this);
18069 this.el.on("touchend", this.onTouchEnd, this);
18074 onRender : function(ct, position)
18076 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18079 setActive : function(state)
18081 Roo.log("panel - set active " + this.tabId + "=" + state);
18083 this.active = state;
18085 this.el.removeClass('active');
18087 } else if (!this.el.hasClass('active')) {
18088 this.el.addClass('active');
18091 this.fireEvent('changed', this, state);
18094 onClick : function(e)
18096 e.preventDefault();
18098 if(!this.href.length){
18102 window.location.href = this.href;
18111 onTouchStart : function(e)
18113 this.swiping = false;
18115 this.startX = e.browserEvent.touches[0].clientX;
18116 this.startY = e.browserEvent.touches[0].clientY;
18119 onTouchMove : function(e)
18121 this.swiping = true;
18123 this.endX = e.browserEvent.touches[0].clientX;
18124 this.endY = e.browserEvent.touches[0].clientY;
18127 onTouchEnd : function(e)
18134 var tabGroup = this.parent();
18136 if(this.endX > this.startX){ // swiping right
18137 tabGroup.showPanelPrev();
18141 if(this.startX > this.endX){ // swiping left
18142 tabGroup.showPanelNext();
18161 * @class Roo.bootstrap.DateField
18162 * @extends Roo.bootstrap.Input
18163 * Bootstrap DateField class
18164 * @cfg {Number} weekStart default 0
18165 * @cfg {String} viewMode default empty, (months|years)
18166 * @cfg {String} minViewMode default empty, (months|years)
18167 * @cfg {Number} startDate default -Infinity
18168 * @cfg {Number} endDate default Infinity
18169 * @cfg {Boolean} todayHighlight default false
18170 * @cfg {Boolean} todayBtn default false
18171 * @cfg {Boolean} calendarWeeks default false
18172 * @cfg {Object} daysOfWeekDisabled default empty
18173 * @cfg {Boolean} singleMode default false (true | false)
18175 * @cfg {Boolean} keyboardNavigation default true
18176 * @cfg {String} language default en
18179 * Create a new DateField
18180 * @param {Object} config The config object
18183 Roo.bootstrap.DateField = function(config){
18184 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18188 * Fires when this field show.
18189 * @param {Roo.bootstrap.DateField} this
18190 * @param {Mixed} date The date value
18195 * Fires when this field hide.
18196 * @param {Roo.bootstrap.DateField} this
18197 * @param {Mixed} date The date value
18202 * Fires when select a date.
18203 * @param {Roo.bootstrap.DateField} this
18204 * @param {Mixed} date The date value
18208 * @event beforeselect
18209 * Fires when before select a date.
18210 * @param {Roo.bootstrap.DateField} this
18211 * @param {Mixed} date The date value
18213 beforeselect : true
18217 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18220 * @cfg {String} format
18221 * The default date format string which can be overriden for localization support. The format must be
18222 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18226 * @cfg {String} altFormats
18227 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18228 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18230 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18238 todayHighlight : false,
18244 keyboardNavigation: true,
18246 calendarWeeks: false,
18248 startDate: -Infinity,
18252 daysOfWeekDisabled: [],
18256 singleMode : false,
18258 UTCDate: function()
18260 return new Date(Date.UTC.apply(Date, arguments));
18263 UTCToday: function()
18265 var today = new Date();
18266 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18269 getDate: function() {
18270 var d = this.getUTCDate();
18271 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18274 getUTCDate: function() {
18278 setDate: function(d) {
18279 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18282 setUTCDate: function(d) {
18284 this.setValue(this.formatDate(this.date));
18287 onRender: function(ct, position)
18290 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18292 this.language = this.language || 'en';
18293 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18294 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18296 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18297 this.format = this.format || 'm/d/y';
18298 this.isInline = false;
18299 this.isInput = true;
18300 this.component = this.el.select('.add-on', true).first() || false;
18301 this.component = (this.component && this.component.length === 0) ? false : this.component;
18302 this.hasInput = this.component && this.inputEl().length;
18304 if (typeof(this.minViewMode === 'string')) {
18305 switch (this.minViewMode) {
18307 this.minViewMode = 1;
18310 this.minViewMode = 2;
18313 this.minViewMode = 0;
18318 if (typeof(this.viewMode === 'string')) {
18319 switch (this.viewMode) {
18332 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18334 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18336 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18338 this.picker().on('mousedown', this.onMousedown, this);
18339 this.picker().on('click', this.onClick, this);
18341 this.picker().addClass('datepicker-dropdown');
18343 this.startViewMode = this.viewMode;
18345 if(this.singleMode){
18346 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18347 v.setVisibilityMode(Roo.Element.DISPLAY);
18351 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18352 v.setStyle('width', '189px');
18356 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18357 if(!this.calendarWeeks){
18362 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18363 v.attr('colspan', function(i, val){
18364 return parseInt(val) + 1;
18369 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18371 this.setStartDate(this.startDate);
18372 this.setEndDate(this.endDate);
18374 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18381 if(this.isInline) {
18386 picker : function()
18388 return this.pickerEl;
18389 // return this.el.select('.datepicker', true).first();
18392 fillDow: function()
18394 var dowCnt = this.weekStart;
18403 if(this.calendarWeeks){
18411 while (dowCnt < this.weekStart + 7) {
18415 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18419 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18422 fillMonths: function()
18425 var months = this.picker().select('>.datepicker-months td', true).first();
18427 months.dom.innerHTML = '';
18433 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18436 months.createChild(month);
18443 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;
18445 if (this.date < this.startDate) {
18446 this.viewDate = new Date(this.startDate);
18447 } else if (this.date > this.endDate) {
18448 this.viewDate = new Date(this.endDate);
18450 this.viewDate = new Date(this.date);
18458 var d = new Date(this.viewDate),
18459 year = d.getUTCFullYear(),
18460 month = d.getUTCMonth(),
18461 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18462 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18463 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18464 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18465 currentDate = this.date && this.date.valueOf(),
18466 today = this.UTCToday();
18468 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18470 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18472 // this.picker.select('>tfoot th.today').
18473 // .text(dates[this.language].today)
18474 // .toggle(this.todayBtn !== false);
18476 this.updateNavArrows();
18479 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18481 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18483 prevMonth.setUTCDate(day);
18485 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18487 var nextMonth = new Date(prevMonth);
18489 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18491 nextMonth = nextMonth.valueOf();
18493 var fillMonths = false;
18495 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18497 while(prevMonth.valueOf() < nextMonth) {
18500 if (prevMonth.getUTCDay() === this.weekStart) {
18502 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18510 if(this.calendarWeeks){
18511 // ISO 8601: First week contains first thursday.
18512 // ISO also states week starts on Monday, but we can be more abstract here.
18514 // Start of current week: based on weekstart/current date
18515 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18516 // Thursday of this week
18517 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18518 // First Thursday of year, year from thursday
18519 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18520 // Calendar week: ms between thursdays, div ms per day, div 7 days
18521 calWeek = (th - yth) / 864e5 / 7 + 1;
18523 fillMonths.cn.push({
18531 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18533 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18536 if (this.todayHighlight &&
18537 prevMonth.getUTCFullYear() == today.getFullYear() &&
18538 prevMonth.getUTCMonth() == today.getMonth() &&
18539 prevMonth.getUTCDate() == today.getDate()) {
18540 clsName += ' today';
18543 if (currentDate && prevMonth.valueOf() === currentDate) {
18544 clsName += ' active';
18547 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18548 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18549 clsName += ' disabled';
18552 fillMonths.cn.push({
18554 cls: 'day ' + clsName,
18555 html: prevMonth.getDate()
18558 prevMonth.setDate(prevMonth.getDate()+1);
18561 var currentYear = this.date && this.date.getUTCFullYear();
18562 var currentMonth = this.date && this.date.getUTCMonth();
18564 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18566 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18567 v.removeClass('active');
18569 if(currentYear === year && k === currentMonth){
18570 v.addClass('active');
18573 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18574 v.addClass('disabled');
18580 year = parseInt(year/10, 10) * 10;
18582 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18584 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18587 for (var i = -1; i < 11; i++) {
18588 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18590 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18598 showMode: function(dir)
18601 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18604 Roo.each(this.picker().select('>div',true).elements, function(v){
18605 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18608 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18613 if(this.isInline) {
18617 this.picker().removeClass(['bottom', 'top']);
18619 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18621 * place to the top of element!
18625 this.picker().addClass('top');
18626 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18631 this.picker().addClass('bottom');
18633 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18636 parseDate : function(value)
18638 if(!value || value instanceof Date){
18641 var v = Date.parseDate(value, this.format);
18642 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18643 v = Date.parseDate(value, 'Y-m-d');
18645 if(!v && this.altFormats){
18646 if(!this.altFormatsArray){
18647 this.altFormatsArray = this.altFormats.split("|");
18649 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18650 v = Date.parseDate(value, this.altFormatsArray[i]);
18656 formatDate : function(date, fmt)
18658 return (!date || !(date instanceof Date)) ?
18659 date : date.dateFormat(fmt || this.format);
18662 onFocus : function()
18664 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18668 onBlur : function()
18670 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18672 var d = this.inputEl().getValue();
18681 this.picker().show();
18685 this.fireEvent('show', this, this.date);
18690 if(this.isInline) {
18693 this.picker().hide();
18694 this.viewMode = this.startViewMode;
18697 this.fireEvent('hide', this, this.date);
18701 onMousedown: function(e)
18703 e.stopPropagation();
18704 e.preventDefault();
18709 Roo.bootstrap.DateField.superclass.keyup.call(this);
18713 setValue: function(v)
18715 if(this.fireEvent('beforeselect', this, v) !== false){
18716 var d = new Date(this.parseDate(v) ).clearTime();
18718 if(isNaN(d.getTime())){
18719 this.date = this.viewDate = '';
18720 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18724 v = this.formatDate(d);
18726 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18728 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18732 this.fireEvent('select', this, this.date);
18736 getValue: function()
18738 return this.formatDate(this.date);
18741 fireKey: function(e)
18743 if (!this.picker().isVisible()){
18744 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18750 var dateChanged = false,
18752 newDate, newViewDate;
18757 e.preventDefault();
18761 if (!this.keyboardNavigation) {
18764 dir = e.keyCode == 37 ? -1 : 1;
18767 newDate = this.moveYear(this.date, dir);
18768 newViewDate = this.moveYear(this.viewDate, dir);
18769 } else if (e.shiftKey){
18770 newDate = this.moveMonth(this.date, dir);
18771 newViewDate = this.moveMonth(this.viewDate, dir);
18773 newDate = new Date(this.date);
18774 newDate.setUTCDate(this.date.getUTCDate() + dir);
18775 newViewDate = new Date(this.viewDate);
18776 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18778 if (this.dateWithinRange(newDate)){
18779 this.date = newDate;
18780 this.viewDate = newViewDate;
18781 this.setValue(this.formatDate(this.date));
18783 e.preventDefault();
18784 dateChanged = true;
18789 if (!this.keyboardNavigation) {
18792 dir = e.keyCode == 38 ? -1 : 1;
18794 newDate = this.moveYear(this.date, dir);
18795 newViewDate = this.moveYear(this.viewDate, dir);
18796 } else if (e.shiftKey){
18797 newDate = this.moveMonth(this.date, dir);
18798 newViewDate = this.moveMonth(this.viewDate, dir);
18800 newDate = new Date(this.date);
18801 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18802 newViewDate = new Date(this.viewDate);
18803 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18805 if (this.dateWithinRange(newDate)){
18806 this.date = newDate;
18807 this.viewDate = newViewDate;
18808 this.setValue(this.formatDate(this.date));
18810 e.preventDefault();
18811 dateChanged = true;
18815 this.setValue(this.formatDate(this.date));
18817 e.preventDefault();
18820 this.setValue(this.formatDate(this.date));
18834 onClick: function(e)
18836 e.stopPropagation();
18837 e.preventDefault();
18839 var target = e.getTarget();
18841 if(target.nodeName.toLowerCase() === 'i'){
18842 target = Roo.get(target).dom.parentNode;
18845 var nodeName = target.nodeName;
18846 var className = target.className;
18847 var html = target.innerHTML;
18848 //Roo.log(nodeName);
18850 switch(nodeName.toLowerCase()) {
18852 switch(className) {
18858 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18859 switch(this.viewMode){
18861 this.viewDate = this.moveMonth(this.viewDate, dir);
18865 this.viewDate = this.moveYear(this.viewDate, dir);
18871 var date = new Date();
18872 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18874 this.setValue(this.formatDate(this.date));
18881 if (className.indexOf('disabled') < 0) {
18882 this.viewDate.setUTCDate(1);
18883 if (className.indexOf('month') > -1) {
18884 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18886 var year = parseInt(html, 10) || 0;
18887 this.viewDate.setUTCFullYear(year);
18891 if(this.singleMode){
18892 this.setValue(this.formatDate(this.viewDate));
18903 //Roo.log(className);
18904 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18905 var day = parseInt(html, 10) || 1;
18906 var year = this.viewDate.getUTCFullYear(),
18907 month = this.viewDate.getUTCMonth();
18909 if (className.indexOf('old') > -1) {
18916 } else if (className.indexOf('new') > -1) {
18924 //Roo.log([year,month,day]);
18925 this.date = this.UTCDate(year, month, day,0,0,0,0);
18926 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18928 //Roo.log(this.formatDate(this.date));
18929 this.setValue(this.formatDate(this.date));
18936 setStartDate: function(startDate)
18938 this.startDate = startDate || -Infinity;
18939 if (this.startDate !== -Infinity) {
18940 this.startDate = this.parseDate(this.startDate);
18943 this.updateNavArrows();
18946 setEndDate: function(endDate)
18948 this.endDate = endDate || Infinity;
18949 if (this.endDate !== Infinity) {
18950 this.endDate = this.parseDate(this.endDate);
18953 this.updateNavArrows();
18956 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18958 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18959 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18960 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18962 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18963 return parseInt(d, 10);
18966 this.updateNavArrows();
18969 updateNavArrows: function()
18971 if(this.singleMode){
18975 var d = new Date(this.viewDate),
18976 year = d.getUTCFullYear(),
18977 month = d.getUTCMonth();
18979 Roo.each(this.picker().select('.prev', true).elements, function(v){
18981 switch (this.viewMode) {
18984 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18990 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18997 Roo.each(this.picker().select('.next', true).elements, function(v){
18999 switch (this.viewMode) {
19002 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19008 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19016 moveMonth: function(date, dir)
19021 var new_date = new Date(date.valueOf()),
19022 day = new_date.getUTCDate(),
19023 month = new_date.getUTCMonth(),
19024 mag = Math.abs(dir),
19026 dir = dir > 0 ? 1 : -1;
19029 // If going back one month, make sure month is not current month
19030 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19032 return new_date.getUTCMonth() == month;
19034 // If going forward one month, make sure month is as expected
19035 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19037 return new_date.getUTCMonth() != new_month;
19039 new_month = month + dir;
19040 new_date.setUTCMonth(new_month);
19041 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19042 if (new_month < 0 || new_month > 11) {
19043 new_month = (new_month + 12) % 12;
19046 // For magnitudes >1, move one month at a time...
19047 for (var i=0; i<mag; i++) {
19048 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19049 new_date = this.moveMonth(new_date, dir);
19051 // ...then reset the day, keeping it in the new month
19052 new_month = new_date.getUTCMonth();
19053 new_date.setUTCDate(day);
19055 return new_month != new_date.getUTCMonth();
19058 // Common date-resetting loop -- if date is beyond end of month, make it
19061 new_date.setUTCDate(--day);
19062 new_date.setUTCMonth(new_month);
19067 moveYear: function(date, dir)
19069 return this.moveMonth(date, dir*12);
19072 dateWithinRange: function(date)
19074 return date >= this.startDate && date <= this.endDate;
19080 this.picker().remove();
19083 validateValue : function(value)
19085 if(value.length < 1) {
19086 if(this.allowBlank){
19092 if(value.length < this.minLength){
19095 if(value.length > this.maxLength){
19099 var vt = Roo.form.VTypes;
19100 if(!vt[this.vtype](value, this)){
19104 if(typeof this.validator == "function"){
19105 var msg = this.validator(value);
19111 if(this.regex && !this.regex.test(value)){
19115 if(typeof(this.parseDate(value)) == 'undefined'){
19119 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19123 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19133 Roo.apply(Roo.bootstrap.DateField, {
19144 html: '<i class="fa fa-arrow-left"/>'
19154 html: '<i class="fa fa-arrow-right"/>'
19196 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19197 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19198 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19199 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19200 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19213 navFnc: 'FullYear',
19218 navFnc: 'FullYear',
19223 Roo.apply(Roo.bootstrap.DateField, {
19227 cls: 'datepicker dropdown-menu roo-dynamic',
19231 cls: 'datepicker-days',
19235 cls: 'table-condensed',
19237 Roo.bootstrap.DateField.head,
19241 Roo.bootstrap.DateField.footer
19248 cls: 'datepicker-months',
19252 cls: 'table-condensed',
19254 Roo.bootstrap.DateField.head,
19255 Roo.bootstrap.DateField.content,
19256 Roo.bootstrap.DateField.footer
19263 cls: 'datepicker-years',
19267 cls: 'table-condensed',
19269 Roo.bootstrap.DateField.head,
19270 Roo.bootstrap.DateField.content,
19271 Roo.bootstrap.DateField.footer
19290 * @class Roo.bootstrap.TimeField
19291 * @extends Roo.bootstrap.Input
19292 * Bootstrap DateField class
19296 * Create a new TimeField
19297 * @param {Object} config The config object
19300 Roo.bootstrap.TimeField = function(config){
19301 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19305 * Fires when this field show.
19306 * @param {Roo.bootstrap.DateField} thisthis
19307 * @param {Mixed} date The date value
19312 * Fires when this field hide.
19313 * @param {Roo.bootstrap.DateField} this
19314 * @param {Mixed} date The date value
19319 * Fires when select a date.
19320 * @param {Roo.bootstrap.DateField} this
19321 * @param {Mixed} date The date value
19327 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19330 * @cfg {String} format
19331 * The default time format string which can be overriden for localization support. The format must be
19332 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19336 onRender: function(ct, position)
19339 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19341 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19343 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19345 this.pop = this.picker().select('>.datepicker-time',true).first();
19346 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19348 this.picker().on('mousedown', this.onMousedown, this);
19349 this.picker().on('click', this.onClick, this);
19351 this.picker().addClass('datepicker-dropdown');
19356 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19357 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19358 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19359 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19360 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19361 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19365 fireKey: function(e){
19366 if (!this.picker().isVisible()){
19367 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19373 e.preventDefault();
19381 this.onTogglePeriod();
19384 this.onIncrementMinutes();
19387 this.onDecrementMinutes();
19396 onClick: function(e) {
19397 e.stopPropagation();
19398 e.preventDefault();
19401 picker : function()
19403 return this.el.select('.datepicker', true).first();
19406 fillTime: function()
19408 var time = this.pop.select('tbody', true).first();
19410 time.dom.innerHTML = '';
19425 cls: 'hours-up glyphicon glyphicon-chevron-up'
19445 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19466 cls: 'timepicker-hour',
19481 cls: 'timepicker-minute',
19496 cls: 'btn btn-primary period',
19518 cls: 'hours-down glyphicon glyphicon-chevron-down'
19538 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19556 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19563 var hours = this.time.getHours();
19564 var minutes = this.time.getMinutes();
19577 hours = hours - 12;
19581 hours = '0' + hours;
19585 minutes = '0' + minutes;
19588 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19589 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19590 this.pop.select('button', true).first().dom.innerHTML = period;
19596 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19598 var cls = ['bottom'];
19600 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19607 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19612 this.picker().addClass(cls.join('-'));
19616 Roo.each(cls, function(c){
19618 _this.picker().setTop(_this.inputEl().getHeight());
19622 _this.picker().setTop(0 - _this.picker().getHeight());
19627 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19631 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19638 onFocus : function()
19640 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19644 onBlur : function()
19646 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19652 this.picker().show();
19657 this.fireEvent('show', this, this.date);
19662 this.picker().hide();
19665 this.fireEvent('hide', this, this.date);
19668 setTime : function()
19671 this.setValue(this.time.format(this.format));
19673 this.fireEvent('select', this, this.date);
19678 onMousedown: function(e){
19679 e.stopPropagation();
19680 e.preventDefault();
19683 onIncrementHours: function()
19685 Roo.log('onIncrementHours');
19686 this.time = this.time.add(Date.HOUR, 1);
19691 onDecrementHours: function()
19693 Roo.log('onDecrementHours');
19694 this.time = this.time.add(Date.HOUR, -1);
19698 onIncrementMinutes: function()
19700 Roo.log('onIncrementMinutes');
19701 this.time = this.time.add(Date.MINUTE, 1);
19705 onDecrementMinutes: function()
19707 Roo.log('onDecrementMinutes');
19708 this.time = this.time.add(Date.MINUTE, -1);
19712 onTogglePeriod: function()
19714 Roo.log('onTogglePeriod');
19715 this.time = this.time.add(Date.HOUR, 12);
19722 Roo.apply(Roo.bootstrap.TimeField, {
19752 cls: 'btn btn-info ok',
19764 Roo.apply(Roo.bootstrap.TimeField, {
19768 cls: 'datepicker dropdown-menu',
19772 cls: 'datepicker-time',
19776 cls: 'table-condensed',
19778 Roo.bootstrap.TimeField.content,
19779 Roo.bootstrap.TimeField.footer
19798 * @class Roo.bootstrap.MonthField
19799 * @extends Roo.bootstrap.Input
19800 * Bootstrap MonthField class
19802 * @cfg {String} language default en
19805 * Create a new MonthField
19806 * @param {Object} config The config object
19809 Roo.bootstrap.MonthField = function(config){
19810 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19815 * Fires when this field show.
19816 * @param {Roo.bootstrap.MonthField} this
19817 * @param {Mixed} date The date value
19822 * Fires when this field hide.
19823 * @param {Roo.bootstrap.MonthField} this
19824 * @param {Mixed} date The date value
19829 * Fires when select a date.
19830 * @param {Roo.bootstrap.MonthField} this
19831 * @param {String} oldvalue The old value
19832 * @param {String} newvalue The new value
19838 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19840 onRender: function(ct, position)
19843 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19845 this.language = this.language || 'en';
19846 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19847 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19849 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19850 this.isInline = false;
19851 this.isInput = true;
19852 this.component = this.el.select('.add-on', true).first() || false;
19853 this.component = (this.component && this.component.length === 0) ? false : this.component;
19854 this.hasInput = this.component && this.inputEL().length;
19856 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19858 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19860 this.picker().on('mousedown', this.onMousedown, this);
19861 this.picker().on('click', this.onClick, this);
19863 this.picker().addClass('datepicker-dropdown');
19865 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19866 v.setStyle('width', '189px');
19873 if(this.isInline) {
19879 setValue: function(v, suppressEvent)
19881 var o = this.getValue();
19883 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19887 if(suppressEvent !== true){
19888 this.fireEvent('select', this, o, v);
19893 getValue: function()
19898 onClick: function(e)
19900 e.stopPropagation();
19901 e.preventDefault();
19903 var target = e.getTarget();
19905 if(target.nodeName.toLowerCase() === 'i'){
19906 target = Roo.get(target).dom.parentNode;
19909 var nodeName = target.nodeName;
19910 var className = target.className;
19911 var html = target.innerHTML;
19913 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19917 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19919 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19925 picker : function()
19927 return this.pickerEl;
19930 fillMonths: function()
19933 var months = this.picker().select('>.datepicker-months td', true).first();
19935 months.dom.innerHTML = '';
19941 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19944 months.createChild(month);
19953 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19954 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19957 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19958 e.removeClass('active');
19960 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19961 e.addClass('active');
19968 if(this.isInline) {
19972 this.picker().removeClass(['bottom', 'top']);
19974 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19976 * place to the top of element!
19980 this.picker().addClass('top');
19981 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19986 this.picker().addClass('bottom');
19988 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19991 onFocus : function()
19993 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19997 onBlur : function()
19999 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20001 var d = this.inputEl().getValue();
20010 this.picker().show();
20011 this.picker().select('>.datepicker-months', true).first().show();
20015 this.fireEvent('show', this, this.date);
20020 if(this.isInline) {
20023 this.picker().hide();
20024 this.fireEvent('hide', this, this.date);
20028 onMousedown: function(e)
20030 e.stopPropagation();
20031 e.preventDefault();
20036 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20040 fireKey: function(e)
20042 if (!this.picker().isVisible()){
20043 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20054 e.preventDefault();
20058 dir = e.keyCode == 37 ? -1 : 1;
20060 this.vIndex = this.vIndex + dir;
20062 if(this.vIndex < 0){
20066 if(this.vIndex > 11){
20070 if(isNaN(this.vIndex)){
20074 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20080 dir = e.keyCode == 38 ? -1 : 1;
20082 this.vIndex = this.vIndex + dir * 4;
20084 if(this.vIndex < 0){
20088 if(this.vIndex > 11){
20092 if(isNaN(this.vIndex)){
20096 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20101 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20102 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20106 e.preventDefault();
20109 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20110 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20126 this.picker().remove();
20131 Roo.apply(Roo.bootstrap.MonthField, {
20150 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20151 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20156 Roo.apply(Roo.bootstrap.MonthField, {
20160 cls: 'datepicker dropdown-menu roo-dynamic',
20164 cls: 'datepicker-months',
20168 cls: 'table-condensed',
20170 Roo.bootstrap.DateField.content
20190 * @class Roo.bootstrap.CheckBox
20191 * @extends Roo.bootstrap.Input
20192 * Bootstrap CheckBox class
20194 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20195 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20196 * @cfg {String} boxLabel The text that appears beside the checkbox
20197 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20198 * @cfg {Boolean} checked initnal the element
20199 * @cfg {Boolean} inline inline the element (default false)
20200 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20201 * @cfg {String} tooltip label tooltip
20204 * Create a new CheckBox
20205 * @param {Object} config The config object
20208 Roo.bootstrap.CheckBox = function(config){
20209 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20214 * Fires when the element is checked or unchecked.
20215 * @param {Roo.bootstrap.CheckBox} this This input
20216 * @param {Boolean} checked The new checked value
20221 * Fires when the element is click.
20222 * @param {Roo.bootstrap.CheckBox} this This input
20229 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20231 inputType: 'checkbox',
20240 getAutoCreate : function()
20242 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20248 cfg.cls = 'form-group ' + this.inputType; //input-group
20251 cfg.cls += ' ' + this.inputType + '-inline';
20257 type : this.inputType,
20258 value : this.inputValue,
20259 cls : 'roo-' + this.inputType, //'form-box',
20260 placeholder : this.placeholder || ''
20264 if(this.inputType != 'radio'){
20268 cls : 'roo-hidden-value',
20269 value : this.checked ? this.inputValue : this.valueOff
20274 if (this.weight) { // Validity check?
20275 cfg.cls += " " + this.inputType + "-" + this.weight;
20278 if (this.disabled) {
20279 input.disabled=true;
20283 input.checked = this.checked;
20288 input.name = this.name;
20290 if(this.inputType != 'radio'){
20291 hidden.name = this.name;
20292 input.name = '_hidden_' + this.name;
20297 input.cls += ' input-' + this.size;
20302 ['xs','sm','md','lg'].map(function(size){
20303 if (settings[size]) {
20304 cfg.cls += ' col-' + size + '-' + settings[size];
20308 var inputblock = input;
20310 if (this.before || this.after) {
20313 cls : 'input-group',
20318 inputblock.cn.push({
20320 cls : 'input-group-addon',
20325 inputblock.cn.push(input);
20327 if(this.inputType != 'radio'){
20328 inputblock.cn.push(hidden);
20332 inputblock.cn.push({
20334 cls : 'input-group-addon',
20341 if (align ==='left' && this.fieldLabel.length) {
20342 // Roo.log("left and has label");
20347 cls : 'control-label',
20348 html : this.fieldLabel
20358 if(this.labelWidth > 12){
20359 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20362 if(this.labelWidth < 13 && this.labelmd == 0){
20363 this.labelmd = this.labelWidth;
20366 if(this.labellg > 0){
20367 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20368 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20371 if(this.labelmd > 0){
20372 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20373 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20376 if(this.labelsm > 0){
20377 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20378 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20381 if(this.labelxs > 0){
20382 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20383 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20386 } else if ( this.fieldLabel.length) {
20387 // Roo.log(" label");
20391 tag: this.boxLabel ? 'span' : 'label',
20393 cls: 'control-label box-input-label',
20394 //cls : 'input-group-addon',
20395 html : this.fieldLabel
20404 // Roo.log(" no label && no align");
20405 cfg.cn = [ inputblock ] ;
20411 var boxLabelCfg = {
20413 //'for': id, // box label is handled by onclick - so no for...
20415 html: this.boxLabel
20419 boxLabelCfg.tooltip = this.tooltip;
20422 cfg.cn.push(boxLabelCfg);
20425 if(this.inputType != 'radio'){
20426 cfg.cn.push(hidden);
20434 * return the real input element.
20436 inputEl: function ()
20438 return this.el.select('input.roo-' + this.inputType,true).first();
20440 hiddenEl: function ()
20442 return this.el.select('input.roo-hidden-value',true).first();
20445 labelEl: function()
20447 return this.el.select('label.control-label',true).first();
20449 /* depricated... */
20453 return this.labelEl();
20456 boxLabelEl: function()
20458 return this.el.select('label.box-label',true).first();
20461 initEvents : function()
20463 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20465 this.inputEl().on('click', this.onClick, this);
20467 if (this.boxLabel) {
20468 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20471 this.startValue = this.getValue();
20474 Roo.bootstrap.CheckBox.register(this);
20478 onClick : function(e)
20480 if(this.fireEvent('click', this, e) !== false){
20481 this.setChecked(!this.checked);
20486 setChecked : function(state,suppressEvent)
20488 this.startValue = this.getValue();
20490 if(this.inputType == 'radio'){
20492 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20493 e.dom.checked = false;
20496 this.inputEl().dom.checked = true;
20498 this.inputEl().dom.value = this.inputValue;
20500 if(suppressEvent !== true){
20501 this.fireEvent('check', this, true);
20509 this.checked = state;
20511 this.inputEl().dom.checked = state;
20514 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20516 if(suppressEvent !== true){
20517 this.fireEvent('check', this, state);
20523 getValue : function()
20525 if(this.inputType == 'radio'){
20526 return this.getGroupValue();
20529 return this.hiddenEl().dom.value;
20533 getGroupValue : function()
20535 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20539 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20542 setValue : function(v,suppressEvent)
20544 if(this.inputType == 'radio'){
20545 this.setGroupValue(v, suppressEvent);
20549 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20554 setGroupValue : function(v, suppressEvent)
20556 this.startValue = this.getValue();
20558 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20559 e.dom.checked = false;
20561 if(e.dom.value == v){
20562 e.dom.checked = true;
20566 if(suppressEvent !== true){
20567 this.fireEvent('check', this, true);
20575 validate : function()
20579 (this.inputType == 'radio' && this.validateRadio()) ||
20580 (this.inputType == 'checkbox' && this.validateCheckbox())
20586 this.markInvalid();
20590 validateRadio : function()
20592 if(this.allowBlank){
20598 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20599 if(!e.dom.checked){
20611 validateCheckbox : function()
20614 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20615 //return (this.getValue() == this.inputValue) ? true : false;
20618 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20626 for(var i in group){
20627 if(group[i].el.isVisible(true)){
20635 for(var i in group){
20640 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20647 * Mark this field as valid
20649 markValid : function()
20653 this.fireEvent('valid', this);
20655 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20658 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20665 if(this.inputType == 'radio'){
20666 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20667 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20668 e.findParent('.form-group', false, true).addClass(_this.validClass);
20675 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20676 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20680 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20686 for(var i in group){
20687 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20688 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20693 * Mark this field as invalid
20694 * @param {String} msg The validation message
20696 markInvalid : function(msg)
20698 if(this.allowBlank){
20704 this.fireEvent('invalid', this, msg);
20706 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20709 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20713 label.markInvalid();
20716 if(this.inputType == 'radio'){
20717 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20718 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20719 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20726 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20727 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20731 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20737 for(var i in group){
20738 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20739 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20744 clearInvalid : function()
20746 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20748 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20750 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20752 if (label && label.iconEl) {
20753 label.iconEl.removeClass(label.validClass);
20754 label.iconEl.removeClass(label.invalidClass);
20758 disable : function()
20760 if(this.inputType != 'radio'){
20761 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20768 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20769 _this.getActionEl().addClass(this.disabledClass);
20770 e.dom.disabled = true;
20774 this.disabled = true;
20775 this.fireEvent("disable", this);
20779 enable : function()
20781 if(this.inputType != 'radio'){
20782 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20789 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20790 _this.getActionEl().removeClass(this.disabledClass);
20791 e.dom.disabled = false;
20795 this.disabled = false;
20796 this.fireEvent("enable", this);
20800 setBoxLabel : function(v)
20805 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20811 Roo.apply(Roo.bootstrap.CheckBox, {
20816 * register a CheckBox Group
20817 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20819 register : function(checkbox)
20821 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20822 this.groups[checkbox.groupId] = {};
20825 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20829 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20833 * fetch a CheckBox Group based on the group ID
20834 * @param {string} the group ID
20835 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20837 get: function(groupId) {
20838 if (typeof(this.groups[groupId]) == 'undefined') {
20842 return this.groups[groupId] ;
20855 * @class Roo.bootstrap.Radio
20856 * @extends Roo.bootstrap.Component
20857 * Bootstrap Radio class
20858 * @cfg {String} boxLabel - the label associated
20859 * @cfg {String} value - the value of radio
20862 * Create a new Radio
20863 * @param {Object} config The config object
20865 Roo.bootstrap.Radio = function(config){
20866 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20870 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20876 getAutoCreate : function()
20880 cls : 'form-group radio',
20885 html : this.boxLabel
20893 initEvents : function()
20895 this.parent().register(this);
20897 this.el.on('click', this.onClick, this);
20901 onClick : function()
20903 this.setChecked(true);
20906 setChecked : function(state, suppressEvent)
20908 this.parent().setValue(this.value, suppressEvent);
20912 setBoxLabel : function(v)
20917 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20932 * @class Roo.bootstrap.SecurePass
20933 * @extends Roo.bootstrap.Input
20934 * Bootstrap SecurePass class
20938 * Create a new SecurePass
20939 * @param {Object} config The config object
20942 Roo.bootstrap.SecurePass = function (config) {
20943 // these go here, so the translation tool can replace them..
20945 PwdEmpty: "Please type a password, and then retype it to confirm.",
20946 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20947 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20948 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20949 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20950 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20951 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20952 TooWeak: "Your password is Too Weak."
20954 this.meterLabel = "Password strength:";
20955 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20956 this.meterClass = [
20957 "roo-password-meter-tooweak",
20958 "roo-password-meter-weak",
20959 "roo-password-meter-medium",
20960 "roo-password-meter-strong",
20961 "roo-password-meter-grey"
20966 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20969 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20971 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20973 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20974 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20975 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20976 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20977 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20978 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20979 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20989 * @cfg {String/Object} Label for the strength meter (defaults to
20990 * 'Password strength:')
20995 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20996 * ['Weak', 'Medium', 'Strong'])
20999 pwdStrengths: false,
21012 initEvents: function ()
21014 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21016 if (this.el.is('input[type=password]') && Roo.isSafari) {
21017 this.el.on('keydown', this.SafariOnKeyDown, this);
21020 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21023 onRender: function (ct, position)
21025 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21026 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21027 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21029 this.trigger.createChild({
21034 cls: 'roo-password-meter-grey col-xs-12',
21037 //width: this.meterWidth + 'px'
21041 cls: 'roo-password-meter-text'
21047 if (this.hideTrigger) {
21048 this.trigger.setDisplayed(false);
21050 this.setSize(this.width || '', this.height || '');
21053 onDestroy: function ()
21055 if (this.trigger) {
21056 this.trigger.removeAllListeners();
21057 this.trigger.remove();
21060 this.wrap.remove();
21062 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21065 checkStrength: function ()
21067 var pwd = this.inputEl().getValue();
21068 if (pwd == this._lastPwd) {
21073 if (this.ClientSideStrongPassword(pwd)) {
21075 } else if (this.ClientSideMediumPassword(pwd)) {
21077 } else if (this.ClientSideWeakPassword(pwd)) {
21083 Roo.log('strength1: ' + strength);
21085 //var pm = this.trigger.child('div/div/div').dom;
21086 var pm = this.trigger.child('div/div');
21087 pm.removeClass(this.meterClass);
21088 pm.addClass(this.meterClass[strength]);
21091 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21093 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21095 this._lastPwd = pwd;
21099 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21101 this._lastPwd = '';
21103 var pm = this.trigger.child('div/div');
21104 pm.removeClass(this.meterClass);
21105 pm.addClass('roo-password-meter-grey');
21108 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21111 this.inputEl().dom.type='password';
21114 validateValue: function (value)
21117 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21120 if (value.length == 0) {
21121 if (this.allowBlank) {
21122 this.clearInvalid();
21126 this.markInvalid(this.errors.PwdEmpty);
21127 this.errorMsg = this.errors.PwdEmpty;
21135 if ('[\x21-\x7e]*'.match(value)) {
21136 this.markInvalid(this.errors.PwdBadChar);
21137 this.errorMsg = this.errors.PwdBadChar;
21140 if (value.length < 6) {
21141 this.markInvalid(this.errors.PwdShort);
21142 this.errorMsg = this.errors.PwdShort;
21145 if (value.length > 16) {
21146 this.markInvalid(this.errors.PwdLong);
21147 this.errorMsg = this.errors.PwdLong;
21151 if (this.ClientSideStrongPassword(value)) {
21153 } else if (this.ClientSideMediumPassword(value)) {
21155 } else if (this.ClientSideWeakPassword(value)) {
21162 if (strength < 2) {
21163 //this.markInvalid(this.errors.TooWeak);
21164 this.errorMsg = this.errors.TooWeak;
21169 console.log('strength2: ' + strength);
21171 //var pm = this.trigger.child('div/div/div').dom;
21173 var pm = this.trigger.child('div/div');
21174 pm.removeClass(this.meterClass);
21175 pm.addClass(this.meterClass[strength]);
21177 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21179 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21181 this.errorMsg = '';
21185 CharacterSetChecks: function (type)
21188 this.fResult = false;
21191 isctype: function (character, type)
21194 case this.kCapitalLetter:
21195 if (character >= 'A' && character <= 'Z') {
21200 case this.kSmallLetter:
21201 if (character >= 'a' && character <= 'z') {
21207 if (character >= '0' && character <= '9') {
21212 case this.kPunctuation:
21213 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21224 IsLongEnough: function (pwd, size)
21226 return !(pwd == null || isNaN(size) || pwd.length < size);
21229 SpansEnoughCharacterSets: function (word, nb)
21231 if (!this.IsLongEnough(word, nb))
21236 var characterSetChecks = new Array(
21237 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21238 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21241 for (var index = 0; index < word.length; ++index) {
21242 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21243 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21244 characterSetChecks[nCharSet].fResult = true;
21251 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21252 if (characterSetChecks[nCharSet].fResult) {
21257 if (nCharSets < nb) {
21263 ClientSideStrongPassword: function (pwd)
21265 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21268 ClientSideMediumPassword: function (pwd)
21270 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21273 ClientSideWeakPassword: function (pwd)
21275 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21278 })//<script type="text/javascript">
21281 * Based Ext JS Library 1.1.1
21282 * Copyright(c) 2006-2007, Ext JS, LLC.
21288 * @class Roo.HtmlEditorCore
21289 * @extends Roo.Component
21290 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21292 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21295 Roo.HtmlEditorCore = function(config){
21298 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21303 * @event initialize
21304 * Fires when the editor is fully initialized (including the iframe)
21305 * @param {Roo.HtmlEditorCore} this
21310 * Fires when the editor is first receives the focus. Any insertion must wait
21311 * until after this event.
21312 * @param {Roo.HtmlEditorCore} this
21316 * @event beforesync
21317 * Fires before the textarea is updated with content from the editor iframe. Return false
21318 * to cancel the sync.
21319 * @param {Roo.HtmlEditorCore} this
21320 * @param {String} html
21324 * @event beforepush
21325 * Fires before the iframe editor is updated with content from the textarea. Return false
21326 * to cancel the push.
21327 * @param {Roo.HtmlEditorCore} this
21328 * @param {String} html
21333 * Fires when the textarea is updated with content from the editor iframe.
21334 * @param {Roo.HtmlEditorCore} this
21335 * @param {String} html
21340 * Fires when the iframe editor is updated with content from the textarea.
21341 * @param {Roo.HtmlEditorCore} this
21342 * @param {String} html
21347 * @event editorevent
21348 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21349 * @param {Roo.HtmlEditorCore} this
21355 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21357 // defaults : white / black...
21358 this.applyBlacklists();
21365 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21369 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21375 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21380 * @cfg {Number} height (in pixels)
21384 * @cfg {Number} width (in pixels)
21389 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21392 stylesheets: false,
21397 // private properties
21398 validationEvent : false,
21400 initialized : false,
21402 sourceEditMode : false,
21403 onFocus : Roo.emptyFn,
21405 hideMode:'offsets',
21409 // blacklist + whitelisted elements..
21416 * Protected method that will not generally be called directly. It
21417 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21418 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21420 getDocMarkup : function(){
21424 // inherit styels from page...??
21425 if (this.stylesheets === false) {
21427 Roo.get(document.head).select('style').each(function(node) {
21428 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21431 Roo.get(document.head).select('link').each(function(node) {
21432 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21435 } else if (!this.stylesheets.length) {
21437 st = '<style type="text/css">' +
21438 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21441 st = '<style type="text/css">' +
21446 st += '<style type="text/css">' +
21447 'IMG { cursor: pointer } ' +
21450 var cls = 'roo-htmleditor-body';
21452 if(this.bodyCls.length){
21453 cls += ' ' + this.bodyCls;
21456 return '<html><head>' + st +
21457 //<style type="text/css">' +
21458 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21460 ' </head><body class="' + cls + '"></body></html>';
21464 onRender : function(ct, position)
21467 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21468 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21471 this.el.dom.style.border = '0 none';
21472 this.el.dom.setAttribute('tabIndex', -1);
21473 this.el.addClass('x-hidden hide');
21477 if(Roo.isIE){ // fix IE 1px bogus margin
21478 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21482 this.frameId = Roo.id();
21486 var iframe = this.owner.wrap.createChild({
21488 cls: 'form-control', // bootstrap..
21490 name: this.frameId,
21491 frameBorder : 'no',
21492 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21497 this.iframe = iframe.dom;
21499 this.assignDocWin();
21501 this.doc.designMode = 'on';
21504 this.doc.write(this.getDocMarkup());
21508 var task = { // must defer to wait for browser to be ready
21510 //console.log("run task?" + this.doc.readyState);
21511 this.assignDocWin();
21512 if(this.doc.body || this.doc.readyState == 'complete'){
21514 this.doc.designMode="on";
21518 Roo.TaskMgr.stop(task);
21519 this.initEditor.defer(10, this);
21526 Roo.TaskMgr.start(task);
21531 onResize : function(w, h)
21533 Roo.log('resize: ' +w + ',' + h );
21534 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21538 if(typeof w == 'number'){
21540 this.iframe.style.width = w + 'px';
21542 if(typeof h == 'number'){
21544 this.iframe.style.height = h + 'px';
21546 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21553 * Toggles the editor between standard and source edit mode.
21554 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21556 toggleSourceEdit : function(sourceEditMode){
21558 this.sourceEditMode = sourceEditMode === true;
21560 if(this.sourceEditMode){
21562 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21565 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21566 //this.iframe.className = '';
21569 //this.setSize(this.owner.wrap.getSize());
21570 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21577 * Protected method that will not generally be called directly. If you need/want
21578 * custom HTML cleanup, this is the method you should override.
21579 * @param {String} html The HTML to be cleaned
21580 * return {String} The cleaned HTML
21582 cleanHtml : function(html){
21583 html = String(html);
21584 if(html.length > 5){
21585 if(Roo.isSafari){ // strip safari nonsense
21586 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21589 if(html == ' '){
21596 * HTML Editor -> Textarea
21597 * Protected method that will not generally be called directly. Syncs the contents
21598 * of the editor iframe with the textarea.
21600 syncValue : function(){
21601 if(this.initialized){
21602 var bd = (this.doc.body || this.doc.documentElement);
21603 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21604 var html = bd.innerHTML;
21606 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21607 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21609 html = '<div style="'+m[0]+'">' + html + '</div>';
21612 html = this.cleanHtml(html);
21613 // fix up the special chars.. normaly like back quotes in word...
21614 // however we do not want to do this with chinese..
21615 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21616 var cc = b.charCodeAt();
21618 (cc >= 0x4E00 && cc < 0xA000 ) ||
21619 (cc >= 0x3400 && cc < 0x4E00 ) ||
21620 (cc >= 0xf900 && cc < 0xfb00 )
21626 if(this.owner.fireEvent('beforesync', this, html) !== false){
21627 this.el.dom.value = html;
21628 this.owner.fireEvent('sync', this, html);
21634 * Protected method that will not generally be called directly. Pushes the value of the textarea
21635 * into the iframe editor.
21637 pushValue : function(){
21638 if(this.initialized){
21639 var v = this.el.dom.value.trim();
21641 // if(v.length < 1){
21645 if(this.owner.fireEvent('beforepush', this, v) !== false){
21646 var d = (this.doc.body || this.doc.documentElement);
21648 this.cleanUpPaste();
21649 this.el.dom.value = d.innerHTML;
21650 this.owner.fireEvent('push', this, v);
21656 deferFocus : function(){
21657 this.focus.defer(10, this);
21661 focus : function(){
21662 if(this.win && !this.sourceEditMode){
21669 assignDocWin: function()
21671 var iframe = this.iframe;
21674 this.doc = iframe.contentWindow.document;
21675 this.win = iframe.contentWindow;
21677 // if (!Roo.get(this.frameId)) {
21680 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21681 // this.win = Roo.get(this.frameId).dom.contentWindow;
21683 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21687 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21688 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21693 initEditor : function(){
21694 //console.log("INIT EDITOR");
21695 this.assignDocWin();
21699 this.doc.designMode="on";
21701 this.doc.write(this.getDocMarkup());
21704 var dbody = (this.doc.body || this.doc.documentElement);
21705 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21706 // this copies styles from the containing element into thsi one..
21707 // not sure why we need all of this..
21708 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21710 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21711 //ss['background-attachment'] = 'fixed'; // w3c
21712 dbody.bgProperties = 'fixed'; // ie
21713 //Roo.DomHelper.applyStyles(dbody, ss);
21714 Roo.EventManager.on(this.doc, {
21715 //'mousedown': this.onEditorEvent,
21716 'mouseup': this.onEditorEvent,
21717 'dblclick': this.onEditorEvent,
21718 'click': this.onEditorEvent,
21719 'keyup': this.onEditorEvent,
21724 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21726 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21727 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21729 this.initialized = true;
21731 this.owner.fireEvent('initialize', this);
21736 onDestroy : function(){
21742 //for (var i =0; i < this.toolbars.length;i++) {
21743 // // fixme - ask toolbars for heights?
21744 // this.toolbars[i].onDestroy();
21747 //this.wrap.dom.innerHTML = '';
21748 //this.wrap.remove();
21753 onFirstFocus : function(){
21755 this.assignDocWin();
21758 this.activated = true;
21761 if(Roo.isGecko){ // prevent silly gecko errors
21763 var s = this.win.getSelection();
21764 if(!s.focusNode || s.focusNode.nodeType != 3){
21765 var r = s.getRangeAt(0);
21766 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21771 this.execCmd('useCSS', true);
21772 this.execCmd('styleWithCSS', false);
21775 this.owner.fireEvent('activate', this);
21779 adjustFont: function(btn){
21780 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21781 //if(Roo.isSafari){ // safari
21784 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21785 if(Roo.isSafari){ // safari
21786 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21787 v = (v < 10) ? 10 : v;
21788 v = (v > 48) ? 48 : v;
21789 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21794 v = Math.max(1, v+adjust);
21796 this.execCmd('FontSize', v );
21799 onEditorEvent : function(e)
21801 this.owner.fireEvent('editorevent', this, e);
21802 // this.updateToolbar();
21803 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21806 insertTag : function(tg)
21808 // could be a bit smarter... -> wrap the current selected tRoo..
21809 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21811 range = this.createRange(this.getSelection());
21812 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21813 wrappingNode.appendChild(range.extractContents());
21814 range.insertNode(wrappingNode);
21821 this.execCmd("formatblock", tg);
21825 insertText : function(txt)
21829 var range = this.createRange();
21830 range.deleteContents();
21831 //alert(Sender.getAttribute('label'));
21833 range.insertNode(this.doc.createTextNode(txt));
21839 * Executes a Midas editor command on the editor document and performs necessary focus and
21840 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21841 * @param {String} cmd The Midas command
21842 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21844 relayCmd : function(cmd, value){
21846 this.execCmd(cmd, value);
21847 this.owner.fireEvent('editorevent', this);
21848 //this.updateToolbar();
21849 this.owner.deferFocus();
21853 * Executes a Midas editor command directly on the editor document.
21854 * For visual commands, you should use {@link #relayCmd} instead.
21855 * <b>This should only be called after the editor is initialized.</b>
21856 * @param {String} cmd The Midas command
21857 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21859 execCmd : function(cmd, value){
21860 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21867 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21869 * @param {String} text | dom node..
21871 insertAtCursor : function(text)
21874 if(!this.activated){
21880 var r = this.doc.selection.createRange();
21891 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21895 // from jquery ui (MIT licenced)
21897 var win = this.win;
21899 if (win.getSelection && win.getSelection().getRangeAt) {
21900 range = win.getSelection().getRangeAt(0);
21901 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21902 range.insertNode(node);
21903 } else if (win.document.selection && win.document.selection.createRange) {
21904 // no firefox support
21905 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21906 win.document.selection.createRange().pasteHTML(txt);
21908 // no firefox support
21909 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21910 this.execCmd('InsertHTML', txt);
21919 mozKeyPress : function(e){
21921 var c = e.getCharCode(), cmd;
21924 c = String.fromCharCode(c).toLowerCase();
21938 this.cleanUpPaste.defer(100, this);
21946 e.preventDefault();
21954 fixKeys : function(){ // load time branching for fastest keydown performance
21956 return function(e){
21957 var k = e.getKey(), r;
21960 r = this.doc.selection.createRange();
21963 r.pasteHTML('    ');
21970 r = this.doc.selection.createRange();
21972 var target = r.parentElement();
21973 if(!target || target.tagName.toLowerCase() != 'li'){
21975 r.pasteHTML('<br />');
21981 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21982 this.cleanUpPaste.defer(100, this);
21988 }else if(Roo.isOpera){
21989 return function(e){
21990 var k = e.getKey();
21994 this.execCmd('InsertHTML','    ');
21997 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21998 this.cleanUpPaste.defer(100, this);
22003 }else if(Roo.isSafari){
22004 return function(e){
22005 var k = e.getKey();
22009 this.execCmd('InsertText','\t');
22013 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22014 this.cleanUpPaste.defer(100, this);
22022 getAllAncestors: function()
22024 var p = this.getSelectedNode();
22027 a.push(p); // push blank onto stack..
22028 p = this.getParentElement();
22032 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22036 a.push(this.doc.body);
22040 lastSelNode : false,
22043 getSelection : function()
22045 this.assignDocWin();
22046 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22049 getSelectedNode: function()
22051 // this may only work on Gecko!!!
22053 // should we cache this!!!!
22058 var range = this.createRange(this.getSelection()).cloneRange();
22061 var parent = range.parentElement();
22063 var testRange = range.duplicate();
22064 testRange.moveToElementText(parent);
22065 if (testRange.inRange(range)) {
22068 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22071 parent = parent.parentElement;
22076 // is ancestor a text element.
22077 var ac = range.commonAncestorContainer;
22078 if (ac.nodeType == 3) {
22079 ac = ac.parentNode;
22082 var ar = ac.childNodes;
22085 var other_nodes = [];
22086 var has_other_nodes = false;
22087 for (var i=0;i<ar.length;i++) {
22088 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22091 // fullly contained node.
22093 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22098 // probably selected..
22099 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22100 other_nodes.push(ar[i]);
22104 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22109 has_other_nodes = true;
22111 if (!nodes.length && other_nodes.length) {
22112 nodes= other_nodes;
22114 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22120 createRange: function(sel)
22122 // this has strange effects when using with
22123 // top toolbar - not sure if it's a great idea.
22124 //this.editor.contentWindow.focus();
22125 if (typeof sel != "undefined") {
22127 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22129 return this.doc.createRange();
22132 return this.doc.createRange();
22135 getParentElement: function()
22138 this.assignDocWin();
22139 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22141 var range = this.createRange(sel);
22144 var p = range.commonAncestorContainer;
22145 while (p.nodeType == 3) { // text node
22156 * Range intersection.. the hard stuff...
22160 * [ -- selected range --- ]
22164 * if end is before start or hits it. fail.
22165 * if start is after end or hits it fail.
22167 * if either hits (but other is outside. - then it's not
22173 // @see http://www.thismuchiknow.co.uk/?p=64.
22174 rangeIntersectsNode : function(range, node)
22176 var nodeRange = node.ownerDocument.createRange();
22178 nodeRange.selectNode(node);
22180 nodeRange.selectNodeContents(node);
22183 var rangeStartRange = range.cloneRange();
22184 rangeStartRange.collapse(true);
22186 var rangeEndRange = range.cloneRange();
22187 rangeEndRange.collapse(false);
22189 var nodeStartRange = nodeRange.cloneRange();
22190 nodeStartRange.collapse(true);
22192 var nodeEndRange = nodeRange.cloneRange();
22193 nodeEndRange.collapse(false);
22195 return rangeStartRange.compareBoundaryPoints(
22196 Range.START_TO_START, nodeEndRange) == -1 &&
22197 rangeEndRange.compareBoundaryPoints(
22198 Range.START_TO_START, nodeStartRange) == 1;
22202 rangeCompareNode : function(range, node)
22204 var nodeRange = node.ownerDocument.createRange();
22206 nodeRange.selectNode(node);
22208 nodeRange.selectNodeContents(node);
22212 range.collapse(true);
22214 nodeRange.collapse(true);
22216 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22217 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22219 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22221 var nodeIsBefore = ss == 1;
22222 var nodeIsAfter = ee == -1;
22224 if (nodeIsBefore && nodeIsAfter) {
22227 if (!nodeIsBefore && nodeIsAfter) {
22228 return 1; //right trailed.
22231 if (nodeIsBefore && !nodeIsAfter) {
22232 return 2; // left trailed.
22238 // private? - in a new class?
22239 cleanUpPaste : function()
22241 // cleans up the whole document..
22242 Roo.log('cleanuppaste');
22244 this.cleanUpChildren(this.doc.body);
22245 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22246 if (clean != this.doc.body.innerHTML) {
22247 this.doc.body.innerHTML = clean;
22252 cleanWordChars : function(input) {// change the chars to hex code
22253 var he = Roo.HtmlEditorCore;
22255 var output = input;
22256 Roo.each(he.swapCodes, function(sw) {
22257 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22259 output = output.replace(swapper, sw[1]);
22266 cleanUpChildren : function (n)
22268 if (!n.childNodes.length) {
22271 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22272 this.cleanUpChild(n.childNodes[i]);
22279 cleanUpChild : function (node)
22282 //console.log(node);
22283 if (node.nodeName == "#text") {
22284 // clean up silly Windows -- stuff?
22287 if (node.nodeName == "#comment") {
22288 node.parentNode.removeChild(node);
22289 // clean up silly Windows -- stuff?
22292 var lcname = node.tagName.toLowerCase();
22293 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22294 // whitelist of tags..
22296 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22298 node.parentNode.removeChild(node);
22303 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22305 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22306 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22308 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22309 // remove_keep_children = true;
22312 if (remove_keep_children) {
22313 this.cleanUpChildren(node);
22314 // inserts everything just before this node...
22315 while (node.childNodes.length) {
22316 var cn = node.childNodes[0];
22317 node.removeChild(cn);
22318 node.parentNode.insertBefore(cn, node);
22320 node.parentNode.removeChild(node);
22324 if (!node.attributes || !node.attributes.length) {
22325 this.cleanUpChildren(node);
22329 function cleanAttr(n,v)
22332 if (v.match(/^\./) || v.match(/^\//)) {
22335 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22338 if (v.match(/^#/)) {
22341 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22342 node.removeAttribute(n);
22346 var cwhite = this.cwhite;
22347 var cblack = this.cblack;
22349 function cleanStyle(n,v)
22351 if (v.match(/expression/)) { //XSS?? should we even bother..
22352 node.removeAttribute(n);
22356 var parts = v.split(/;/);
22359 Roo.each(parts, function(p) {
22360 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22364 var l = p.split(':').shift().replace(/\s+/g,'');
22365 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22367 if ( cwhite.length && cblack.indexOf(l) > -1) {
22368 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22369 //node.removeAttribute(n);
22373 // only allow 'c whitelisted system attributes'
22374 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22375 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22376 //node.removeAttribute(n);
22386 if (clean.length) {
22387 node.setAttribute(n, clean.join(';'));
22389 node.removeAttribute(n);
22395 for (var i = node.attributes.length-1; i > -1 ; i--) {
22396 var a = node.attributes[i];
22399 if (a.name.toLowerCase().substr(0,2)=='on') {
22400 node.removeAttribute(a.name);
22403 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22404 node.removeAttribute(a.name);
22407 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22408 cleanAttr(a.name,a.value); // fixme..
22411 if (a.name == 'style') {
22412 cleanStyle(a.name,a.value);
22415 /// clean up MS crap..
22416 // tecnically this should be a list of valid class'es..
22419 if (a.name == 'class') {
22420 if (a.value.match(/^Mso/)) {
22421 node.className = '';
22424 if (a.value.match(/^body$/)) {
22425 node.className = '';
22436 this.cleanUpChildren(node);
22442 * Clean up MS wordisms...
22444 cleanWord : function(node)
22449 this.cleanWord(this.doc.body);
22452 if (node.nodeName == "#text") {
22453 // clean up silly Windows -- stuff?
22456 if (node.nodeName == "#comment") {
22457 node.parentNode.removeChild(node);
22458 // clean up silly Windows -- stuff?
22462 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22463 node.parentNode.removeChild(node);
22467 // remove - but keep children..
22468 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22469 while (node.childNodes.length) {
22470 var cn = node.childNodes[0];
22471 node.removeChild(cn);
22472 node.parentNode.insertBefore(cn, node);
22474 node.parentNode.removeChild(node);
22475 this.iterateChildren(node, this.cleanWord);
22479 if (node.className.length) {
22481 var cn = node.className.split(/\W+/);
22483 Roo.each(cn, function(cls) {
22484 if (cls.match(/Mso[a-zA-Z]+/)) {
22489 node.className = cna.length ? cna.join(' ') : '';
22491 node.removeAttribute("class");
22495 if (node.hasAttribute("lang")) {
22496 node.removeAttribute("lang");
22499 if (node.hasAttribute("style")) {
22501 var styles = node.getAttribute("style").split(";");
22503 Roo.each(styles, function(s) {
22504 if (!s.match(/:/)) {
22507 var kv = s.split(":");
22508 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22511 // what ever is left... we allow.
22514 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22515 if (!nstyle.length) {
22516 node.removeAttribute('style');
22519 this.iterateChildren(node, this.cleanWord);
22525 * iterateChildren of a Node, calling fn each time, using this as the scole..
22526 * @param {DomNode} node node to iterate children of.
22527 * @param {Function} fn method of this class to call on each item.
22529 iterateChildren : function(node, fn)
22531 if (!node.childNodes.length) {
22534 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22535 fn.call(this, node.childNodes[i])
22541 * cleanTableWidths.
22543 * Quite often pasting from word etc.. results in tables with column and widths.
22544 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22547 cleanTableWidths : function(node)
22552 this.cleanTableWidths(this.doc.body);
22557 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22560 Roo.log(node.tagName);
22561 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22562 this.iterateChildren(node, this.cleanTableWidths);
22565 if (node.hasAttribute('width')) {
22566 node.removeAttribute('width');
22570 if (node.hasAttribute("style")) {
22573 var styles = node.getAttribute("style").split(";");
22575 Roo.each(styles, function(s) {
22576 if (!s.match(/:/)) {
22579 var kv = s.split(":");
22580 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22583 // what ever is left... we allow.
22586 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22587 if (!nstyle.length) {
22588 node.removeAttribute('style');
22592 this.iterateChildren(node, this.cleanTableWidths);
22600 domToHTML : function(currentElement, depth, nopadtext) {
22602 depth = depth || 0;
22603 nopadtext = nopadtext || false;
22605 if (!currentElement) {
22606 return this.domToHTML(this.doc.body);
22609 //Roo.log(currentElement);
22611 var allText = false;
22612 var nodeName = currentElement.nodeName;
22613 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22615 if (nodeName == '#text') {
22617 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22622 if (nodeName != 'BODY') {
22625 // Prints the node tagName, such as <A>, <IMG>, etc
22628 for(i = 0; i < currentElement.attributes.length;i++) {
22630 var aname = currentElement.attributes.item(i).name;
22631 if (!currentElement.attributes.item(i).value.length) {
22634 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22637 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22646 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22649 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22654 // Traverse the tree
22656 var currentElementChild = currentElement.childNodes.item(i);
22657 var allText = true;
22658 var innerHTML = '';
22660 while (currentElementChild) {
22661 // Formatting code (indent the tree so it looks nice on the screen)
22662 var nopad = nopadtext;
22663 if (lastnode == 'SPAN') {
22667 if (currentElementChild.nodeName == '#text') {
22668 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22669 toadd = nopadtext ? toadd : toadd.trim();
22670 if (!nopad && toadd.length > 80) {
22671 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22673 innerHTML += toadd;
22676 currentElementChild = currentElement.childNodes.item(i);
22682 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22684 // Recursively traverse the tree structure of the child node
22685 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22686 lastnode = currentElementChild.nodeName;
22688 currentElementChild=currentElement.childNodes.item(i);
22694 // The remaining code is mostly for formatting the tree
22695 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22700 ret+= "</"+tagName+">";
22706 applyBlacklists : function()
22708 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22709 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22713 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22714 if (b.indexOf(tag) > -1) {
22717 this.white.push(tag);
22721 Roo.each(w, function(tag) {
22722 if (b.indexOf(tag) > -1) {
22725 if (this.white.indexOf(tag) > -1) {
22728 this.white.push(tag);
22733 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22734 if (w.indexOf(tag) > -1) {
22737 this.black.push(tag);
22741 Roo.each(b, function(tag) {
22742 if (w.indexOf(tag) > -1) {
22745 if (this.black.indexOf(tag) > -1) {
22748 this.black.push(tag);
22753 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22754 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22758 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22759 if (b.indexOf(tag) > -1) {
22762 this.cwhite.push(tag);
22766 Roo.each(w, function(tag) {
22767 if (b.indexOf(tag) > -1) {
22770 if (this.cwhite.indexOf(tag) > -1) {
22773 this.cwhite.push(tag);
22778 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22779 if (w.indexOf(tag) > -1) {
22782 this.cblack.push(tag);
22786 Roo.each(b, function(tag) {
22787 if (w.indexOf(tag) > -1) {
22790 if (this.cblack.indexOf(tag) > -1) {
22793 this.cblack.push(tag);
22798 setStylesheets : function(stylesheets)
22800 if(typeof(stylesheets) == 'string'){
22801 Roo.get(this.iframe.contentDocument.head).createChild({
22803 rel : 'stylesheet',
22812 Roo.each(stylesheets, function(s) {
22817 Roo.get(_this.iframe.contentDocument.head).createChild({
22819 rel : 'stylesheet',
22828 removeStylesheets : function()
22832 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22837 setStyle : function(style)
22839 Roo.get(this.iframe.contentDocument.head).createChild({
22848 // hide stuff that is not compatible
22862 * @event specialkey
22866 * @cfg {String} fieldClass @hide
22869 * @cfg {String} focusClass @hide
22872 * @cfg {String} autoCreate @hide
22875 * @cfg {String} inputType @hide
22878 * @cfg {String} invalidClass @hide
22881 * @cfg {String} invalidText @hide
22884 * @cfg {String} msgFx @hide
22887 * @cfg {String} validateOnBlur @hide
22891 Roo.HtmlEditorCore.white = [
22892 'area', 'br', 'img', 'input', 'hr', 'wbr',
22894 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22895 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22896 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22897 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22898 'table', 'ul', 'xmp',
22900 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22903 'dir', 'menu', 'ol', 'ul', 'dl',
22909 Roo.HtmlEditorCore.black = [
22910 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22912 'base', 'basefont', 'bgsound', 'blink', 'body',
22913 'frame', 'frameset', 'head', 'html', 'ilayer',
22914 'iframe', 'layer', 'link', 'meta', 'object',
22915 'script', 'style' ,'title', 'xml' // clean later..
22917 Roo.HtmlEditorCore.clean = [
22918 'script', 'style', 'title', 'xml'
22920 Roo.HtmlEditorCore.remove = [
22925 Roo.HtmlEditorCore.ablack = [
22929 Roo.HtmlEditorCore.aclean = [
22930 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22934 Roo.HtmlEditorCore.pwhite= [
22935 'http', 'https', 'mailto'
22938 // white listed style attributes.
22939 Roo.HtmlEditorCore.cwhite= [
22940 // 'text-align', /// default is to allow most things..
22946 // black listed style attributes.
22947 Roo.HtmlEditorCore.cblack= [
22948 // 'font-size' -- this can be set by the project
22952 Roo.HtmlEditorCore.swapCodes =[
22971 * @class Roo.bootstrap.HtmlEditor
22972 * @extends Roo.bootstrap.TextArea
22973 * Bootstrap HtmlEditor class
22976 * Create a new HtmlEditor
22977 * @param {Object} config The config object
22980 Roo.bootstrap.HtmlEditor = function(config){
22981 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22982 if (!this.toolbars) {
22983 this.toolbars = [];
22986 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22989 * @event initialize
22990 * Fires when the editor is fully initialized (including the iframe)
22991 * @param {HtmlEditor} this
22996 * Fires when the editor is first receives the focus. Any insertion must wait
22997 * until after this event.
22998 * @param {HtmlEditor} this
23002 * @event beforesync
23003 * Fires before the textarea is updated with content from the editor iframe. Return false
23004 * to cancel the sync.
23005 * @param {HtmlEditor} this
23006 * @param {String} html
23010 * @event beforepush
23011 * Fires before the iframe editor is updated with content from the textarea. Return false
23012 * to cancel the push.
23013 * @param {HtmlEditor} this
23014 * @param {String} html
23019 * Fires when the textarea is updated with content from the editor iframe.
23020 * @param {HtmlEditor} this
23021 * @param {String} html
23026 * Fires when the iframe editor is updated with content from the textarea.
23027 * @param {HtmlEditor} this
23028 * @param {String} html
23032 * @event editmodechange
23033 * Fires when the editor switches edit modes
23034 * @param {HtmlEditor} this
23035 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23037 editmodechange: true,
23039 * @event editorevent
23040 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23041 * @param {HtmlEditor} this
23045 * @event firstfocus
23046 * Fires when on first focus - needed by toolbars..
23047 * @param {HtmlEditor} this
23052 * Auto save the htmlEditor value as a file into Events
23053 * @param {HtmlEditor} this
23057 * @event savedpreview
23058 * preview the saved version of htmlEditor
23059 * @param {HtmlEditor} this
23066 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23070 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23075 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23080 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23085 * @cfg {Number} height (in pixels)
23089 * @cfg {Number} width (in pixels)
23094 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23097 stylesheets: false,
23102 // private properties
23103 validationEvent : false,
23105 initialized : false,
23108 onFocus : Roo.emptyFn,
23110 hideMode:'offsets',
23112 tbContainer : false,
23116 toolbarContainer :function() {
23117 return this.wrap.select('.x-html-editor-tb',true).first();
23121 * Protected method that will not generally be called directly. It
23122 * is called when the editor creates its toolbar. Override this method if you need to
23123 * add custom toolbar buttons.
23124 * @param {HtmlEditor} editor
23126 createToolbar : function(){
23127 Roo.log('renewing');
23128 Roo.log("create toolbars");
23130 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23131 this.toolbars[0].render(this.toolbarContainer());
23135 // if (!editor.toolbars || !editor.toolbars.length) {
23136 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23139 // for (var i =0 ; i < editor.toolbars.length;i++) {
23140 // editor.toolbars[i] = Roo.factory(
23141 // typeof(editor.toolbars[i]) == 'string' ?
23142 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23143 // Roo.bootstrap.HtmlEditor);
23144 // editor.toolbars[i].init(editor);
23150 onRender : function(ct, position)
23152 // Roo.log("Call onRender: " + this.xtype);
23154 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23156 this.wrap = this.inputEl().wrap({
23157 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23160 this.editorcore.onRender(ct, position);
23162 if (this.resizable) {
23163 this.resizeEl = new Roo.Resizable(this.wrap, {
23167 minHeight : this.height,
23168 height: this.height,
23169 handles : this.resizable,
23172 resize : function(r, w, h) {
23173 _t.onResize(w,h); // -something
23179 this.createToolbar(this);
23182 if(!this.width && this.resizable){
23183 this.setSize(this.wrap.getSize());
23185 if (this.resizeEl) {
23186 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23187 // should trigger onReize..
23193 onResize : function(w, h)
23195 Roo.log('resize: ' +w + ',' + h );
23196 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23200 if(this.inputEl() ){
23201 if(typeof w == 'number'){
23202 var aw = w - this.wrap.getFrameWidth('lr');
23203 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23206 if(typeof h == 'number'){
23207 var tbh = -11; // fixme it needs to tool bar size!
23208 for (var i =0; i < this.toolbars.length;i++) {
23209 // fixme - ask toolbars for heights?
23210 tbh += this.toolbars[i].el.getHeight();
23211 //if (this.toolbars[i].footer) {
23212 // tbh += this.toolbars[i].footer.el.getHeight();
23220 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23221 ah -= 5; // knock a few pixes off for look..
23222 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23226 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23227 this.editorcore.onResize(ew,eh);
23232 * Toggles the editor between standard and source edit mode.
23233 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23235 toggleSourceEdit : function(sourceEditMode)
23237 this.editorcore.toggleSourceEdit(sourceEditMode);
23239 if(this.editorcore.sourceEditMode){
23240 Roo.log('editor - showing textarea');
23243 // Roo.log(this.syncValue());
23245 this.inputEl().removeClass(['hide', 'x-hidden']);
23246 this.inputEl().dom.removeAttribute('tabIndex');
23247 this.inputEl().focus();
23249 Roo.log('editor - hiding textarea');
23251 // Roo.log(this.pushValue());
23254 this.inputEl().addClass(['hide', 'x-hidden']);
23255 this.inputEl().dom.setAttribute('tabIndex', -1);
23256 //this.deferFocus();
23259 if(this.resizable){
23260 this.setSize(this.wrap.getSize());
23263 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23266 // private (for BoxComponent)
23267 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23269 // private (for BoxComponent)
23270 getResizeEl : function(){
23274 // private (for BoxComponent)
23275 getPositionEl : function(){
23280 initEvents : function(){
23281 this.originalValue = this.getValue();
23285 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23288 // markInvalid : Roo.emptyFn,
23290 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23293 // clearInvalid : Roo.emptyFn,
23295 setValue : function(v){
23296 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23297 this.editorcore.pushValue();
23302 deferFocus : function(){
23303 this.focus.defer(10, this);
23307 focus : function(){
23308 this.editorcore.focus();
23314 onDestroy : function(){
23320 for (var i =0; i < this.toolbars.length;i++) {
23321 // fixme - ask toolbars for heights?
23322 this.toolbars[i].onDestroy();
23325 this.wrap.dom.innerHTML = '';
23326 this.wrap.remove();
23331 onFirstFocus : function(){
23332 //Roo.log("onFirstFocus");
23333 this.editorcore.onFirstFocus();
23334 for (var i =0; i < this.toolbars.length;i++) {
23335 this.toolbars[i].onFirstFocus();
23341 syncValue : function()
23343 this.editorcore.syncValue();
23346 pushValue : function()
23348 this.editorcore.pushValue();
23352 // hide stuff that is not compatible
23366 * @event specialkey
23370 * @cfg {String} fieldClass @hide
23373 * @cfg {String} focusClass @hide
23376 * @cfg {String} autoCreate @hide
23379 * @cfg {String} inputType @hide
23382 * @cfg {String} invalidClass @hide
23385 * @cfg {String} invalidText @hide
23388 * @cfg {String} msgFx @hide
23391 * @cfg {String} validateOnBlur @hide
23400 Roo.namespace('Roo.bootstrap.htmleditor');
23402 * @class Roo.bootstrap.HtmlEditorToolbar1
23407 new Roo.bootstrap.HtmlEditor({
23410 new Roo.bootstrap.HtmlEditorToolbar1({
23411 disable : { fonts: 1 , format: 1, ..., ... , ...],
23417 * @cfg {Object} disable List of elements to disable..
23418 * @cfg {Array} btns List of additional buttons.
23422 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23425 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23428 Roo.apply(this, config);
23430 // default disabled, based on 'good practice'..
23431 this.disable = this.disable || {};
23432 Roo.applyIf(this.disable, {
23435 specialElements : true
23437 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23439 this.editor = config.editor;
23440 this.editorcore = config.editor.editorcore;
23442 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23444 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23445 // dont call parent... till later.
23447 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23452 editorcore : false,
23457 "h1","h2","h3","h4","h5","h6",
23459 "abbr", "acronym", "address", "cite", "samp", "var",
23463 onRender : function(ct, position)
23465 // Roo.log("Call onRender: " + this.xtype);
23467 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23469 this.el.dom.style.marginBottom = '0';
23471 var editorcore = this.editorcore;
23472 var editor= this.editor;
23475 var btn = function(id,cmd , toggle, handler, html){
23477 var event = toggle ? 'toggle' : 'click';
23482 xns: Roo.bootstrap,
23485 enableToggle:toggle !== false,
23487 pressed : toggle ? false : null,
23490 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23491 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23497 // var cb_box = function...
23502 xns: Roo.bootstrap,
23503 glyphicon : 'font',
23507 xns: Roo.bootstrap,
23511 Roo.each(this.formats, function(f) {
23512 style.menu.items.push({
23514 xns: Roo.bootstrap,
23515 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23520 editorcore.insertTag(this.tagname);
23527 children.push(style);
23529 btn('bold',false,true);
23530 btn('italic',false,true);
23531 btn('align-left', 'justifyleft',true);
23532 btn('align-center', 'justifycenter',true);
23533 btn('align-right' , 'justifyright',true);
23534 btn('link', false, false, function(btn) {
23535 //Roo.log("create link?");
23536 var url = prompt(this.createLinkText, this.defaultLinkValue);
23537 if(url && url != 'http:/'+'/'){
23538 this.editorcore.relayCmd('createlink', url);
23541 btn('list','insertunorderedlist',true);
23542 btn('pencil', false,true, function(btn){
23544 this.toggleSourceEdit(btn.pressed);
23547 if (this.editor.btns.length > 0) {
23548 for (var i = 0; i<this.editor.btns.length; i++) {
23549 children.push(this.editor.btns[i]);
23557 xns: Roo.bootstrap,
23562 xns: Roo.bootstrap,
23567 cog.menu.items.push({
23569 xns: Roo.bootstrap,
23570 html : Clean styles,
23575 editorcore.insertTag(this.tagname);
23584 this.xtype = 'NavSimplebar';
23586 for(var i=0;i< children.length;i++) {
23588 this.buttons.add(this.addxtypeChild(children[i]));
23592 editor.on('editorevent', this.updateToolbar, this);
23594 onBtnClick : function(id)
23596 this.editorcore.relayCmd(id);
23597 this.editorcore.focus();
23601 * Protected method that will not generally be called directly. It triggers
23602 * a toolbar update by reading the markup state of the current selection in the editor.
23604 updateToolbar: function(){
23606 if(!this.editorcore.activated){
23607 this.editor.onFirstFocus(); // is this neeed?
23611 var btns = this.buttons;
23612 var doc = this.editorcore.doc;
23613 btns.get('bold').setActive(doc.queryCommandState('bold'));
23614 btns.get('italic').setActive(doc.queryCommandState('italic'));
23615 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23617 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23618 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23619 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23621 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23622 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23625 var ans = this.editorcore.getAllAncestors();
23626 if (this.formatCombo) {
23629 var store = this.formatCombo.store;
23630 this.formatCombo.setValue("");
23631 for (var i =0; i < ans.length;i++) {
23632 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23634 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23642 // hides menus... - so this cant be on a menu...
23643 Roo.bootstrap.MenuMgr.hideAll();
23645 Roo.bootstrap.MenuMgr.hideAll();
23646 //this.editorsyncValue();
23648 onFirstFocus: function() {
23649 this.buttons.each(function(item){
23653 toggleSourceEdit : function(sourceEditMode){
23656 if(sourceEditMode){
23657 Roo.log("disabling buttons");
23658 this.buttons.each( function(item){
23659 if(item.cmd != 'pencil'){
23665 Roo.log("enabling buttons");
23666 if(this.editorcore.initialized){
23667 this.buttons.each( function(item){
23673 Roo.log("calling toggole on editor");
23674 // tell the editor that it's been pressed..
23675 this.editor.toggleSourceEdit(sourceEditMode);
23685 * @class Roo.bootstrap.Table.AbstractSelectionModel
23686 * @extends Roo.util.Observable
23687 * Abstract base class for grid SelectionModels. It provides the interface that should be
23688 * implemented by descendant classes. This class should not be directly instantiated.
23691 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23692 this.locked = false;
23693 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23697 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23698 /** @ignore Called by the grid automatically. Do not call directly. */
23699 init : function(grid){
23705 * Locks the selections.
23708 this.locked = true;
23712 * Unlocks the selections.
23714 unlock : function(){
23715 this.locked = false;
23719 * Returns true if the selections are locked.
23720 * @return {Boolean}
23722 isLocked : function(){
23723 return this.locked;
23727 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23728 * @class Roo.bootstrap.Table.RowSelectionModel
23729 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23730 * It supports multiple selections and keyboard selection/navigation.
23732 * @param {Object} config
23735 Roo.bootstrap.Table.RowSelectionModel = function(config){
23736 Roo.apply(this, config);
23737 this.selections = new Roo.util.MixedCollection(false, function(o){
23742 this.lastActive = false;
23746 * @event selectionchange
23747 * Fires when the selection changes
23748 * @param {SelectionModel} this
23750 "selectionchange" : true,
23752 * @event afterselectionchange
23753 * Fires after the selection changes (eg. by key press or clicking)
23754 * @param {SelectionModel} this
23756 "afterselectionchange" : true,
23758 * @event beforerowselect
23759 * Fires when a row is selected being selected, return false to cancel.
23760 * @param {SelectionModel} this
23761 * @param {Number} rowIndex The selected index
23762 * @param {Boolean} keepExisting False if other selections will be cleared
23764 "beforerowselect" : true,
23767 * Fires when a row is selected.
23768 * @param {SelectionModel} this
23769 * @param {Number} rowIndex The selected index
23770 * @param {Roo.data.Record} r The record
23772 "rowselect" : true,
23774 * @event rowdeselect
23775 * Fires when a row is deselected.
23776 * @param {SelectionModel} this
23777 * @param {Number} rowIndex The selected index
23779 "rowdeselect" : true
23781 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23782 this.locked = false;
23785 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23787 * @cfg {Boolean} singleSelect
23788 * True to allow selection of only one row at a time (defaults to false)
23790 singleSelect : false,
23793 initEvents : function()
23796 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23797 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23798 //}else{ // allow click to work like normal
23799 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23801 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23802 this.grid.on("rowclick", this.handleMouseDown, this);
23804 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23805 "up" : function(e){
23807 this.selectPrevious(e.shiftKey);
23808 }else if(this.last !== false && this.lastActive !== false){
23809 var last = this.last;
23810 this.selectRange(this.last, this.lastActive-1);
23811 this.grid.getView().focusRow(this.lastActive);
23812 if(last !== false){
23816 this.selectFirstRow();
23818 this.fireEvent("afterselectionchange", this);
23820 "down" : function(e){
23822 this.selectNext(e.shiftKey);
23823 }else if(this.last !== false && this.lastActive !== false){
23824 var last = this.last;
23825 this.selectRange(this.last, this.lastActive+1);
23826 this.grid.getView().focusRow(this.lastActive);
23827 if(last !== false){
23831 this.selectFirstRow();
23833 this.fireEvent("afterselectionchange", this);
23837 this.grid.store.on('load', function(){
23838 this.selections.clear();
23841 var view = this.grid.view;
23842 view.on("refresh", this.onRefresh, this);
23843 view.on("rowupdated", this.onRowUpdated, this);
23844 view.on("rowremoved", this.onRemove, this);
23849 onRefresh : function()
23851 var ds = this.grid.store, i, v = this.grid.view;
23852 var s = this.selections;
23853 s.each(function(r){
23854 if((i = ds.indexOfId(r.id)) != -1){
23863 onRemove : function(v, index, r){
23864 this.selections.remove(r);
23868 onRowUpdated : function(v, index, r){
23869 if(this.isSelected(r)){
23870 v.onRowSelect(index);
23876 * @param {Array} records The records to select
23877 * @param {Boolean} keepExisting (optional) True to keep existing selections
23879 selectRecords : function(records, keepExisting)
23882 this.clearSelections();
23884 var ds = this.grid.store;
23885 for(var i = 0, len = records.length; i < len; i++){
23886 this.selectRow(ds.indexOf(records[i]), true);
23891 * Gets the number of selected rows.
23894 getCount : function(){
23895 return this.selections.length;
23899 * Selects the first row in the grid.
23901 selectFirstRow : function(){
23906 * Select the last row.
23907 * @param {Boolean} keepExisting (optional) True to keep existing selections
23909 selectLastRow : function(keepExisting){
23910 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23911 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23915 * Selects the row immediately following the last selected row.
23916 * @param {Boolean} keepExisting (optional) True to keep existing selections
23918 selectNext : function(keepExisting)
23920 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23921 this.selectRow(this.last+1, keepExisting);
23922 this.grid.getView().focusRow(this.last);
23927 * Selects the row that precedes the last selected row.
23928 * @param {Boolean} keepExisting (optional) True to keep existing selections
23930 selectPrevious : function(keepExisting){
23932 this.selectRow(this.last-1, keepExisting);
23933 this.grid.getView().focusRow(this.last);
23938 * Returns the selected records
23939 * @return {Array} Array of selected records
23941 getSelections : function(){
23942 return [].concat(this.selections.items);
23946 * Returns the first selected record.
23949 getSelected : function(){
23950 return this.selections.itemAt(0);
23955 * Clears all selections.
23957 clearSelections : function(fast)
23963 var ds = this.grid.store;
23964 var s = this.selections;
23965 s.each(function(r){
23966 this.deselectRow(ds.indexOfId(r.id));
23970 this.selections.clear();
23977 * Selects all rows.
23979 selectAll : function(){
23983 this.selections.clear();
23984 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23985 this.selectRow(i, true);
23990 * Returns True if there is a selection.
23991 * @return {Boolean}
23993 hasSelection : function(){
23994 return this.selections.length > 0;
23998 * Returns True if the specified row is selected.
23999 * @param {Number/Record} record The record or index of the record to check
24000 * @return {Boolean}
24002 isSelected : function(index){
24003 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24004 return (r && this.selections.key(r.id) ? true : false);
24008 * Returns True if the specified record id is selected.
24009 * @param {String} id The id of record to check
24010 * @return {Boolean}
24012 isIdSelected : function(id){
24013 return (this.selections.key(id) ? true : false);
24018 handleMouseDBClick : function(e, t){
24022 handleMouseDown : function(e, t)
24024 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24025 if(this.isLocked() || rowIndex < 0 ){
24028 if(e.shiftKey && this.last !== false){
24029 var last = this.last;
24030 this.selectRange(last, rowIndex, e.ctrlKey);
24031 this.last = last; // reset the last
24035 var isSelected = this.isSelected(rowIndex);
24036 //Roo.log("select row:" + rowIndex);
24038 this.deselectRow(rowIndex);
24040 this.selectRow(rowIndex, true);
24044 if(e.button !== 0 && isSelected){
24045 alert('rowIndex 2: ' + rowIndex);
24046 view.focusRow(rowIndex);
24047 }else if(e.ctrlKey && isSelected){
24048 this.deselectRow(rowIndex);
24049 }else if(!isSelected){
24050 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24051 view.focusRow(rowIndex);
24055 this.fireEvent("afterselectionchange", this);
24058 handleDragableRowClick : function(grid, rowIndex, e)
24060 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24061 this.selectRow(rowIndex, false);
24062 grid.view.focusRow(rowIndex);
24063 this.fireEvent("afterselectionchange", this);
24068 * Selects multiple rows.
24069 * @param {Array} rows Array of the indexes of the row to select
24070 * @param {Boolean} keepExisting (optional) True to keep existing selections
24072 selectRows : function(rows, keepExisting){
24074 this.clearSelections();
24076 for(var i = 0, len = rows.length; i < len; i++){
24077 this.selectRow(rows[i], true);
24082 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24083 * @param {Number} startRow The index of the first row in the range
24084 * @param {Number} endRow The index of the last row in the range
24085 * @param {Boolean} keepExisting (optional) True to retain existing selections
24087 selectRange : function(startRow, endRow, keepExisting){
24092 this.clearSelections();
24094 if(startRow <= endRow){
24095 for(var i = startRow; i <= endRow; i++){
24096 this.selectRow(i, true);
24099 for(var i = startRow; i >= endRow; i--){
24100 this.selectRow(i, true);
24106 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24107 * @param {Number} startRow The index of the first row in the range
24108 * @param {Number} endRow The index of the last row in the range
24110 deselectRange : function(startRow, endRow, preventViewNotify){
24114 for(var i = startRow; i <= endRow; i++){
24115 this.deselectRow(i, preventViewNotify);
24121 * @param {Number} row The index of the row to select
24122 * @param {Boolean} keepExisting (optional) True to keep existing selections
24124 selectRow : function(index, keepExisting, preventViewNotify)
24126 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24129 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24130 if(!keepExisting || this.singleSelect){
24131 this.clearSelections();
24134 var r = this.grid.store.getAt(index);
24135 //console.log('selectRow - record id :' + r.id);
24137 this.selections.add(r);
24138 this.last = this.lastActive = index;
24139 if(!preventViewNotify){
24140 var proxy = new Roo.Element(
24141 this.grid.getRowDom(index)
24143 proxy.addClass('bg-info info');
24145 this.fireEvent("rowselect", this, index, r);
24146 this.fireEvent("selectionchange", this);
24152 * @param {Number} row The index of the row to deselect
24154 deselectRow : function(index, preventViewNotify)
24159 if(this.last == index){
24162 if(this.lastActive == index){
24163 this.lastActive = false;
24166 var r = this.grid.store.getAt(index);
24171 this.selections.remove(r);
24172 //.console.log('deselectRow - record id :' + r.id);
24173 if(!preventViewNotify){
24175 var proxy = new Roo.Element(
24176 this.grid.getRowDom(index)
24178 proxy.removeClass('bg-info info');
24180 this.fireEvent("rowdeselect", this, index);
24181 this.fireEvent("selectionchange", this);
24185 restoreLast : function(){
24187 this.last = this._last;
24192 acceptsNav : function(row, col, cm){
24193 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24197 onEditorKey : function(field, e){
24198 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24203 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24205 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24207 }else if(k == e.ENTER && !e.ctrlKey){
24211 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24213 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24215 }else if(k == e.ESC){
24219 g.startEditing(newCell[0], newCell[1]);
24225 * Ext JS Library 1.1.1
24226 * Copyright(c) 2006-2007, Ext JS, LLC.
24228 * Originally Released Under LGPL - original licence link has changed is not relivant.
24231 * <script type="text/javascript">
24235 * @class Roo.bootstrap.PagingToolbar
24236 * @extends Roo.bootstrap.NavSimplebar
24237 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24239 * Create a new PagingToolbar
24240 * @param {Object} config The config object
24241 * @param {Roo.data.Store} store
24243 Roo.bootstrap.PagingToolbar = function(config)
24245 // old args format still supported... - xtype is prefered..
24246 // created from xtype...
24248 this.ds = config.dataSource;
24250 if (config.store && !this.ds) {
24251 this.store= Roo.factory(config.store, Roo.data);
24252 this.ds = this.store;
24253 this.ds.xmodule = this.xmodule || false;
24256 this.toolbarItems = [];
24257 if (config.items) {
24258 this.toolbarItems = config.items;
24261 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24266 this.bind(this.ds);
24269 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24273 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24275 * @cfg {Roo.data.Store} dataSource
24276 * The underlying data store providing the paged data
24279 * @cfg {String/HTMLElement/Element} container
24280 * container The id or element that will contain the toolbar
24283 * @cfg {Boolean} displayInfo
24284 * True to display the displayMsg (defaults to false)
24287 * @cfg {Number} pageSize
24288 * The number of records to display per page (defaults to 20)
24292 * @cfg {String} displayMsg
24293 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24295 displayMsg : 'Displaying {0} - {1} of {2}',
24297 * @cfg {String} emptyMsg
24298 * The message to display when no records are found (defaults to "No data to display")
24300 emptyMsg : 'No data to display',
24302 * Customizable piece of the default paging text (defaults to "Page")
24305 beforePageText : "Page",
24307 * Customizable piece of the default paging text (defaults to "of %0")
24310 afterPageText : "of {0}",
24312 * Customizable piece of the default paging text (defaults to "First Page")
24315 firstText : "First Page",
24317 * Customizable piece of the default paging text (defaults to "Previous Page")
24320 prevText : "Previous Page",
24322 * Customizable piece of the default paging text (defaults to "Next Page")
24325 nextText : "Next Page",
24327 * Customizable piece of the default paging text (defaults to "Last Page")
24330 lastText : "Last Page",
24332 * Customizable piece of the default paging text (defaults to "Refresh")
24335 refreshText : "Refresh",
24339 onRender : function(ct, position)
24341 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24342 this.navgroup.parentId = this.id;
24343 this.navgroup.onRender(this.el, null);
24344 // add the buttons to the navgroup
24346 if(this.displayInfo){
24347 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24348 this.displayEl = this.el.select('.x-paging-info', true).first();
24349 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24350 // this.displayEl = navel.el.select('span',true).first();
24356 Roo.each(_this.buttons, function(e){ // this might need to use render????
24357 Roo.factory(e).onRender(_this.el, null);
24361 Roo.each(_this.toolbarItems, function(e) {
24362 _this.navgroup.addItem(e);
24366 this.first = this.navgroup.addItem({
24367 tooltip: this.firstText,
24369 icon : 'fa fa-backward',
24371 preventDefault: true,
24372 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24375 this.prev = this.navgroup.addItem({
24376 tooltip: this.prevText,
24378 icon : 'fa fa-step-backward',
24380 preventDefault: true,
24381 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24383 //this.addSeparator();
24386 var field = this.navgroup.addItem( {
24388 cls : 'x-paging-position',
24390 html : this.beforePageText +
24391 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24392 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24395 this.field = field.el.select('input', true).first();
24396 this.field.on("keydown", this.onPagingKeydown, this);
24397 this.field.on("focus", function(){this.dom.select();});
24400 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24401 //this.field.setHeight(18);
24402 //this.addSeparator();
24403 this.next = this.navgroup.addItem({
24404 tooltip: this.nextText,
24406 html : ' <i class="fa fa-step-forward">',
24408 preventDefault: true,
24409 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24411 this.last = this.navgroup.addItem({
24412 tooltip: this.lastText,
24413 icon : 'fa fa-forward',
24416 preventDefault: true,
24417 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24419 //this.addSeparator();
24420 this.loading = this.navgroup.addItem({
24421 tooltip: this.refreshText,
24422 icon: 'fa fa-refresh',
24423 preventDefault: true,
24424 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24430 updateInfo : function(){
24431 if(this.displayEl){
24432 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24433 var msg = count == 0 ?
24437 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24439 this.displayEl.update(msg);
24444 onLoad : function(ds, r, o)
24446 this.cursor = o.params ? o.params.start : 0;
24447 var d = this.getPageData(),
24452 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24453 this.field.dom.value = ap;
24454 this.first.setDisabled(ap == 1);
24455 this.prev.setDisabled(ap == 1);
24456 this.next.setDisabled(ap == ps);
24457 this.last.setDisabled(ap == ps);
24458 this.loading.enable();
24463 getPageData : function(){
24464 var total = this.ds.getTotalCount();
24467 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24468 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24473 onLoadError : function(){
24474 this.loading.enable();
24478 onPagingKeydown : function(e){
24479 var k = e.getKey();
24480 var d = this.getPageData();
24482 var v = this.field.dom.value, pageNum;
24483 if(!v || isNaN(pageNum = parseInt(v, 10))){
24484 this.field.dom.value = d.activePage;
24487 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24488 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24491 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))
24493 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24494 this.field.dom.value = pageNum;
24495 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24498 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24500 var v = this.field.dom.value, pageNum;
24501 var increment = (e.shiftKey) ? 10 : 1;
24502 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24505 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24506 this.field.dom.value = d.activePage;
24509 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24511 this.field.dom.value = parseInt(v, 10) + increment;
24512 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24513 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24520 beforeLoad : function(){
24522 this.loading.disable();
24527 onClick : function(which){
24536 ds.load({params:{start: 0, limit: this.pageSize}});
24539 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24542 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24545 var total = ds.getTotalCount();
24546 var extra = total % this.pageSize;
24547 var lastStart = extra ? (total - extra) : total-this.pageSize;
24548 ds.load({params:{start: lastStart, limit: this.pageSize}});
24551 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24557 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24558 * @param {Roo.data.Store} store The data store to unbind
24560 unbind : function(ds){
24561 ds.un("beforeload", this.beforeLoad, this);
24562 ds.un("load", this.onLoad, this);
24563 ds.un("loadexception", this.onLoadError, this);
24564 ds.un("remove", this.updateInfo, this);
24565 ds.un("add", this.updateInfo, this);
24566 this.ds = undefined;
24570 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24571 * @param {Roo.data.Store} store The data store to bind
24573 bind : function(ds){
24574 ds.on("beforeload", this.beforeLoad, this);
24575 ds.on("load", this.onLoad, this);
24576 ds.on("loadexception", this.onLoadError, this);
24577 ds.on("remove", this.updateInfo, this);
24578 ds.on("add", this.updateInfo, this);
24589 * @class Roo.bootstrap.MessageBar
24590 * @extends Roo.bootstrap.Component
24591 * Bootstrap MessageBar class
24592 * @cfg {String} html contents of the MessageBar
24593 * @cfg {String} weight (info | success | warning | danger) default info
24594 * @cfg {String} beforeClass insert the bar before the given class
24595 * @cfg {Boolean} closable (true | false) default false
24596 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24599 * Create a new Element
24600 * @param {Object} config The config object
24603 Roo.bootstrap.MessageBar = function(config){
24604 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24607 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24613 beforeClass: 'bootstrap-sticky-wrap',
24615 getAutoCreate : function(){
24619 cls: 'alert alert-dismissable alert-' + this.weight,
24624 html: this.html || ''
24630 cfg.cls += ' alert-messages-fixed';
24644 onRender : function(ct, position)
24646 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24649 var cfg = Roo.apply({}, this.getAutoCreate());
24653 cfg.cls += ' ' + this.cls;
24656 cfg.style = this.style;
24658 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24660 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24663 this.el.select('>button.close').on('click', this.hide, this);
24669 if (!this.rendered) {
24675 this.fireEvent('show', this);
24681 if (!this.rendered) {
24687 this.fireEvent('hide', this);
24690 update : function()
24692 // var e = this.el.dom.firstChild;
24694 // if(this.closable){
24695 // e = e.nextSibling;
24698 // e.data = this.html || '';
24700 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24716 * @class Roo.bootstrap.Graph
24717 * @extends Roo.bootstrap.Component
24718 * Bootstrap Graph class
24722 @cfg {String} graphtype bar | vbar | pie
24723 @cfg {number} g_x coodinator | centre x (pie)
24724 @cfg {number} g_y coodinator | centre y (pie)
24725 @cfg {number} g_r radius (pie)
24726 @cfg {number} g_height height of the chart (respected by all elements in the set)
24727 @cfg {number} g_width width of the chart (respected by all elements in the set)
24728 @cfg {Object} title The title of the chart
24731 -opts (object) options for the chart
24733 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24734 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24736 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.
24737 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24739 o stretch (boolean)
24741 -opts (object) options for the pie
24744 o startAngle (number)
24745 o endAngle (number)
24749 * Create a new Input
24750 * @param {Object} config The config object
24753 Roo.bootstrap.Graph = function(config){
24754 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24760 * The img click event for the img.
24761 * @param {Roo.EventObject} e
24767 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24778 //g_colors: this.colors,
24785 getAutoCreate : function(){
24796 onRender : function(ct,position){
24799 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24801 if (typeof(Raphael) == 'undefined') {
24802 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24806 this.raphael = Raphael(this.el.dom);
24808 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24809 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24810 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24811 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24813 r.text(160, 10, "Single Series Chart").attr(txtattr);
24814 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24815 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24816 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24818 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24819 r.barchart(330, 10, 300, 220, data1);
24820 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24821 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24824 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24825 // r.barchart(30, 30, 560, 250, xdata, {
24826 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24827 // axis : "0 0 1 1",
24828 // axisxlabels : xdata
24829 // //yvalues : cols,
24832 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24834 // this.load(null,xdata,{
24835 // axis : "0 0 1 1",
24836 // axisxlabels : xdata
24841 load : function(graphtype,xdata,opts)
24843 this.raphael.clear();
24845 graphtype = this.graphtype;
24850 var r = this.raphael,
24851 fin = function () {
24852 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24854 fout = function () {
24855 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24857 pfin = function() {
24858 this.sector.stop();
24859 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24862 this.label[0].stop();
24863 this.label[0].attr({ r: 7.5 });
24864 this.label[1].attr({ "font-weight": 800 });
24867 pfout = function() {
24868 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24871 this.label[0].animate({ r: 5 }, 500, "bounce");
24872 this.label[1].attr({ "font-weight": 400 });
24878 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24881 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24884 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24885 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24887 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24894 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24899 setTitle: function(o)
24904 initEvents: function() {
24907 this.el.on('click', this.onClick, this);
24911 onClick : function(e)
24913 Roo.log('img onclick');
24914 this.fireEvent('click', this, e);
24926 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24929 * @class Roo.bootstrap.dash.NumberBox
24930 * @extends Roo.bootstrap.Component
24931 * Bootstrap NumberBox class
24932 * @cfg {String} headline Box headline
24933 * @cfg {String} content Box content
24934 * @cfg {String} icon Box icon
24935 * @cfg {String} footer Footer text
24936 * @cfg {String} fhref Footer href
24939 * Create a new NumberBox
24940 * @param {Object} config The config object
24944 Roo.bootstrap.dash.NumberBox = function(config){
24945 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24949 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24958 getAutoCreate : function(){
24962 cls : 'small-box ',
24970 cls : 'roo-headline',
24971 html : this.headline
24975 cls : 'roo-content',
24976 html : this.content
24990 cls : 'ion ' + this.icon
24999 cls : 'small-box-footer',
25000 href : this.fhref || '#',
25004 cfg.cn.push(footer);
25011 onRender : function(ct,position){
25012 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25019 setHeadline: function (value)
25021 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25024 setFooter: function (value, href)
25026 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25029 this.el.select('a.small-box-footer',true).first().attr('href', href);
25034 setContent: function (value)
25036 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25039 initEvents: function()
25053 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25056 * @class Roo.bootstrap.dash.TabBox
25057 * @extends Roo.bootstrap.Component
25058 * Bootstrap TabBox class
25059 * @cfg {String} title Title of the TabBox
25060 * @cfg {String} icon Icon of the TabBox
25061 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25062 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25065 * Create a new TabBox
25066 * @param {Object} config The config object
25070 Roo.bootstrap.dash.TabBox = function(config){
25071 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25076 * When a pane is added
25077 * @param {Roo.bootstrap.dash.TabPane} pane
25081 * @event activatepane
25082 * When a pane is activated
25083 * @param {Roo.bootstrap.dash.TabPane} pane
25085 "activatepane" : true
25093 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25098 tabScrollable : false,
25100 getChildContainer : function()
25102 return this.el.select('.tab-content', true).first();
25105 getAutoCreate : function(){
25109 cls: 'pull-left header',
25117 cls: 'fa ' + this.icon
25123 cls: 'nav nav-tabs pull-right',
25129 if(this.tabScrollable){
25136 cls: 'nav nav-tabs pull-right',
25147 cls: 'nav-tabs-custom',
25152 cls: 'tab-content no-padding',
25160 initEvents : function()
25162 //Roo.log('add add pane handler');
25163 this.on('addpane', this.onAddPane, this);
25166 * Updates the box title
25167 * @param {String} html to set the title to.
25169 setTitle : function(value)
25171 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25173 onAddPane : function(pane)
25175 this.panes.push(pane);
25176 //Roo.log('addpane');
25178 // tabs are rendere left to right..
25179 if(!this.showtabs){
25183 var ctr = this.el.select('.nav-tabs', true).first();
25186 var existing = ctr.select('.nav-tab',true);
25187 var qty = existing.getCount();;
25190 var tab = ctr.createChild({
25192 cls : 'nav-tab' + (qty ? '' : ' active'),
25200 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25203 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25205 pane.el.addClass('active');
25210 onTabClick : function(ev,un,ob,pane)
25212 //Roo.log('tab - prev default');
25213 ev.preventDefault();
25216 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25217 pane.tab.addClass('active');
25218 //Roo.log(pane.title);
25219 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25220 // technically we should have a deactivate event.. but maybe add later.
25221 // and it should not de-activate the selected tab...
25222 this.fireEvent('activatepane', pane);
25223 pane.el.addClass('active');
25224 pane.fireEvent('activate');
25229 getActivePane : function()
25232 Roo.each(this.panes, function(p) {
25233 if(p.el.hasClass('active')){
25254 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25256 * @class Roo.bootstrap.TabPane
25257 * @extends Roo.bootstrap.Component
25258 * Bootstrap TabPane class
25259 * @cfg {Boolean} active (false | true) Default false
25260 * @cfg {String} title title of panel
25264 * Create a new TabPane
25265 * @param {Object} config The config object
25268 Roo.bootstrap.dash.TabPane = function(config){
25269 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25275 * When a pane is activated
25276 * @param {Roo.bootstrap.dash.TabPane} pane
25283 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25288 // the tabBox that this is attached to.
25291 getAutoCreate : function()
25299 cfg.cls += ' active';
25304 initEvents : function()
25306 //Roo.log('trigger add pane handler');
25307 this.parent().fireEvent('addpane', this)
25311 * Updates the tab title
25312 * @param {String} html to set the title to.
25314 setTitle: function(str)
25320 this.tab.select('a', true).first().dom.innerHTML = str;
25337 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25340 * @class Roo.bootstrap.menu.Menu
25341 * @extends Roo.bootstrap.Component
25342 * Bootstrap Menu class - container for Menu
25343 * @cfg {String} html Text of the menu
25344 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25345 * @cfg {String} icon Font awesome icon
25346 * @cfg {String} pos Menu align to (top | bottom) default bottom
25350 * Create a new Menu
25351 * @param {Object} config The config object
25355 Roo.bootstrap.menu.Menu = function(config){
25356 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25360 * @event beforeshow
25361 * Fires before this menu is displayed
25362 * @param {Roo.bootstrap.menu.Menu} this
25366 * @event beforehide
25367 * Fires before this menu is hidden
25368 * @param {Roo.bootstrap.menu.Menu} this
25373 * Fires after this menu is displayed
25374 * @param {Roo.bootstrap.menu.Menu} this
25379 * Fires after this menu is hidden
25380 * @param {Roo.bootstrap.menu.Menu} this
25385 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25386 * @param {Roo.bootstrap.menu.Menu} this
25387 * @param {Roo.EventObject} e
25394 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25398 weight : 'default',
25403 getChildContainer : function() {
25404 if(this.isSubMenu){
25408 return this.el.select('ul.dropdown-menu', true).first();
25411 getAutoCreate : function()
25416 cls : 'roo-menu-text',
25424 cls : 'fa ' + this.icon
25435 cls : 'dropdown-button btn btn-' + this.weight,
25440 cls : 'dropdown-toggle btn btn-' + this.weight,
25450 cls : 'dropdown-menu'
25456 if(this.pos == 'top'){
25457 cfg.cls += ' dropup';
25460 if(this.isSubMenu){
25463 cls : 'dropdown-menu'
25470 onRender : function(ct, position)
25472 this.isSubMenu = ct.hasClass('dropdown-submenu');
25474 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25477 initEvents : function()
25479 if(this.isSubMenu){
25483 this.hidden = true;
25485 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25486 this.triggerEl.on('click', this.onTriggerPress, this);
25488 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25489 this.buttonEl.on('click', this.onClick, this);
25495 if(this.isSubMenu){
25499 return this.el.select('ul.dropdown-menu', true).first();
25502 onClick : function(e)
25504 this.fireEvent("click", this, e);
25507 onTriggerPress : function(e)
25509 if (this.isVisible()) {
25516 isVisible : function(){
25517 return !this.hidden;
25522 this.fireEvent("beforeshow", this);
25524 this.hidden = false;
25525 this.el.addClass('open');
25527 Roo.get(document).on("mouseup", this.onMouseUp, this);
25529 this.fireEvent("show", this);
25536 this.fireEvent("beforehide", this);
25538 this.hidden = true;
25539 this.el.removeClass('open');
25541 Roo.get(document).un("mouseup", this.onMouseUp);
25543 this.fireEvent("hide", this);
25546 onMouseUp : function()
25560 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25563 * @class Roo.bootstrap.menu.Item
25564 * @extends Roo.bootstrap.Component
25565 * Bootstrap MenuItem class
25566 * @cfg {Boolean} submenu (true | false) default false
25567 * @cfg {String} html text of the item
25568 * @cfg {String} href the link
25569 * @cfg {Boolean} disable (true | false) default false
25570 * @cfg {Boolean} preventDefault (true | false) default true
25571 * @cfg {String} icon Font awesome icon
25572 * @cfg {String} pos Submenu align to (left | right) default right
25576 * Create a new Item
25577 * @param {Object} config The config object
25581 Roo.bootstrap.menu.Item = function(config){
25582 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25586 * Fires when the mouse is hovering over this menu
25587 * @param {Roo.bootstrap.menu.Item} this
25588 * @param {Roo.EventObject} e
25593 * Fires when the mouse exits this menu
25594 * @param {Roo.bootstrap.menu.Item} this
25595 * @param {Roo.EventObject} e
25601 * The raw click event for the entire grid.
25602 * @param {Roo.EventObject} e
25608 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25613 preventDefault: true,
25618 getAutoCreate : function()
25623 cls : 'roo-menu-item-text',
25631 cls : 'fa ' + this.icon
25640 href : this.href || '#',
25647 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25651 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25653 if(this.pos == 'left'){
25654 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25661 initEvents : function()
25663 this.el.on('mouseover', this.onMouseOver, this);
25664 this.el.on('mouseout', this.onMouseOut, this);
25666 this.el.select('a', true).first().on('click', this.onClick, this);
25670 onClick : function(e)
25672 if(this.preventDefault){
25673 e.preventDefault();
25676 this.fireEvent("click", this, e);
25679 onMouseOver : function(e)
25681 if(this.submenu && this.pos == 'left'){
25682 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25685 this.fireEvent("mouseover", this, e);
25688 onMouseOut : function(e)
25690 this.fireEvent("mouseout", this, e);
25702 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25705 * @class Roo.bootstrap.menu.Separator
25706 * @extends Roo.bootstrap.Component
25707 * Bootstrap Separator class
25710 * Create a new Separator
25711 * @param {Object} config The config object
25715 Roo.bootstrap.menu.Separator = function(config){
25716 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25719 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25721 getAutoCreate : function(){
25742 * @class Roo.bootstrap.Tooltip
25743 * Bootstrap Tooltip class
25744 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25745 * to determine which dom element triggers the tooltip.
25747 * It needs to add support for additional attributes like tooltip-position
25750 * Create a new Toolti
25751 * @param {Object} config The config object
25754 Roo.bootstrap.Tooltip = function(config){
25755 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25757 this.alignment = Roo.bootstrap.Tooltip.alignment;
25759 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25760 this.alignment = config.alignment;
25765 Roo.apply(Roo.bootstrap.Tooltip, {
25767 * @function init initialize tooltip monitoring.
25771 currentTip : false,
25772 currentRegion : false,
25778 Roo.get(document).on('mouseover', this.enter ,this);
25779 Roo.get(document).on('mouseout', this.leave, this);
25782 this.currentTip = new Roo.bootstrap.Tooltip();
25785 enter : function(ev)
25787 var dom = ev.getTarget();
25789 //Roo.log(['enter',dom]);
25790 var el = Roo.fly(dom);
25791 if (this.currentEl) {
25793 //Roo.log(this.currentEl);
25794 //Roo.log(this.currentEl.contains(dom));
25795 if (this.currentEl == el) {
25798 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25804 if (this.currentTip.el) {
25805 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25809 if(!el || el.dom == document){
25815 // you can not look for children, as if el is the body.. then everythign is the child..
25816 if (!el.attr('tooltip')) { //
25817 if (!el.select("[tooltip]").elements.length) {
25820 // is the mouse over this child...?
25821 bindEl = el.select("[tooltip]").first();
25822 var xy = ev.getXY();
25823 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25824 //Roo.log("not in region.");
25827 //Roo.log("child element over..");
25830 this.currentEl = bindEl;
25831 this.currentTip.bind(bindEl);
25832 this.currentRegion = Roo.lib.Region.getRegion(dom);
25833 this.currentTip.enter();
25836 leave : function(ev)
25838 var dom = ev.getTarget();
25839 //Roo.log(['leave',dom]);
25840 if (!this.currentEl) {
25845 if (dom != this.currentEl.dom) {
25848 var xy = ev.getXY();
25849 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25852 // only activate leave if mouse cursor is outside... bounding box..
25857 if (this.currentTip) {
25858 this.currentTip.leave();
25860 //Roo.log('clear currentEl');
25861 this.currentEl = false;
25866 'left' : ['r-l', [-2,0], 'right'],
25867 'right' : ['l-r', [2,0], 'left'],
25868 'bottom' : ['t-b', [0,2], 'top'],
25869 'top' : [ 'b-t', [0,-2], 'bottom']
25875 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25880 delay : null, // can be { show : 300 , hide: 500}
25884 hoverState : null, //???
25886 placement : 'bottom',
25890 getAutoCreate : function(){
25897 cls : 'tooltip-arrow'
25900 cls : 'tooltip-inner'
25907 bind : function(el)
25913 enter : function () {
25915 if (this.timeout != null) {
25916 clearTimeout(this.timeout);
25919 this.hoverState = 'in';
25920 //Roo.log("enter - show");
25921 if (!this.delay || !this.delay.show) {
25926 this.timeout = setTimeout(function () {
25927 if (_t.hoverState == 'in') {
25930 }, this.delay.show);
25934 clearTimeout(this.timeout);
25936 this.hoverState = 'out';
25937 if (!this.delay || !this.delay.hide) {
25943 this.timeout = setTimeout(function () {
25944 //Roo.log("leave - timeout");
25946 if (_t.hoverState == 'out') {
25948 Roo.bootstrap.Tooltip.currentEl = false;
25953 show : function (msg)
25956 this.render(document.body);
25959 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25961 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25963 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25965 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25967 var placement = typeof this.placement == 'function' ?
25968 this.placement.call(this, this.el, on_el) :
25971 var autoToken = /\s?auto?\s?/i;
25972 var autoPlace = autoToken.test(placement);
25974 placement = placement.replace(autoToken, '') || 'top';
25978 //this.el.setXY([0,0]);
25980 //this.el.dom.style.display='block';
25982 //this.el.appendTo(on_el);
25984 var p = this.getPosition();
25985 var box = this.el.getBox();
25991 var align = this.alignment[placement];
25993 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25995 if(placement == 'top' || placement == 'bottom'){
25997 placement = 'right';
26000 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26001 placement = 'left';
26004 var scroll = Roo.select('body', true).first().getScroll();
26006 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26012 this.el.alignTo(this.bindEl, align[0],align[1]);
26013 //var arrow = this.el.select('.arrow',true).first();
26014 //arrow.set(align[2],
26016 this.el.addClass(placement);
26018 this.el.addClass('in fade');
26020 this.hoverState = null;
26022 if (this.el.hasClass('fade')) {
26033 //this.el.setXY([0,0]);
26034 this.el.removeClass('in');
26050 * @class Roo.bootstrap.LocationPicker
26051 * @extends Roo.bootstrap.Component
26052 * Bootstrap LocationPicker class
26053 * @cfg {Number} latitude Position when init default 0
26054 * @cfg {Number} longitude Position when init default 0
26055 * @cfg {Number} zoom default 15
26056 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26057 * @cfg {Boolean} mapTypeControl default false
26058 * @cfg {Boolean} disableDoubleClickZoom default false
26059 * @cfg {Boolean} scrollwheel default true
26060 * @cfg {Boolean} streetViewControl default false
26061 * @cfg {Number} radius default 0
26062 * @cfg {String} locationName
26063 * @cfg {Boolean} draggable default true
26064 * @cfg {Boolean} enableAutocomplete default false
26065 * @cfg {Boolean} enableReverseGeocode default true
26066 * @cfg {String} markerTitle
26069 * Create a new LocationPicker
26070 * @param {Object} config The config object
26074 Roo.bootstrap.LocationPicker = function(config){
26076 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26081 * Fires when the picker initialized.
26082 * @param {Roo.bootstrap.LocationPicker} this
26083 * @param {Google Location} location
26087 * @event positionchanged
26088 * Fires when the picker position changed.
26089 * @param {Roo.bootstrap.LocationPicker} this
26090 * @param {Google Location} location
26092 positionchanged : true,
26095 * Fires when the map resize.
26096 * @param {Roo.bootstrap.LocationPicker} this
26101 * Fires when the map show.
26102 * @param {Roo.bootstrap.LocationPicker} this
26107 * Fires when the map hide.
26108 * @param {Roo.bootstrap.LocationPicker} this
26113 * Fires when click the map.
26114 * @param {Roo.bootstrap.LocationPicker} this
26115 * @param {Map event} e
26119 * @event mapRightClick
26120 * Fires when right click the map.
26121 * @param {Roo.bootstrap.LocationPicker} this
26122 * @param {Map event} e
26124 mapRightClick : true,
26126 * @event markerClick
26127 * Fires when click the marker.
26128 * @param {Roo.bootstrap.LocationPicker} this
26129 * @param {Map event} e
26131 markerClick : true,
26133 * @event markerRightClick
26134 * Fires when right click the marker.
26135 * @param {Roo.bootstrap.LocationPicker} this
26136 * @param {Map event} e
26138 markerRightClick : true,
26140 * @event OverlayViewDraw
26141 * Fires when OverlayView Draw
26142 * @param {Roo.bootstrap.LocationPicker} this
26144 OverlayViewDraw : true,
26146 * @event OverlayViewOnAdd
26147 * Fires when OverlayView Draw
26148 * @param {Roo.bootstrap.LocationPicker} this
26150 OverlayViewOnAdd : true,
26152 * @event OverlayViewOnRemove
26153 * Fires when OverlayView Draw
26154 * @param {Roo.bootstrap.LocationPicker} this
26156 OverlayViewOnRemove : true,
26158 * @event OverlayViewShow
26159 * Fires when OverlayView Draw
26160 * @param {Roo.bootstrap.LocationPicker} this
26161 * @param {Pixel} cpx
26163 OverlayViewShow : true,
26165 * @event OverlayViewHide
26166 * Fires when OverlayView Draw
26167 * @param {Roo.bootstrap.LocationPicker} this
26169 OverlayViewHide : true,
26171 * @event loadexception
26172 * Fires when load google lib failed.
26173 * @param {Roo.bootstrap.LocationPicker} this
26175 loadexception : true
26180 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26182 gMapContext: false,
26188 mapTypeControl: false,
26189 disableDoubleClickZoom: false,
26191 streetViewControl: false,
26195 enableAutocomplete: false,
26196 enableReverseGeocode: true,
26199 getAutoCreate: function()
26204 cls: 'roo-location-picker'
26210 initEvents: function(ct, position)
26212 if(!this.el.getWidth() || this.isApplied()){
26216 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26221 initial: function()
26223 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26224 this.fireEvent('loadexception', this);
26228 if(!this.mapTypeId){
26229 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26232 this.gMapContext = this.GMapContext();
26234 this.initOverlayView();
26236 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26240 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26241 _this.setPosition(_this.gMapContext.marker.position);
26244 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26245 _this.fireEvent('mapClick', this, event);
26249 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26250 _this.fireEvent('mapRightClick', this, event);
26254 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26255 _this.fireEvent('markerClick', this, event);
26259 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26260 _this.fireEvent('markerRightClick', this, event);
26264 this.setPosition(this.gMapContext.location);
26266 this.fireEvent('initial', this, this.gMapContext.location);
26269 initOverlayView: function()
26273 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26277 _this.fireEvent('OverlayViewDraw', _this);
26282 _this.fireEvent('OverlayViewOnAdd', _this);
26285 onRemove: function()
26287 _this.fireEvent('OverlayViewOnRemove', _this);
26290 show: function(cpx)
26292 _this.fireEvent('OverlayViewShow', _this, cpx);
26297 _this.fireEvent('OverlayViewHide', _this);
26303 fromLatLngToContainerPixel: function(event)
26305 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26308 isApplied: function()
26310 return this.getGmapContext() == false ? false : true;
26313 getGmapContext: function()
26315 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26318 GMapContext: function()
26320 var position = new google.maps.LatLng(this.latitude, this.longitude);
26322 var _map = new google.maps.Map(this.el.dom, {
26325 mapTypeId: this.mapTypeId,
26326 mapTypeControl: this.mapTypeControl,
26327 disableDoubleClickZoom: this.disableDoubleClickZoom,
26328 scrollwheel: this.scrollwheel,
26329 streetViewControl: this.streetViewControl,
26330 locationName: this.locationName,
26331 draggable: this.draggable,
26332 enableAutocomplete: this.enableAutocomplete,
26333 enableReverseGeocode: this.enableReverseGeocode
26336 var _marker = new google.maps.Marker({
26337 position: position,
26339 title: this.markerTitle,
26340 draggable: this.draggable
26347 location: position,
26348 radius: this.radius,
26349 locationName: this.locationName,
26350 addressComponents: {
26351 formatted_address: null,
26352 addressLine1: null,
26353 addressLine2: null,
26355 streetNumber: null,
26359 stateOrProvince: null
26362 domContainer: this.el.dom,
26363 geodecoder: new google.maps.Geocoder()
26367 drawCircle: function(center, radius, options)
26369 if (this.gMapContext.circle != null) {
26370 this.gMapContext.circle.setMap(null);
26374 options = Roo.apply({}, options, {
26375 strokeColor: "#0000FF",
26376 strokeOpacity: .35,
26378 fillColor: "#0000FF",
26382 options.map = this.gMapContext.map;
26383 options.radius = radius;
26384 options.center = center;
26385 this.gMapContext.circle = new google.maps.Circle(options);
26386 return this.gMapContext.circle;
26392 setPosition: function(location)
26394 this.gMapContext.location = location;
26395 this.gMapContext.marker.setPosition(location);
26396 this.gMapContext.map.panTo(location);
26397 this.drawCircle(location, this.gMapContext.radius, {});
26401 if (this.gMapContext.settings.enableReverseGeocode) {
26402 this.gMapContext.geodecoder.geocode({
26403 latLng: this.gMapContext.location
26404 }, function(results, status) {
26406 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26407 _this.gMapContext.locationName = results[0].formatted_address;
26408 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26410 _this.fireEvent('positionchanged', this, location);
26417 this.fireEvent('positionchanged', this, location);
26422 google.maps.event.trigger(this.gMapContext.map, "resize");
26424 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26426 this.fireEvent('resize', this);
26429 setPositionByLatLng: function(latitude, longitude)
26431 this.setPosition(new google.maps.LatLng(latitude, longitude));
26434 getCurrentPosition: function()
26437 latitude: this.gMapContext.location.lat(),
26438 longitude: this.gMapContext.location.lng()
26442 getAddressName: function()
26444 return this.gMapContext.locationName;
26447 getAddressComponents: function()
26449 return this.gMapContext.addressComponents;
26452 address_component_from_google_geocode: function(address_components)
26456 for (var i = 0; i < address_components.length; i++) {
26457 var component = address_components[i];
26458 if (component.types.indexOf("postal_code") >= 0) {
26459 result.postalCode = component.short_name;
26460 } else if (component.types.indexOf("street_number") >= 0) {
26461 result.streetNumber = component.short_name;
26462 } else if (component.types.indexOf("route") >= 0) {
26463 result.streetName = component.short_name;
26464 } else if (component.types.indexOf("neighborhood") >= 0) {
26465 result.city = component.short_name;
26466 } else if (component.types.indexOf("locality") >= 0) {
26467 result.city = component.short_name;
26468 } else if (component.types.indexOf("sublocality") >= 0) {
26469 result.district = component.short_name;
26470 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26471 result.stateOrProvince = component.short_name;
26472 } else if (component.types.indexOf("country") >= 0) {
26473 result.country = component.short_name;
26477 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26478 result.addressLine2 = "";
26482 setZoomLevel: function(zoom)
26484 this.gMapContext.map.setZoom(zoom);
26497 this.fireEvent('show', this);
26508 this.fireEvent('hide', this);
26513 Roo.apply(Roo.bootstrap.LocationPicker, {
26515 OverlayView : function(map, options)
26517 options = options || {};
26531 * @class Roo.bootstrap.Alert
26532 * @extends Roo.bootstrap.Component
26533 * Bootstrap Alert class
26534 * @cfg {String} title The title of alert
26535 * @cfg {String} html The content of alert
26536 * @cfg {String} weight ( success | info | warning | danger )
26537 * @cfg {String} faicon font-awesomeicon
26540 * Create a new alert
26541 * @param {Object} config The config object
26545 Roo.bootstrap.Alert = function(config){
26546 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26550 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26557 getAutoCreate : function()
26566 cls : 'roo-alert-icon'
26571 cls : 'roo-alert-title',
26576 cls : 'roo-alert-text',
26583 cfg.cn[0].cls += ' fa ' + this.faicon;
26587 cfg.cls += ' alert-' + this.weight;
26593 initEvents: function()
26595 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26598 setTitle : function(str)
26600 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26603 setText : function(str)
26605 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26608 setWeight : function(weight)
26611 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26614 this.weight = weight;
26616 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26619 setIcon : function(icon)
26622 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26625 this.faicon = icon;
26627 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26648 * @class Roo.bootstrap.UploadCropbox
26649 * @extends Roo.bootstrap.Component
26650 * Bootstrap UploadCropbox class
26651 * @cfg {String} emptyText show when image has been loaded
26652 * @cfg {String} rotateNotify show when image too small to rotate
26653 * @cfg {Number} errorTimeout default 3000
26654 * @cfg {Number} minWidth default 300
26655 * @cfg {Number} minHeight default 300
26656 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26657 * @cfg {Boolean} isDocument (true|false) default false
26658 * @cfg {String} url action url
26659 * @cfg {String} paramName default 'imageUpload'
26660 * @cfg {String} method default POST
26661 * @cfg {Boolean} loadMask (true|false) default true
26662 * @cfg {Boolean} loadingText default 'Loading...'
26665 * Create a new UploadCropbox
26666 * @param {Object} config The config object
26669 Roo.bootstrap.UploadCropbox = function(config){
26670 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26674 * @event beforeselectfile
26675 * Fire before select file
26676 * @param {Roo.bootstrap.UploadCropbox} this
26678 "beforeselectfile" : true,
26681 * Fire after initEvent
26682 * @param {Roo.bootstrap.UploadCropbox} this
26687 * Fire after initEvent
26688 * @param {Roo.bootstrap.UploadCropbox} this
26689 * @param {String} data
26694 * Fire when preparing the file data
26695 * @param {Roo.bootstrap.UploadCropbox} this
26696 * @param {Object} file
26701 * Fire when get exception
26702 * @param {Roo.bootstrap.UploadCropbox} this
26703 * @param {XMLHttpRequest} xhr
26705 "exception" : true,
26707 * @event beforeloadcanvas
26708 * Fire before load the canvas
26709 * @param {Roo.bootstrap.UploadCropbox} this
26710 * @param {String} src
26712 "beforeloadcanvas" : true,
26715 * Fire when trash image
26716 * @param {Roo.bootstrap.UploadCropbox} this
26721 * Fire when download the image
26722 * @param {Roo.bootstrap.UploadCropbox} this
26726 * @event footerbuttonclick
26727 * Fire when footerbuttonclick
26728 * @param {Roo.bootstrap.UploadCropbox} this
26729 * @param {String} type
26731 "footerbuttonclick" : true,
26735 * @param {Roo.bootstrap.UploadCropbox} this
26740 * Fire when rotate the image
26741 * @param {Roo.bootstrap.UploadCropbox} this
26742 * @param {String} pos
26747 * Fire when inspect the file
26748 * @param {Roo.bootstrap.UploadCropbox} this
26749 * @param {Object} file
26754 * Fire when xhr upload the file
26755 * @param {Roo.bootstrap.UploadCropbox} this
26756 * @param {Object} data
26761 * Fire when arrange the file data
26762 * @param {Roo.bootstrap.UploadCropbox} this
26763 * @param {Object} formData
26768 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26771 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26773 emptyText : 'Click to upload image',
26774 rotateNotify : 'Image is too small to rotate',
26775 errorTimeout : 3000,
26789 cropType : 'image/jpeg',
26791 canvasLoaded : false,
26792 isDocument : false,
26794 paramName : 'imageUpload',
26796 loadingText : 'Loading...',
26799 getAutoCreate : function()
26803 cls : 'roo-upload-cropbox',
26807 cls : 'roo-upload-cropbox-selector',
26812 cls : 'roo-upload-cropbox-body',
26813 style : 'cursor:pointer',
26817 cls : 'roo-upload-cropbox-preview'
26821 cls : 'roo-upload-cropbox-thumb'
26825 cls : 'roo-upload-cropbox-empty-notify',
26826 html : this.emptyText
26830 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26831 html : this.rotateNotify
26837 cls : 'roo-upload-cropbox-footer',
26840 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26850 onRender : function(ct, position)
26852 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26854 if (this.buttons.length) {
26856 Roo.each(this.buttons, function(bb) {
26858 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26860 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26866 this.maskEl = this.el;
26870 initEvents : function()
26872 this.urlAPI = (window.createObjectURL && window) ||
26873 (window.URL && URL.revokeObjectURL && URL) ||
26874 (window.webkitURL && webkitURL);
26876 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26877 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26879 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26880 this.selectorEl.hide();
26882 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26883 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26885 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26886 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26887 this.thumbEl.hide();
26889 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26890 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26892 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26893 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26894 this.errorEl.hide();
26896 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26897 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26898 this.footerEl.hide();
26900 this.setThumbBoxSize();
26906 this.fireEvent('initial', this);
26913 window.addEventListener("resize", function() { _this.resize(); } );
26915 this.bodyEl.on('click', this.beforeSelectFile, this);
26918 this.bodyEl.on('touchstart', this.onTouchStart, this);
26919 this.bodyEl.on('touchmove', this.onTouchMove, this);
26920 this.bodyEl.on('touchend', this.onTouchEnd, this);
26924 this.bodyEl.on('mousedown', this.onMouseDown, this);
26925 this.bodyEl.on('mousemove', this.onMouseMove, this);
26926 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26927 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26928 Roo.get(document).on('mouseup', this.onMouseUp, this);
26931 this.selectorEl.on('change', this.onFileSelected, this);
26937 this.baseScale = 1;
26939 this.baseRotate = 1;
26940 this.dragable = false;
26941 this.pinching = false;
26944 this.cropData = false;
26945 this.notifyEl.dom.innerHTML = this.emptyText;
26947 this.selectorEl.dom.value = '';
26951 resize : function()
26953 if(this.fireEvent('resize', this) != false){
26954 this.setThumbBoxPosition();
26955 this.setCanvasPosition();
26959 onFooterButtonClick : function(e, el, o, type)
26962 case 'rotate-left' :
26963 this.onRotateLeft(e);
26965 case 'rotate-right' :
26966 this.onRotateRight(e);
26969 this.beforeSelectFile(e);
26984 this.fireEvent('footerbuttonclick', this, type);
26987 beforeSelectFile : function(e)
26989 e.preventDefault();
26991 if(this.fireEvent('beforeselectfile', this) != false){
26992 this.selectorEl.dom.click();
26996 onFileSelected : function(e)
26998 e.preventDefault();
27000 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27004 var file = this.selectorEl.dom.files[0];
27006 if(this.fireEvent('inspect', this, file) != false){
27007 this.prepare(file);
27012 trash : function(e)
27014 this.fireEvent('trash', this);
27017 download : function(e)
27019 this.fireEvent('download', this);
27022 loadCanvas : function(src)
27024 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27028 this.imageEl = document.createElement('img');
27032 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27034 this.imageEl.src = src;
27038 onLoadCanvas : function()
27040 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27041 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27043 this.bodyEl.un('click', this.beforeSelectFile, this);
27045 this.notifyEl.hide();
27046 this.thumbEl.show();
27047 this.footerEl.show();
27049 this.baseRotateLevel();
27051 if(this.isDocument){
27052 this.setThumbBoxSize();
27055 this.setThumbBoxPosition();
27057 this.baseScaleLevel();
27063 this.canvasLoaded = true;
27066 this.maskEl.unmask();
27071 setCanvasPosition : function()
27073 if(!this.canvasEl){
27077 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27078 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27080 this.previewEl.setLeft(pw);
27081 this.previewEl.setTop(ph);
27085 onMouseDown : function(e)
27089 this.dragable = true;
27090 this.pinching = false;
27092 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27093 this.dragable = false;
27097 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27098 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27102 onMouseMove : function(e)
27106 if(!this.canvasLoaded){
27110 if (!this.dragable){
27114 var minX = Math.ceil(this.thumbEl.getLeft(true));
27115 var minY = Math.ceil(this.thumbEl.getTop(true));
27117 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27118 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27120 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27121 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27123 x = x - this.mouseX;
27124 y = y - this.mouseY;
27126 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27127 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27129 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27130 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27132 this.previewEl.setLeft(bgX);
27133 this.previewEl.setTop(bgY);
27135 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27136 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27139 onMouseUp : function(e)
27143 this.dragable = false;
27146 onMouseWheel : function(e)
27150 this.startScale = this.scale;
27152 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27154 if(!this.zoomable()){
27155 this.scale = this.startScale;
27164 zoomable : function()
27166 var minScale = this.thumbEl.getWidth() / this.minWidth;
27168 if(this.minWidth < this.minHeight){
27169 minScale = this.thumbEl.getHeight() / this.minHeight;
27172 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27173 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27177 (this.rotate == 0 || this.rotate == 180) &&
27179 width > this.imageEl.OriginWidth ||
27180 height > this.imageEl.OriginHeight ||
27181 (width < this.minWidth && height < this.minHeight)
27189 (this.rotate == 90 || this.rotate == 270) &&
27191 width > this.imageEl.OriginWidth ||
27192 height > this.imageEl.OriginHeight ||
27193 (width < this.minHeight && height < this.minWidth)
27200 !this.isDocument &&
27201 (this.rotate == 0 || this.rotate == 180) &&
27203 width < this.minWidth ||
27204 width > this.imageEl.OriginWidth ||
27205 height < this.minHeight ||
27206 height > this.imageEl.OriginHeight
27213 !this.isDocument &&
27214 (this.rotate == 90 || this.rotate == 270) &&
27216 width < this.minHeight ||
27217 width > this.imageEl.OriginWidth ||
27218 height < this.minWidth ||
27219 height > this.imageEl.OriginHeight
27229 onRotateLeft : function(e)
27231 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27233 var minScale = this.thumbEl.getWidth() / this.minWidth;
27235 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27236 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27238 this.startScale = this.scale;
27240 while (this.getScaleLevel() < minScale){
27242 this.scale = this.scale + 1;
27244 if(!this.zoomable()){
27249 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27250 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27255 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27262 this.scale = this.startScale;
27264 this.onRotateFail();
27269 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27271 if(this.isDocument){
27272 this.setThumbBoxSize();
27273 this.setThumbBoxPosition();
27274 this.setCanvasPosition();
27279 this.fireEvent('rotate', this, 'left');
27283 onRotateRight : function(e)
27285 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27287 var minScale = this.thumbEl.getWidth() / this.minWidth;
27289 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27290 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27292 this.startScale = this.scale;
27294 while (this.getScaleLevel() < minScale){
27296 this.scale = this.scale + 1;
27298 if(!this.zoomable()){
27303 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27304 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27309 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27316 this.scale = this.startScale;
27318 this.onRotateFail();
27323 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27325 if(this.isDocument){
27326 this.setThumbBoxSize();
27327 this.setThumbBoxPosition();
27328 this.setCanvasPosition();
27333 this.fireEvent('rotate', this, 'right');
27336 onRotateFail : function()
27338 this.errorEl.show(true);
27342 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27347 this.previewEl.dom.innerHTML = '';
27349 var canvasEl = document.createElement("canvas");
27351 var contextEl = canvasEl.getContext("2d");
27353 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27354 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27355 var center = this.imageEl.OriginWidth / 2;
27357 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27358 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27359 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27360 center = this.imageEl.OriginHeight / 2;
27363 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27365 contextEl.translate(center, center);
27366 contextEl.rotate(this.rotate * Math.PI / 180);
27368 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27370 this.canvasEl = document.createElement("canvas");
27372 this.contextEl = this.canvasEl.getContext("2d");
27374 switch (this.rotate) {
27377 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27378 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27380 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27385 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27386 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27388 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27389 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);
27393 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27398 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27399 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27401 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27402 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);
27406 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);
27411 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27412 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27414 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27415 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27419 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);
27426 this.previewEl.appendChild(this.canvasEl);
27428 this.setCanvasPosition();
27433 if(!this.canvasLoaded){
27437 var imageCanvas = document.createElement("canvas");
27439 var imageContext = imageCanvas.getContext("2d");
27441 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27442 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27444 var center = imageCanvas.width / 2;
27446 imageContext.translate(center, center);
27448 imageContext.rotate(this.rotate * Math.PI / 180);
27450 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27452 var canvas = document.createElement("canvas");
27454 var context = canvas.getContext("2d");
27456 canvas.width = this.minWidth;
27457 canvas.height = this.minHeight;
27459 switch (this.rotate) {
27462 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27463 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27465 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27466 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27468 var targetWidth = this.minWidth - 2 * x;
27469 var targetHeight = this.minHeight - 2 * y;
27473 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27474 scale = targetWidth / width;
27477 if(x > 0 && y == 0){
27478 scale = targetHeight / height;
27481 if(x > 0 && y > 0){
27482 scale = targetWidth / width;
27484 if(width < height){
27485 scale = targetHeight / height;
27489 context.scale(scale, scale);
27491 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27492 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27494 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27495 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27497 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27502 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27503 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27505 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27506 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27508 var targetWidth = this.minWidth - 2 * x;
27509 var targetHeight = this.minHeight - 2 * y;
27513 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27514 scale = targetWidth / width;
27517 if(x > 0 && y == 0){
27518 scale = targetHeight / height;
27521 if(x > 0 && y > 0){
27522 scale = targetWidth / width;
27524 if(width < height){
27525 scale = targetHeight / height;
27529 context.scale(scale, scale);
27531 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27532 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27534 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27535 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27537 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27539 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27544 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27545 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27547 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27548 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27550 var targetWidth = this.minWidth - 2 * x;
27551 var targetHeight = this.minHeight - 2 * y;
27555 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27556 scale = targetWidth / width;
27559 if(x > 0 && y == 0){
27560 scale = targetHeight / height;
27563 if(x > 0 && y > 0){
27564 scale = targetWidth / width;
27566 if(width < height){
27567 scale = targetHeight / height;
27571 context.scale(scale, scale);
27573 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27574 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27576 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27577 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27579 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27580 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27582 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27587 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27588 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27590 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27591 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27593 var targetWidth = this.minWidth - 2 * x;
27594 var targetHeight = this.minHeight - 2 * y;
27598 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27599 scale = targetWidth / width;
27602 if(x > 0 && y == 0){
27603 scale = targetHeight / height;
27606 if(x > 0 && y > 0){
27607 scale = targetWidth / width;
27609 if(width < height){
27610 scale = targetHeight / height;
27614 context.scale(scale, scale);
27616 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27617 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27619 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27620 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27622 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27624 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27631 this.cropData = canvas.toDataURL(this.cropType);
27633 if(this.fireEvent('crop', this, this.cropData) !== false){
27634 this.process(this.file, this.cropData);
27641 setThumbBoxSize : function()
27645 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27646 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27647 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27649 this.minWidth = width;
27650 this.minHeight = height;
27652 if(this.rotate == 90 || this.rotate == 270){
27653 this.minWidth = height;
27654 this.minHeight = width;
27659 width = Math.ceil(this.minWidth * height / this.minHeight);
27661 if(this.minWidth > this.minHeight){
27663 height = Math.ceil(this.minHeight * width / this.minWidth);
27666 this.thumbEl.setStyle({
27667 width : width + 'px',
27668 height : height + 'px'
27675 setThumbBoxPosition : function()
27677 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27678 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27680 this.thumbEl.setLeft(x);
27681 this.thumbEl.setTop(y);
27685 baseRotateLevel : function()
27687 this.baseRotate = 1;
27690 typeof(this.exif) != 'undefined' &&
27691 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27692 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27694 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27697 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27701 baseScaleLevel : function()
27705 if(this.isDocument){
27707 if(this.baseRotate == 6 || this.baseRotate == 8){
27709 height = this.thumbEl.getHeight();
27710 this.baseScale = height / this.imageEl.OriginWidth;
27712 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27713 width = this.thumbEl.getWidth();
27714 this.baseScale = width / this.imageEl.OriginHeight;
27720 height = this.thumbEl.getHeight();
27721 this.baseScale = height / this.imageEl.OriginHeight;
27723 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27724 width = this.thumbEl.getWidth();
27725 this.baseScale = width / this.imageEl.OriginWidth;
27731 if(this.baseRotate == 6 || this.baseRotate == 8){
27733 width = this.thumbEl.getHeight();
27734 this.baseScale = width / this.imageEl.OriginHeight;
27736 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27737 height = this.thumbEl.getWidth();
27738 this.baseScale = height / this.imageEl.OriginHeight;
27741 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27742 height = this.thumbEl.getWidth();
27743 this.baseScale = height / this.imageEl.OriginHeight;
27745 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27746 width = this.thumbEl.getHeight();
27747 this.baseScale = width / this.imageEl.OriginWidth;
27754 width = this.thumbEl.getWidth();
27755 this.baseScale = width / this.imageEl.OriginWidth;
27757 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27758 height = this.thumbEl.getHeight();
27759 this.baseScale = height / this.imageEl.OriginHeight;
27762 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27764 height = this.thumbEl.getHeight();
27765 this.baseScale = height / this.imageEl.OriginHeight;
27767 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27768 width = this.thumbEl.getWidth();
27769 this.baseScale = width / this.imageEl.OriginWidth;
27777 getScaleLevel : function()
27779 return this.baseScale * Math.pow(1.1, this.scale);
27782 onTouchStart : function(e)
27784 if(!this.canvasLoaded){
27785 this.beforeSelectFile(e);
27789 var touches = e.browserEvent.touches;
27795 if(touches.length == 1){
27796 this.onMouseDown(e);
27800 if(touches.length != 2){
27806 for(var i = 0, finger; finger = touches[i]; i++){
27807 coords.push(finger.pageX, finger.pageY);
27810 var x = Math.pow(coords[0] - coords[2], 2);
27811 var y = Math.pow(coords[1] - coords[3], 2);
27813 this.startDistance = Math.sqrt(x + y);
27815 this.startScale = this.scale;
27817 this.pinching = true;
27818 this.dragable = false;
27822 onTouchMove : function(e)
27824 if(!this.pinching && !this.dragable){
27828 var touches = e.browserEvent.touches;
27835 this.onMouseMove(e);
27841 for(var i = 0, finger; finger = touches[i]; i++){
27842 coords.push(finger.pageX, finger.pageY);
27845 var x = Math.pow(coords[0] - coords[2], 2);
27846 var y = Math.pow(coords[1] - coords[3], 2);
27848 this.endDistance = Math.sqrt(x + y);
27850 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27852 if(!this.zoomable()){
27853 this.scale = this.startScale;
27861 onTouchEnd : function(e)
27863 this.pinching = false;
27864 this.dragable = false;
27868 process : function(file, crop)
27871 this.maskEl.mask(this.loadingText);
27874 this.xhr = new XMLHttpRequest();
27876 file.xhr = this.xhr;
27878 this.xhr.open(this.method, this.url, true);
27881 "Accept": "application/json",
27882 "Cache-Control": "no-cache",
27883 "X-Requested-With": "XMLHttpRequest"
27886 for (var headerName in headers) {
27887 var headerValue = headers[headerName];
27889 this.xhr.setRequestHeader(headerName, headerValue);
27895 this.xhr.onload = function()
27897 _this.xhrOnLoad(_this.xhr);
27900 this.xhr.onerror = function()
27902 _this.xhrOnError(_this.xhr);
27905 var formData = new FormData();
27907 formData.append('returnHTML', 'NO');
27910 formData.append('crop', crop);
27913 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27914 formData.append(this.paramName, file, file.name);
27917 if(typeof(file.filename) != 'undefined'){
27918 formData.append('filename', file.filename);
27921 if(typeof(file.mimetype) != 'undefined'){
27922 formData.append('mimetype', file.mimetype);
27925 if(this.fireEvent('arrange', this, formData) != false){
27926 this.xhr.send(formData);
27930 xhrOnLoad : function(xhr)
27933 this.maskEl.unmask();
27936 if (xhr.readyState !== 4) {
27937 this.fireEvent('exception', this, xhr);
27941 var response = Roo.decode(xhr.responseText);
27943 if(!response.success){
27944 this.fireEvent('exception', this, xhr);
27948 var response = Roo.decode(xhr.responseText);
27950 this.fireEvent('upload', this, response);
27954 xhrOnError : function()
27957 this.maskEl.unmask();
27960 Roo.log('xhr on error');
27962 var response = Roo.decode(xhr.responseText);
27968 prepare : function(file)
27971 this.maskEl.mask(this.loadingText);
27977 if(typeof(file) === 'string'){
27978 this.loadCanvas(file);
27982 if(!file || !this.urlAPI){
27987 this.cropType = file.type;
27991 if(this.fireEvent('prepare', this, this.file) != false){
27993 var reader = new FileReader();
27995 reader.onload = function (e) {
27996 if (e.target.error) {
27997 Roo.log(e.target.error);
28001 var buffer = e.target.result,
28002 dataView = new DataView(buffer),
28004 maxOffset = dataView.byteLength - 4,
28008 if (dataView.getUint16(0) === 0xffd8) {
28009 while (offset < maxOffset) {
28010 markerBytes = dataView.getUint16(offset);
28012 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28013 markerLength = dataView.getUint16(offset + 2) + 2;
28014 if (offset + markerLength > dataView.byteLength) {
28015 Roo.log('Invalid meta data: Invalid segment size.');
28019 if(markerBytes == 0xffe1){
28020 _this.parseExifData(
28027 offset += markerLength;
28037 var url = _this.urlAPI.createObjectURL(_this.file);
28039 _this.loadCanvas(url);
28044 reader.readAsArrayBuffer(this.file);
28050 parseExifData : function(dataView, offset, length)
28052 var tiffOffset = offset + 10,
28056 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28057 // No Exif data, might be XMP data instead
28061 // Check for the ASCII code for "Exif" (0x45786966):
28062 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28063 // No Exif data, might be XMP data instead
28066 if (tiffOffset + 8 > dataView.byteLength) {
28067 Roo.log('Invalid Exif data: Invalid segment size.');
28070 // Check for the two null bytes:
28071 if (dataView.getUint16(offset + 8) !== 0x0000) {
28072 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28075 // Check the byte alignment:
28076 switch (dataView.getUint16(tiffOffset)) {
28078 littleEndian = true;
28081 littleEndian = false;
28084 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28087 // Check for the TIFF tag marker (0x002A):
28088 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28089 Roo.log('Invalid Exif data: Missing TIFF marker.');
28092 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28093 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28095 this.parseExifTags(
28098 tiffOffset + dirOffset,
28103 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28108 if (dirOffset + 6 > dataView.byteLength) {
28109 Roo.log('Invalid Exif data: Invalid directory offset.');
28112 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28113 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28114 if (dirEndOffset + 4 > dataView.byteLength) {
28115 Roo.log('Invalid Exif data: Invalid directory size.');
28118 for (i = 0; i < tagsNumber; i += 1) {
28122 dirOffset + 2 + 12 * i, // tag offset
28126 // Return the offset to the next directory:
28127 return dataView.getUint32(dirEndOffset, littleEndian);
28130 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28132 var tag = dataView.getUint16(offset, littleEndian);
28134 this.exif[tag] = this.getExifValue(
28138 dataView.getUint16(offset + 2, littleEndian), // tag type
28139 dataView.getUint32(offset + 4, littleEndian), // tag length
28144 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28146 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28155 Roo.log('Invalid Exif data: Invalid tag type.');
28159 tagSize = tagType.size * length;
28160 // Determine if the value is contained in the dataOffset bytes,
28161 // or if the value at the dataOffset is a pointer to the actual data:
28162 dataOffset = tagSize > 4 ?
28163 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28164 if (dataOffset + tagSize > dataView.byteLength) {
28165 Roo.log('Invalid Exif data: Invalid data offset.');
28168 if (length === 1) {
28169 return tagType.getValue(dataView, dataOffset, littleEndian);
28172 for (i = 0; i < length; i += 1) {
28173 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28176 if (tagType.ascii) {
28178 // Concatenate the chars:
28179 for (i = 0; i < values.length; i += 1) {
28181 // Ignore the terminating NULL byte(s):
28182 if (c === '\u0000') {
28194 Roo.apply(Roo.bootstrap.UploadCropbox, {
28196 'Orientation': 0x0112
28200 1: 0, //'top-left',
28202 3: 180, //'bottom-right',
28203 // 4: 'bottom-left',
28205 6: 90, //'right-top',
28206 // 7: 'right-bottom',
28207 8: 270 //'left-bottom'
28211 // byte, 8-bit unsigned int:
28213 getValue: function (dataView, dataOffset) {
28214 return dataView.getUint8(dataOffset);
28218 // ascii, 8-bit byte:
28220 getValue: function (dataView, dataOffset) {
28221 return String.fromCharCode(dataView.getUint8(dataOffset));
28226 // short, 16 bit int:
28228 getValue: function (dataView, dataOffset, littleEndian) {
28229 return dataView.getUint16(dataOffset, littleEndian);
28233 // long, 32 bit int:
28235 getValue: function (dataView, dataOffset, littleEndian) {
28236 return dataView.getUint32(dataOffset, littleEndian);
28240 // rational = two long values, first is numerator, second is denominator:
28242 getValue: function (dataView, dataOffset, littleEndian) {
28243 return dataView.getUint32(dataOffset, littleEndian) /
28244 dataView.getUint32(dataOffset + 4, littleEndian);
28248 // slong, 32 bit signed int:
28250 getValue: function (dataView, dataOffset, littleEndian) {
28251 return dataView.getInt32(dataOffset, littleEndian);
28255 // srational, two slongs, first is numerator, second is denominator:
28257 getValue: function (dataView, dataOffset, littleEndian) {
28258 return dataView.getInt32(dataOffset, littleEndian) /
28259 dataView.getInt32(dataOffset + 4, littleEndian);
28269 cls : 'btn-group roo-upload-cropbox-rotate-left',
28270 action : 'rotate-left',
28274 cls : 'btn btn-default',
28275 html : '<i class="fa fa-undo"></i>'
28281 cls : 'btn-group roo-upload-cropbox-picture',
28282 action : 'picture',
28286 cls : 'btn btn-default',
28287 html : '<i class="fa fa-picture-o"></i>'
28293 cls : 'btn-group roo-upload-cropbox-rotate-right',
28294 action : 'rotate-right',
28298 cls : 'btn btn-default',
28299 html : '<i class="fa fa-repeat"></i>'
28307 cls : 'btn-group roo-upload-cropbox-rotate-left',
28308 action : 'rotate-left',
28312 cls : 'btn btn-default',
28313 html : '<i class="fa fa-undo"></i>'
28319 cls : 'btn-group roo-upload-cropbox-download',
28320 action : 'download',
28324 cls : 'btn btn-default',
28325 html : '<i class="fa fa-download"></i>'
28331 cls : 'btn-group roo-upload-cropbox-crop',
28336 cls : 'btn btn-default',
28337 html : '<i class="fa fa-crop"></i>'
28343 cls : 'btn-group roo-upload-cropbox-trash',
28348 cls : 'btn btn-default',
28349 html : '<i class="fa fa-trash"></i>'
28355 cls : 'btn-group roo-upload-cropbox-rotate-right',
28356 action : 'rotate-right',
28360 cls : 'btn btn-default',
28361 html : '<i class="fa fa-repeat"></i>'
28369 cls : 'btn-group roo-upload-cropbox-rotate-left',
28370 action : 'rotate-left',
28374 cls : 'btn btn-default',
28375 html : '<i class="fa fa-undo"></i>'
28381 cls : 'btn-group roo-upload-cropbox-rotate-right',
28382 action : 'rotate-right',
28386 cls : 'btn btn-default',
28387 html : '<i class="fa fa-repeat"></i>'
28400 * @class Roo.bootstrap.DocumentManager
28401 * @extends Roo.bootstrap.Component
28402 * Bootstrap DocumentManager class
28403 * @cfg {String} paramName default 'imageUpload'
28404 * @cfg {String} toolTipName default 'filename'
28405 * @cfg {String} method default POST
28406 * @cfg {String} url action url
28407 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28408 * @cfg {Boolean} multiple multiple upload default true
28409 * @cfg {Number} thumbSize default 300
28410 * @cfg {String} fieldLabel
28411 * @cfg {Number} labelWidth default 4
28412 * @cfg {String} labelAlign (left|top) default left
28413 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28414 * @cfg {Number} labellg set the width of label (1-12)
28415 * @cfg {Number} labelmd set the width of label (1-12)
28416 * @cfg {Number} labelsm set the width of label (1-12)
28417 * @cfg {Number} labelxs set the width of label (1-12)
28420 * Create a new DocumentManager
28421 * @param {Object} config The config object
28424 Roo.bootstrap.DocumentManager = function(config){
28425 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28428 this.delegates = [];
28433 * Fire when initial the DocumentManager
28434 * @param {Roo.bootstrap.DocumentManager} this
28439 * inspect selected file
28440 * @param {Roo.bootstrap.DocumentManager} this
28441 * @param {File} file
28446 * Fire when xhr load exception
28447 * @param {Roo.bootstrap.DocumentManager} this
28448 * @param {XMLHttpRequest} xhr
28450 "exception" : true,
28452 * @event afterupload
28453 * Fire when xhr load exception
28454 * @param {Roo.bootstrap.DocumentManager} this
28455 * @param {XMLHttpRequest} xhr
28457 "afterupload" : true,
28460 * prepare the form data
28461 * @param {Roo.bootstrap.DocumentManager} this
28462 * @param {Object} formData
28467 * Fire when remove the file
28468 * @param {Roo.bootstrap.DocumentManager} this
28469 * @param {Object} file
28474 * Fire after refresh the file
28475 * @param {Roo.bootstrap.DocumentManager} this
28480 * Fire after click the image
28481 * @param {Roo.bootstrap.DocumentManager} this
28482 * @param {Object} file
28487 * Fire when upload a image and editable set to true
28488 * @param {Roo.bootstrap.DocumentManager} this
28489 * @param {Object} file
28493 * @event beforeselectfile
28494 * Fire before select file
28495 * @param {Roo.bootstrap.DocumentManager} this
28497 "beforeselectfile" : true,
28500 * Fire before process file
28501 * @param {Roo.bootstrap.DocumentManager} this
28502 * @param {Object} file
28506 * @event previewrendered
28507 * Fire when preview rendered
28508 * @param {Roo.bootstrap.DocumentManager} this
28509 * @param {Object} file
28511 "previewrendered" : true
28516 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28525 paramName : 'imageUpload',
28526 toolTipName : 'filename',
28529 labelAlign : 'left',
28539 getAutoCreate : function()
28541 var managerWidget = {
28543 cls : 'roo-document-manager',
28547 cls : 'roo-document-manager-selector',
28552 cls : 'roo-document-manager-uploader',
28556 cls : 'roo-document-manager-upload-btn',
28557 html : '<i class="fa fa-plus"></i>'
28568 cls : 'column col-md-12',
28573 if(this.fieldLabel.length){
28578 cls : 'column col-md-12',
28579 html : this.fieldLabel
28583 cls : 'column col-md-12',
28588 if(this.labelAlign == 'left'){
28593 html : this.fieldLabel
28602 if(this.labelWidth > 12){
28603 content[0].style = "width: " + this.labelWidth + 'px';
28606 if(this.labelWidth < 13 && this.labelmd == 0){
28607 this.labelmd = this.labelWidth;
28610 if(this.labellg > 0){
28611 content[0].cls += ' col-lg-' + this.labellg;
28612 content[1].cls += ' col-lg-' + (12 - this.labellg);
28615 if(this.labelmd > 0){
28616 content[0].cls += ' col-md-' + this.labelmd;
28617 content[1].cls += ' col-md-' + (12 - this.labelmd);
28620 if(this.labelsm > 0){
28621 content[0].cls += ' col-sm-' + this.labelsm;
28622 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28625 if(this.labelxs > 0){
28626 content[0].cls += ' col-xs-' + this.labelxs;
28627 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28635 cls : 'row clearfix',
28643 initEvents : function()
28645 this.managerEl = this.el.select('.roo-document-manager', true).first();
28646 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28648 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28649 this.selectorEl.hide();
28652 this.selectorEl.attr('multiple', 'multiple');
28655 this.selectorEl.on('change', this.onFileSelected, this);
28657 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28658 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28660 this.uploader.on('click', this.onUploaderClick, this);
28662 this.renderProgressDialog();
28666 window.addEventListener("resize", function() { _this.refresh(); } );
28668 this.fireEvent('initial', this);
28671 renderProgressDialog : function()
28675 this.progressDialog = new Roo.bootstrap.Modal({
28676 cls : 'roo-document-manager-progress-dialog',
28677 allow_close : false,
28687 btnclick : function() {
28688 _this.uploadCancel();
28694 this.progressDialog.render(Roo.get(document.body));
28696 this.progress = new Roo.bootstrap.Progress({
28697 cls : 'roo-document-manager-progress',
28702 this.progress.render(this.progressDialog.getChildContainer());
28704 this.progressBar = new Roo.bootstrap.ProgressBar({
28705 cls : 'roo-document-manager-progress-bar',
28708 aria_valuemax : 12,
28712 this.progressBar.render(this.progress.getChildContainer());
28715 onUploaderClick : function(e)
28717 e.preventDefault();
28719 if(this.fireEvent('beforeselectfile', this) != false){
28720 this.selectorEl.dom.click();
28725 onFileSelected : function(e)
28727 e.preventDefault();
28729 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28733 Roo.each(this.selectorEl.dom.files, function(file){
28734 if(this.fireEvent('inspect', this, file) != false){
28735 this.files.push(file);
28745 this.selectorEl.dom.value = '';
28747 if(!this.files || !this.files.length){
28751 if(this.boxes > 0 && this.files.length > this.boxes){
28752 this.files = this.files.slice(0, this.boxes);
28755 this.uploader.show();
28757 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28758 this.uploader.hide();
28767 Roo.each(this.files, function(file){
28769 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28770 var f = this.renderPreview(file);
28775 if(file.type.indexOf('image') != -1){
28776 this.delegates.push(
28778 _this.process(file);
28779 }).createDelegate(this)
28787 _this.process(file);
28788 }).createDelegate(this)
28793 this.files = files;
28795 this.delegates = this.delegates.concat(docs);
28797 if(!this.delegates.length){
28802 this.progressBar.aria_valuemax = this.delegates.length;
28809 arrange : function()
28811 if(!this.delegates.length){
28812 this.progressDialog.hide();
28817 var delegate = this.delegates.shift();
28819 this.progressDialog.show();
28821 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28823 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28828 refresh : function()
28830 this.uploader.show();
28832 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28833 this.uploader.hide();
28836 Roo.isTouch ? this.closable(false) : this.closable(true);
28838 this.fireEvent('refresh', this);
28841 onRemove : function(e, el, o)
28843 e.preventDefault();
28845 this.fireEvent('remove', this, o);
28849 remove : function(o)
28853 Roo.each(this.files, function(file){
28854 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28863 this.files = files;
28870 Roo.each(this.files, function(file){
28875 file.target.remove();
28884 onClick : function(e, el, o)
28886 e.preventDefault();
28888 this.fireEvent('click', this, o);
28892 closable : function(closable)
28894 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28896 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28908 xhrOnLoad : function(xhr)
28910 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28914 if (xhr.readyState !== 4) {
28916 this.fireEvent('exception', this, xhr);
28920 var response = Roo.decode(xhr.responseText);
28922 if(!response.success){
28924 this.fireEvent('exception', this, xhr);
28928 var file = this.renderPreview(response.data);
28930 this.files.push(file);
28934 this.fireEvent('afterupload', this, xhr);
28938 xhrOnError : function(xhr)
28940 Roo.log('xhr on error');
28942 var response = Roo.decode(xhr.responseText);
28949 process : function(file)
28951 if(this.fireEvent('process', this, file) !== false){
28952 if(this.editable && file.type.indexOf('image') != -1){
28953 this.fireEvent('edit', this, file);
28957 this.uploadStart(file, false);
28964 uploadStart : function(file, crop)
28966 this.xhr = new XMLHttpRequest();
28968 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28973 file.xhr = this.xhr;
28975 this.managerEl.createChild({
28977 cls : 'roo-document-manager-loading',
28981 tooltip : file.name,
28982 cls : 'roo-document-manager-thumb',
28983 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28989 this.xhr.open(this.method, this.url, true);
28992 "Accept": "application/json",
28993 "Cache-Control": "no-cache",
28994 "X-Requested-With": "XMLHttpRequest"
28997 for (var headerName in headers) {
28998 var headerValue = headers[headerName];
29000 this.xhr.setRequestHeader(headerName, headerValue);
29006 this.xhr.onload = function()
29008 _this.xhrOnLoad(_this.xhr);
29011 this.xhr.onerror = function()
29013 _this.xhrOnError(_this.xhr);
29016 var formData = new FormData();
29018 formData.append('returnHTML', 'NO');
29021 formData.append('crop', crop);
29024 formData.append(this.paramName, file, file.name);
29031 if(this.fireEvent('prepare', this, formData, options) != false){
29033 if(options.manually){
29037 this.xhr.send(formData);
29041 this.uploadCancel();
29044 uploadCancel : function()
29050 this.delegates = [];
29052 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29059 renderPreview : function(file)
29061 if(typeof(file.target) != 'undefined' && file.target){
29065 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29067 var previewEl = this.managerEl.createChild({
29069 cls : 'roo-document-manager-preview',
29073 tooltip : file[this.toolTipName],
29074 cls : 'roo-document-manager-thumb',
29075 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29080 html : '<i class="fa fa-times-circle"></i>'
29085 var close = previewEl.select('button.close', true).first();
29087 close.on('click', this.onRemove, this, file);
29089 file.target = previewEl;
29091 var image = previewEl.select('img', true).first();
29095 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29097 image.on('click', this.onClick, this, file);
29099 this.fireEvent('previewrendered', this, file);
29105 onPreviewLoad : function(file, image)
29107 if(typeof(file.target) == 'undefined' || !file.target){
29111 var width = image.dom.naturalWidth || image.dom.width;
29112 var height = image.dom.naturalHeight || image.dom.height;
29114 if(width > height){
29115 file.target.addClass('wide');
29119 file.target.addClass('tall');
29124 uploadFromSource : function(file, crop)
29126 this.xhr = new XMLHttpRequest();
29128 this.managerEl.createChild({
29130 cls : 'roo-document-manager-loading',
29134 tooltip : file.name,
29135 cls : 'roo-document-manager-thumb',
29136 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29142 this.xhr.open(this.method, this.url, true);
29145 "Accept": "application/json",
29146 "Cache-Control": "no-cache",
29147 "X-Requested-With": "XMLHttpRequest"
29150 for (var headerName in headers) {
29151 var headerValue = headers[headerName];
29153 this.xhr.setRequestHeader(headerName, headerValue);
29159 this.xhr.onload = function()
29161 _this.xhrOnLoad(_this.xhr);
29164 this.xhr.onerror = function()
29166 _this.xhrOnError(_this.xhr);
29169 var formData = new FormData();
29171 formData.append('returnHTML', 'NO');
29173 formData.append('crop', crop);
29175 if(typeof(file.filename) != 'undefined'){
29176 formData.append('filename', file.filename);
29179 if(typeof(file.mimetype) != 'undefined'){
29180 formData.append('mimetype', file.mimetype);
29185 if(this.fireEvent('prepare', this, formData) != false){
29186 this.xhr.send(formData);
29196 * @class Roo.bootstrap.DocumentViewer
29197 * @extends Roo.bootstrap.Component
29198 * Bootstrap DocumentViewer class
29199 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29200 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29203 * Create a new DocumentViewer
29204 * @param {Object} config The config object
29207 Roo.bootstrap.DocumentViewer = function(config){
29208 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29213 * Fire after initEvent
29214 * @param {Roo.bootstrap.DocumentViewer} this
29220 * @param {Roo.bootstrap.DocumentViewer} this
29225 * Fire after download button
29226 * @param {Roo.bootstrap.DocumentViewer} this
29231 * Fire after trash button
29232 * @param {Roo.bootstrap.DocumentViewer} this
29239 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29241 showDownload : true,
29245 getAutoCreate : function()
29249 cls : 'roo-document-viewer',
29253 cls : 'roo-document-viewer-body',
29257 cls : 'roo-document-viewer-thumb',
29261 cls : 'roo-document-viewer-image'
29269 cls : 'roo-document-viewer-footer',
29272 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29276 cls : 'btn-group roo-document-viewer-download',
29280 cls : 'btn btn-default',
29281 html : '<i class="fa fa-download"></i>'
29287 cls : 'btn-group roo-document-viewer-trash',
29291 cls : 'btn btn-default',
29292 html : '<i class="fa fa-trash"></i>'
29305 initEvents : function()
29307 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29308 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29310 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29311 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29313 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29314 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29316 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29317 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29319 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29320 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29322 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29323 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29325 this.bodyEl.on('click', this.onClick, this);
29326 this.downloadBtn.on('click', this.onDownload, this);
29327 this.trashBtn.on('click', this.onTrash, this);
29329 this.downloadBtn.hide();
29330 this.trashBtn.hide();
29332 if(this.showDownload){
29333 this.downloadBtn.show();
29336 if(this.showTrash){
29337 this.trashBtn.show();
29340 if(!this.showDownload && !this.showTrash) {
29341 this.footerEl.hide();
29346 initial : function()
29348 this.fireEvent('initial', this);
29352 onClick : function(e)
29354 e.preventDefault();
29356 this.fireEvent('click', this);
29359 onDownload : function(e)
29361 e.preventDefault();
29363 this.fireEvent('download', this);
29366 onTrash : function(e)
29368 e.preventDefault();
29370 this.fireEvent('trash', this);
29382 * @class Roo.bootstrap.NavProgressBar
29383 * @extends Roo.bootstrap.Component
29384 * Bootstrap NavProgressBar class
29387 * Create a new nav progress bar
29388 * @param {Object} config The config object
29391 Roo.bootstrap.NavProgressBar = function(config){
29392 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29394 this.bullets = this.bullets || [];
29396 // Roo.bootstrap.NavProgressBar.register(this);
29400 * Fires when the active item changes
29401 * @param {Roo.bootstrap.NavProgressBar} this
29402 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29403 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29410 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29415 getAutoCreate : function()
29417 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29421 cls : 'roo-navigation-bar-group',
29425 cls : 'roo-navigation-top-bar'
29429 cls : 'roo-navigation-bullets-bar',
29433 cls : 'roo-navigation-bar'
29440 cls : 'roo-navigation-bottom-bar'
29450 initEvents: function()
29455 onRender : function(ct, position)
29457 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29459 if(this.bullets.length){
29460 Roo.each(this.bullets, function(b){
29469 addItem : function(cfg)
29471 var item = new Roo.bootstrap.NavProgressItem(cfg);
29473 item.parentId = this.id;
29474 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29477 var top = new Roo.bootstrap.Element({
29479 cls : 'roo-navigation-bar-text'
29482 var bottom = new Roo.bootstrap.Element({
29484 cls : 'roo-navigation-bar-text'
29487 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29488 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29490 var topText = new Roo.bootstrap.Element({
29492 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29495 var bottomText = new Roo.bootstrap.Element({
29497 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29500 topText.onRender(top.el, null);
29501 bottomText.onRender(bottom.el, null);
29504 item.bottomEl = bottom;
29507 this.barItems.push(item);
29512 getActive : function()
29514 var active = false;
29516 Roo.each(this.barItems, function(v){
29518 if (!v.isActive()) {
29530 setActiveItem : function(item)
29534 Roo.each(this.barItems, function(v){
29535 if (v.rid == item.rid) {
29539 if (v.isActive()) {
29540 v.setActive(false);
29545 item.setActive(true);
29547 this.fireEvent('changed', this, item, prev);
29550 getBarItem: function(rid)
29554 Roo.each(this.barItems, function(e) {
29555 if (e.rid != rid) {
29566 indexOfItem : function(item)
29570 Roo.each(this.barItems, function(v, i){
29572 if (v.rid != item.rid) {
29583 setActiveNext : function()
29585 var i = this.indexOfItem(this.getActive());
29587 if (i > this.barItems.length) {
29591 this.setActiveItem(this.barItems[i+1]);
29594 setActivePrev : function()
29596 var i = this.indexOfItem(this.getActive());
29602 this.setActiveItem(this.barItems[i-1]);
29605 format : function()
29607 if(!this.barItems.length){
29611 var width = 100 / this.barItems.length;
29613 Roo.each(this.barItems, function(i){
29614 i.el.setStyle('width', width + '%');
29615 i.topEl.el.setStyle('width', width + '%');
29616 i.bottomEl.el.setStyle('width', width + '%');
29625 * Nav Progress Item
29630 * @class Roo.bootstrap.NavProgressItem
29631 * @extends Roo.bootstrap.Component
29632 * Bootstrap NavProgressItem class
29633 * @cfg {String} rid the reference id
29634 * @cfg {Boolean} active (true|false) Is item active default false
29635 * @cfg {Boolean} disabled (true|false) Is item active default false
29636 * @cfg {String} html
29637 * @cfg {String} position (top|bottom) text position default bottom
29638 * @cfg {String} icon show icon instead of number
29641 * Create a new NavProgressItem
29642 * @param {Object} config The config object
29644 Roo.bootstrap.NavProgressItem = function(config){
29645 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29650 * The raw click event for the entire grid.
29651 * @param {Roo.bootstrap.NavProgressItem} this
29652 * @param {Roo.EventObject} e
29659 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29665 position : 'bottom',
29668 getAutoCreate : function()
29670 var iconCls = 'roo-navigation-bar-item-icon';
29672 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29676 cls: 'roo-navigation-bar-item',
29686 cfg.cls += ' active';
29689 cfg.cls += ' disabled';
29695 disable : function()
29697 this.setDisabled(true);
29700 enable : function()
29702 this.setDisabled(false);
29705 initEvents: function()
29707 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29709 this.iconEl.on('click', this.onClick, this);
29712 onClick : function(e)
29714 e.preventDefault();
29720 if(this.fireEvent('click', this, e) === false){
29724 this.parent().setActiveItem(this);
29727 isActive: function ()
29729 return this.active;
29732 setActive : function(state)
29734 if(this.active == state){
29738 this.active = state;
29741 this.el.addClass('active');
29745 this.el.removeClass('active');
29750 setDisabled : function(state)
29752 if(this.disabled == state){
29756 this.disabled = state;
29759 this.el.addClass('disabled');
29763 this.el.removeClass('disabled');
29766 tooltipEl : function()
29768 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29781 * @class Roo.bootstrap.FieldLabel
29782 * @extends Roo.bootstrap.Component
29783 * Bootstrap FieldLabel class
29784 * @cfg {String} html contents of the element
29785 * @cfg {String} tag tag of the element default label
29786 * @cfg {String} cls class of the element
29787 * @cfg {String} target label target
29788 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29789 * @cfg {String} invalidClass default "text-warning"
29790 * @cfg {String} validClass default "text-success"
29791 * @cfg {String} iconTooltip default "This field is required"
29792 * @cfg {String} indicatorpos (left|right) default left
29795 * Create a new FieldLabel
29796 * @param {Object} config The config object
29799 Roo.bootstrap.FieldLabel = function(config){
29800 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29805 * Fires after the field has been marked as invalid.
29806 * @param {Roo.form.FieldLabel} this
29807 * @param {String} msg The validation message
29812 * Fires after the field has been validated with no errors.
29813 * @param {Roo.form.FieldLabel} this
29819 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29826 invalidClass : 'has-warning',
29827 validClass : 'has-success',
29828 iconTooltip : 'This field is required',
29829 indicatorpos : 'left',
29831 getAutoCreate : function(){
29835 cls : 'roo-bootstrap-field-label ' + this.cls,
29840 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29841 tooltip : this.iconTooltip
29850 if(this.indicatorpos == 'right'){
29853 cls : 'roo-bootstrap-field-label ' + this.cls,
29862 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29863 tooltip : this.iconTooltip
29872 initEvents: function()
29874 Roo.bootstrap.Element.superclass.initEvents.call(this);
29876 this.indicator = this.indicatorEl();
29878 if(this.indicator){
29879 this.indicator.removeClass('visible');
29880 this.indicator.addClass('invisible');
29883 Roo.bootstrap.FieldLabel.register(this);
29886 indicatorEl : function()
29888 var indicator = this.el.select('i.roo-required-indicator',true).first();
29899 * Mark this field as valid
29901 markValid : function()
29903 if(this.indicator){
29904 this.indicator.removeClass('visible');
29905 this.indicator.addClass('invisible');
29908 this.el.removeClass(this.invalidClass);
29910 this.el.addClass(this.validClass);
29912 this.fireEvent('valid', this);
29916 * Mark this field as invalid
29917 * @param {String} msg The validation message
29919 markInvalid : function(msg)
29921 if(this.indicator){
29922 this.indicator.removeClass('invisible');
29923 this.indicator.addClass('visible');
29926 this.el.removeClass(this.validClass);
29928 this.el.addClass(this.invalidClass);
29930 this.fireEvent('invalid', this, msg);
29936 Roo.apply(Roo.bootstrap.FieldLabel, {
29941 * register a FieldLabel Group
29942 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29944 register : function(label)
29946 if(this.groups.hasOwnProperty(label.target)){
29950 this.groups[label.target] = label;
29954 * fetch a FieldLabel Group based on the target
29955 * @param {string} target
29956 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29958 get: function(target) {
29959 if (typeof(this.groups[target]) == 'undefined') {
29963 return this.groups[target] ;
29972 * page DateSplitField.
29978 * @class Roo.bootstrap.DateSplitField
29979 * @extends Roo.bootstrap.Component
29980 * Bootstrap DateSplitField class
29981 * @cfg {string} fieldLabel - the label associated
29982 * @cfg {Number} labelWidth set the width of label (0-12)
29983 * @cfg {String} labelAlign (top|left)
29984 * @cfg {Boolean} dayAllowBlank (true|false) default false
29985 * @cfg {Boolean} monthAllowBlank (true|false) default false
29986 * @cfg {Boolean} yearAllowBlank (true|false) default false
29987 * @cfg {string} dayPlaceholder
29988 * @cfg {string} monthPlaceholder
29989 * @cfg {string} yearPlaceholder
29990 * @cfg {string} dayFormat default 'd'
29991 * @cfg {string} monthFormat default 'm'
29992 * @cfg {string} yearFormat default 'Y'
29993 * @cfg {Number} labellg set the width of label (1-12)
29994 * @cfg {Number} labelmd set the width of label (1-12)
29995 * @cfg {Number} labelsm set the width of label (1-12)
29996 * @cfg {Number} labelxs set the width of label (1-12)
30000 * Create a new DateSplitField
30001 * @param {Object} config The config object
30004 Roo.bootstrap.DateSplitField = function(config){
30005 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30011 * getting the data of years
30012 * @param {Roo.bootstrap.DateSplitField} this
30013 * @param {Object} years
30018 * getting the data of days
30019 * @param {Roo.bootstrap.DateSplitField} this
30020 * @param {Object} days
30025 * Fires after the field has been marked as invalid.
30026 * @param {Roo.form.Field} this
30027 * @param {String} msg The validation message
30032 * Fires after the field has been validated with no errors.
30033 * @param {Roo.form.Field} this
30039 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30042 labelAlign : 'top',
30044 dayAllowBlank : false,
30045 monthAllowBlank : false,
30046 yearAllowBlank : false,
30047 dayPlaceholder : '',
30048 monthPlaceholder : '',
30049 yearPlaceholder : '',
30053 isFormField : true,
30059 getAutoCreate : function()
30063 cls : 'row roo-date-split-field-group',
30068 cls : 'form-hidden-field roo-date-split-field-group-value',
30074 var labelCls = 'col-md-12';
30075 var contentCls = 'col-md-4';
30077 if(this.fieldLabel){
30081 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30085 html : this.fieldLabel
30090 if(this.labelAlign == 'left'){
30092 if(this.labelWidth > 12){
30093 label.style = "width: " + this.labelWidth + 'px';
30096 if(this.labelWidth < 13 && this.labelmd == 0){
30097 this.labelmd = this.labelWidth;
30100 if(this.labellg > 0){
30101 labelCls = ' col-lg-' + this.labellg;
30102 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30105 if(this.labelmd > 0){
30106 labelCls = ' col-md-' + this.labelmd;
30107 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30110 if(this.labelsm > 0){
30111 labelCls = ' col-sm-' + this.labelsm;
30112 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30115 if(this.labelxs > 0){
30116 labelCls = ' col-xs-' + this.labelxs;
30117 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30121 label.cls += ' ' + labelCls;
30123 cfg.cn.push(label);
30126 Roo.each(['day', 'month', 'year'], function(t){
30129 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30136 inputEl: function ()
30138 return this.el.select('.roo-date-split-field-group-value', true).first();
30141 onRender : function(ct, position)
30145 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30147 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30149 this.dayField = new Roo.bootstrap.ComboBox({
30150 allowBlank : this.dayAllowBlank,
30151 alwaysQuery : true,
30152 displayField : 'value',
30155 forceSelection : true,
30157 placeholder : this.dayPlaceholder,
30158 selectOnFocus : true,
30159 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30160 triggerAction : 'all',
30162 valueField : 'value',
30163 store : new Roo.data.SimpleStore({
30164 data : (function() {
30166 _this.fireEvent('days', _this, days);
30169 fields : [ 'value' ]
30172 select : function (_self, record, index)
30174 _this.setValue(_this.getValue());
30179 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30181 this.monthField = new Roo.bootstrap.MonthField({
30182 after : '<i class=\"fa fa-calendar\"></i>',
30183 allowBlank : this.monthAllowBlank,
30184 placeholder : this.monthPlaceholder,
30187 render : function (_self)
30189 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30190 e.preventDefault();
30194 select : function (_self, oldvalue, newvalue)
30196 _this.setValue(_this.getValue());
30201 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30203 this.yearField = new Roo.bootstrap.ComboBox({
30204 allowBlank : this.yearAllowBlank,
30205 alwaysQuery : true,
30206 displayField : 'value',
30209 forceSelection : true,
30211 placeholder : this.yearPlaceholder,
30212 selectOnFocus : true,
30213 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30214 triggerAction : 'all',
30216 valueField : 'value',
30217 store : new Roo.data.SimpleStore({
30218 data : (function() {
30220 _this.fireEvent('years', _this, years);
30223 fields : [ 'value' ]
30226 select : function (_self, record, index)
30228 _this.setValue(_this.getValue());
30233 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30236 setValue : function(v, format)
30238 this.inputEl.dom.value = v;
30240 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30242 var d = Date.parseDate(v, f);
30249 this.setDay(d.format(this.dayFormat));
30250 this.setMonth(d.format(this.monthFormat));
30251 this.setYear(d.format(this.yearFormat));
30258 setDay : function(v)
30260 this.dayField.setValue(v);
30261 this.inputEl.dom.value = this.getValue();
30266 setMonth : function(v)
30268 this.monthField.setValue(v, true);
30269 this.inputEl.dom.value = this.getValue();
30274 setYear : function(v)
30276 this.yearField.setValue(v);
30277 this.inputEl.dom.value = this.getValue();
30282 getDay : function()
30284 return this.dayField.getValue();
30287 getMonth : function()
30289 return this.monthField.getValue();
30292 getYear : function()
30294 return this.yearField.getValue();
30297 getValue : function()
30299 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30301 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30311 this.inputEl.dom.value = '';
30316 validate : function()
30318 var d = this.dayField.validate();
30319 var m = this.monthField.validate();
30320 var y = this.yearField.validate();
30325 (!this.dayAllowBlank && !d) ||
30326 (!this.monthAllowBlank && !m) ||
30327 (!this.yearAllowBlank && !y)
30332 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30341 this.markInvalid();
30346 markValid : function()
30349 var label = this.el.select('label', true).first();
30350 var icon = this.el.select('i.fa-star', true).first();
30356 this.fireEvent('valid', this);
30360 * Mark this field as invalid
30361 * @param {String} msg The validation message
30363 markInvalid : function(msg)
30366 var label = this.el.select('label', true).first();
30367 var icon = this.el.select('i.fa-star', true).first();
30369 if(label && !icon){
30370 this.el.select('.roo-date-split-field-label', true).createChild({
30372 cls : 'text-danger fa fa-lg fa-star',
30373 tooltip : 'This field is required',
30374 style : 'margin-right:5px;'
30378 this.fireEvent('invalid', this, msg);
30381 clearInvalid : function()
30383 var label = this.el.select('label', true).first();
30384 var icon = this.el.select('i.fa-star', true).first();
30390 this.fireEvent('valid', this);
30393 getName: function()
30403 * http://masonry.desandro.com
30405 * The idea is to render all the bricks based on vertical width...
30407 * The original code extends 'outlayer' - we might need to use that....
30413 * @class Roo.bootstrap.LayoutMasonry
30414 * @extends Roo.bootstrap.Component
30415 * Bootstrap Layout Masonry class
30418 * Create a new Element
30419 * @param {Object} config The config object
30422 Roo.bootstrap.LayoutMasonry = function(config){
30424 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30428 Roo.bootstrap.LayoutMasonry.register(this);
30434 * Fire after layout the items
30435 * @param {Roo.bootstrap.LayoutMasonry} this
30436 * @param {Roo.EventObject} e
30443 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30446 * @cfg {Boolean} isLayoutInstant = no animation?
30448 isLayoutInstant : false, // needed?
30451 * @cfg {Number} boxWidth width of the columns
30456 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30461 * @cfg {Number} padWidth padding below box..
30466 * @cfg {Number} gutter gutter width..
30471 * @cfg {Number} maxCols maximum number of columns
30477 * @cfg {Boolean} isAutoInitial defalut true
30479 isAutoInitial : true,
30484 * @cfg {Boolean} isHorizontal defalut false
30486 isHorizontal : false,
30488 currentSize : null,
30494 bricks: null, //CompositeElement
30498 _isLayoutInited : false,
30500 // isAlternative : false, // only use for vertical layout...
30503 * @cfg {Number} alternativePadWidth padding below box..
30505 alternativePadWidth : 50,
30507 selectedBrick : [],
30509 getAutoCreate : function(){
30511 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30515 cls: 'blog-masonary-wrapper ' + this.cls,
30517 cls : 'mas-boxes masonary'
30524 getChildContainer: function( )
30526 if (this.boxesEl) {
30527 return this.boxesEl;
30530 this.boxesEl = this.el.select('.mas-boxes').first();
30532 return this.boxesEl;
30536 initEvents : function()
30540 if(this.isAutoInitial){
30541 Roo.log('hook children rendered');
30542 this.on('childrenrendered', function() {
30543 Roo.log('children rendered');
30549 initial : function()
30551 this.selectedBrick = [];
30553 this.currentSize = this.el.getBox(true);
30555 Roo.EventManager.onWindowResize(this.resize, this);
30557 if(!this.isAutoInitial){
30565 //this.layout.defer(500,this);
30569 resize : function()
30571 var cs = this.el.getBox(true);
30574 this.currentSize.width == cs.width &&
30575 this.currentSize.x == cs.x &&
30576 this.currentSize.height == cs.height &&
30577 this.currentSize.y == cs.y
30579 Roo.log("no change in with or X or Y");
30583 this.currentSize = cs;
30589 layout : function()
30591 this._resetLayout();
30593 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30595 this.layoutItems( isInstant );
30597 this._isLayoutInited = true;
30599 this.fireEvent('layout', this);
30603 _resetLayout : function()
30605 if(this.isHorizontal){
30606 this.horizontalMeasureColumns();
30610 this.verticalMeasureColumns();
30614 verticalMeasureColumns : function()
30616 this.getContainerWidth();
30618 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30619 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30623 var boxWidth = this.boxWidth + this.padWidth;
30625 if(this.containerWidth < this.boxWidth){
30626 boxWidth = this.containerWidth
30629 var containerWidth = this.containerWidth;
30631 var cols = Math.floor(containerWidth / boxWidth);
30633 this.cols = Math.max( cols, 1 );
30635 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30637 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30639 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30641 this.colWidth = boxWidth + avail - this.padWidth;
30643 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30644 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30647 horizontalMeasureColumns : function()
30649 this.getContainerWidth();
30651 var boxWidth = this.boxWidth;
30653 if(this.containerWidth < boxWidth){
30654 boxWidth = this.containerWidth;
30657 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30659 this.el.setHeight(boxWidth);
30663 getContainerWidth : function()
30665 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30668 layoutItems : function( isInstant )
30670 Roo.log(this.bricks);
30672 var items = Roo.apply([], this.bricks);
30674 if(this.isHorizontal){
30675 this._horizontalLayoutItems( items , isInstant );
30679 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30680 // this._verticalAlternativeLayoutItems( items , isInstant );
30684 this._verticalLayoutItems( items , isInstant );
30688 _verticalLayoutItems : function ( items , isInstant)
30690 if ( !items || !items.length ) {
30695 ['xs', 'xs', 'xs', 'tall'],
30696 ['xs', 'xs', 'tall'],
30697 ['xs', 'xs', 'sm'],
30698 ['xs', 'xs', 'xs'],
30704 ['sm', 'xs', 'xs'],
30708 ['tall', 'xs', 'xs', 'xs'],
30709 ['tall', 'xs', 'xs'],
30721 Roo.each(items, function(item, k){
30723 switch (item.size) {
30724 // these layouts take up a full box,
30735 boxes.push([item]);
30758 var filterPattern = function(box, length)
30766 var pattern = box.slice(0, length);
30770 Roo.each(pattern, function(i){
30771 format.push(i.size);
30774 Roo.each(standard, function(s){
30776 if(String(s) != String(format)){
30785 if(!match && length == 1){
30790 filterPattern(box, length - 1);
30794 queue.push(pattern);
30796 box = box.slice(length, box.length);
30798 filterPattern(box, 4);
30804 Roo.each(boxes, function(box, k){
30810 if(box.length == 1){
30815 filterPattern(box, 4);
30819 this._processVerticalLayoutQueue( queue, isInstant );
30823 // _verticalAlternativeLayoutItems : function( items , isInstant )
30825 // if ( !items || !items.length ) {
30829 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30833 _horizontalLayoutItems : function ( items , isInstant)
30835 if ( !items || !items.length || items.length < 3) {
30841 var eItems = items.slice(0, 3);
30843 items = items.slice(3, items.length);
30846 ['xs', 'xs', 'xs', 'wide'],
30847 ['xs', 'xs', 'wide'],
30848 ['xs', 'xs', 'sm'],
30849 ['xs', 'xs', 'xs'],
30855 ['sm', 'xs', 'xs'],
30859 ['wide', 'xs', 'xs', 'xs'],
30860 ['wide', 'xs', 'xs'],
30873 Roo.each(items, function(item, k){
30875 switch (item.size) {
30886 boxes.push([item]);
30910 var filterPattern = function(box, length)
30918 var pattern = box.slice(0, length);
30922 Roo.each(pattern, function(i){
30923 format.push(i.size);
30926 Roo.each(standard, function(s){
30928 if(String(s) != String(format)){
30937 if(!match && length == 1){
30942 filterPattern(box, length - 1);
30946 queue.push(pattern);
30948 box = box.slice(length, box.length);
30950 filterPattern(box, 4);
30956 Roo.each(boxes, function(box, k){
30962 if(box.length == 1){
30967 filterPattern(box, 4);
30974 var pos = this.el.getBox(true);
30978 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30980 var hit_end = false;
30982 Roo.each(queue, function(box){
30986 Roo.each(box, function(b){
30988 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30998 Roo.each(box, function(b){
31000 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31003 mx = Math.max(mx, b.x);
31007 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31011 Roo.each(box, function(b){
31013 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31027 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31030 /** Sets position of item in DOM
31031 * @param {Element} item
31032 * @param {Number} x - horizontal position
31033 * @param {Number} y - vertical position
31034 * @param {Boolean} isInstant - disables transitions
31036 _processVerticalLayoutQueue : function( queue, isInstant )
31038 var pos = this.el.getBox(true);
31043 for (var i = 0; i < this.cols; i++){
31047 Roo.each(queue, function(box, k){
31049 var col = k % this.cols;
31051 Roo.each(box, function(b,kk){
31053 b.el.position('absolute');
31055 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31056 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31058 if(b.size == 'md-left' || b.size == 'md-right'){
31059 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31060 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31063 b.el.setWidth(width);
31064 b.el.setHeight(height);
31066 b.el.select('iframe',true).setSize(width,height);
31070 for (var i = 0; i < this.cols; i++){
31072 if(maxY[i] < maxY[col]){
31077 col = Math.min(col, i);
31081 x = pos.x + col * (this.colWidth + this.padWidth);
31085 var positions = [];
31087 switch (box.length){
31089 positions = this.getVerticalOneBoxColPositions(x, y, box);
31092 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31095 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31098 positions = this.getVerticalFourBoxColPositions(x, y, box);
31104 Roo.each(box, function(b,kk){
31106 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31108 var sz = b.el.getSize();
31110 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31118 for (var i = 0; i < this.cols; i++){
31119 mY = Math.max(mY, maxY[i]);
31122 this.el.setHeight(mY - pos.y);
31126 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31128 // var pos = this.el.getBox(true);
31131 // var maxX = pos.right;
31133 // var maxHeight = 0;
31135 // Roo.each(items, function(item, k){
31139 // item.el.position('absolute');
31141 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31143 // item.el.setWidth(width);
31145 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31147 // item.el.setHeight(height);
31150 // item.el.setXY([x, y], isInstant ? false : true);
31152 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31155 // y = y + height + this.alternativePadWidth;
31157 // maxHeight = maxHeight + height + this.alternativePadWidth;
31161 // this.el.setHeight(maxHeight);
31165 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31167 var pos = this.el.getBox(true);
31172 var maxX = pos.right;
31174 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31176 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31178 Roo.each(queue, function(box, k){
31180 Roo.each(box, function(b, kk){
31182 b.el.position('absolute');
31184 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31185 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31187 if(b.size == 'md-left' || b.size == 'md-right'){
31188 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31189 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31192 b.el.setWidth(width);
31193 b.el.setHeight(height);
31201 var positions = [];
31203 switch (box.length){
31205 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31208 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31211 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31214 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31220 Roo.each(box, function(b,kk){
31222 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31224 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31232 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31234 Roo.each(eItems, function(b,k){
31236 b.size = (k == 0) ? 'sm' : 'xs';
31237 b.x = (k == 0) ? 2 : 1;
31238 b.y = (k == 0) ? 2 : 1;
31240 b.el.position('absolute');
31242 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31244 b.el.setWidth(width);
31246 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31248 b.el.setHeight(height);
31252 var positions = [];
31255 x : maxX - this.unitWidth * 2 - this.gutter,
31260 x : maxX - this.unitWidth,
31261 y : minY + (this.unitWidth + this.gutter) * 2
31265 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31269 Roo.each(eItems, function(b,k){
31271 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31277 getVerticalOneBoxColPositions : function(x, y, box)
31281 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31283 if(box[0].size == 'md-left'){
31287 if(box[0].size == 'md-right'){
31292 x : x + (this.unitWidth + this.gutter) * rand,
31299 getVerticalTwoBoxColPositions : function(x, y, box)
31303 if(box[0].size == 'xs'){
31307 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31311 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31325 x : x + (this.unitWidth + this.gutter) * 2,
31326 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31333 getVerticalThreeBoxColPositions : function(x, y, box)
31337 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31345 x : x + (this.unitWidth + this.gutter) * 1,
31350 x : x + (this.unitWidth + this.gutter) * 2,
31358 if(box[0].size == 'xs' && box[1].size == 'xs'){
31367 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31371 x : x + (this.unitWidth + this.gutter) * 1,
31385 x : x + (this.unitWidth + this.gutter) * 2,
31390 x : x + (this.unitWidth + this.gutter) * 2,
31391 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31398 getVerticalFourBoxColPositions : function(x, y, box)
31402 if(box[0].size == 'xs'){
31411 y : y + (this.unitHeight + this.gutter) * 1
31416 y : y + (this.unitHeight + this.gutter) * 2
31420 x : x + (this.unitWidth + this.gutter) * 1,
31434 x : x + (this.unitWidth + this.gutter) * 2,
31439 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31440 y : y + (this.unitHeight + this.gutter) * 1
31444 x : x + (this.unitWidth + this.gutter) * 2,
31445 y : y + (this.unitWidth + this.gutter) * 2
31452 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31456 if(box[0].size == 'md-left'){
31458 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31465 if(box[0].size == 'md-right'){
31467 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31468 y : minY + (this.unitWidth + this.gutter) * 1
31474 var rand = Math.floor(Math.random() * (4 - box[0].y));
31477 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31478 y : minY + (this.unitWidth + this.gutter) * rand
31485 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31489 if(box[0].size == 'xs'){
31492 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31497 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31498 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31506 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31511 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31512 y : minY + (this.unitWidth + this.gutter) * 2
31519 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31523 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31526 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31531 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31532 y : minY + (this.unitWidth + this.gutter) * 1
31536 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31537 y : minY + (this.unitWidth + this.gutter) * 2
31544 if(box[0].size == 'xs' && box[1].size == 'xs'){
31547 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31552 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31557 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31558 y : minY + (this.unitWidth + this.gutter) * 1
31566 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31571 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31572 y : minY + (this.unitWidth + this.gutter) * 2
31576 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31577 y : minY + (this.unitWidth + this.gutter) * 2
31584 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31588 if(box[0].size == 'xs'){
31591 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31596 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31601 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),
31606 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31607 y : minY + (this.unitWidth + this.gutter) * 1
31615 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31620 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31621 y : minY + (this.unitWidth + this.gutter) * 2
31625 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31626 y : minY + (this.unitWidth + this.gutter) * 2
31630 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),
31631 y : minY + (this.unitWidth + this.gutter) * 2
31639 * remove a Masonry Brick
31640 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31642 removeBrick : function(brick_id)
31648 for (var i = 0; i<this.bricks.length; i++) {
31649 if (this.bricks[i].id == brick_id) {
31650 this.bricks.splice(i,1);
31651 this.el.dom.removeChild(Roo.get(brick_id).dom);
31658 * adds a Masonry Brick
31659 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31661 addBrick : function(cfg)
31663 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31664 //this.register(cn);
31665 cn.parentId = this.id;
31666 cn.onRender(this.el, null);
31671 * register a Masonry Brick
31672 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31675 register : function(brick)
31677 this.bricks.push(brick);
31678 brick.masonryId = this.id;
31682 * clear all the Masonry Brick
31684 clearAll : function()
31687 //this.getChildContainer().dom.innerHTML = "";
31688 this.el.dom.innerHTML = '';
31691 getSelected : function()
31693 if (!this.selectedBrick) {
31697 return this.selectedBrick;
31701 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31705 * register a Masonry Layout
31706 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31709 register : function(layout)
31711 this.groups[layout.id] = layout;
31714 * fetch a Masonry Layout based on the masonry layout ID
31715 * @param {string} the masonry layout to add
31716 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31719 get: function(layout_id) {
31720 if (typeof(this.groups[layout_id]) == 'undefined') {
31723 return this.groups[layout_id] ;
31735 * http://masonry.desandro.com
31737 * The idea is to render all the bricks based on vertical width...
31739 * The original code extends 'outlayer' - we might need to use that....
31745 * @class Roo.bootstrap.LayoutMasonryAuto
31746 * @extends Roo.bootstrap.Component
31747 * Bootstrap Layout Masonry class
31750 * Create a new Element
31751 * @param {Object} config The config object
31754 Roo.bootstrap.LayoutMasonryAuto = function(config){
31755 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31758 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31761 * @cfg {Boolean} isFitWidth - resize the width..
31763 isFitWidth : false, // options..
31765 * @cfg {Boolean} isOriginLeft = left align?
31767 isOriginLeft : true,
31769 * @cfg {Boolean} isOriginTop = top align?
31771 isOriginTop : false,
31773 * @cfg {Boolean} isLayoutInstant = no animation?
31775 isLayoutInstant : false, // needed?
31777 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31779 isResizingContainer : true,
31781 * @cfg {Number} columnWidth width of the columns
31787 * @cfg {Number} maxCols maximum number of columns
31792 * @cfg {Number} padHeight padding below box..
31798 * @cfg {Boolean} isAutoInitial defalut true
31801 isAutoInitial : true,
31807 initialColumnWidth : 0,
31808 currentSize : null,
31810 colYs : null, // array.
31817 bricks: null, //CompositeElement
31818 cols : 0, // array?
31819 // element : null, // wrapped now this.el
31820 _isLayoutInited : null,
31823 getAutoCreate : function(){
31827 cls: 'blog-masonary-wrapper ' + this.cls,
31829 cls : 'mas-boxes masonary'
31836 getChildContainer: function( )
31838 if (this.boxesEl) {
31839 return this.boxesEl;
31842 this.boxesEl = this.el.select('.mas-boxes').first();
31844 return this.boxesEl;
31848 initEvents : function()
31852 if(this.isAutoInitial){
31853 Roo.log('hook children rendered');
31854 this.on('childrenrendered', function() {
31855 Roo.log('children rendered');
31862 initial : function()
31864 this.reloadItems();
31866 this.currentSize = this.el.getBox(true);
31868 /// was window resize... - let's see if this works..
31869 Roo.EventManager.onWindowResize(this.resize, this);
31871 if(!this.isAutoInitial){
31876 this.layout.defer(500,this);
31879 reloadItems: function()
31881 this.bricks = this.el.select('.masonry-brick', true);
31883 this.bricks.each(function(b) {
31884 //Roo.log(b.getSize());
31885 if (!b.attr('originalwidth')) {
31886 b.attr('originalwidth', b.getSize().width);
31891 Roo.log(this.bricks.elements.length);
31894 resize : function()
31897 var cs = this.el.getBox(true);
31899 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31900 Roo.log("no change in with or X");
31903 this.currentSize = cs;
31907 layout : function()
31910 this._resetLayout();
31911 //this._manageStamps();
31913 // don't animate first layout
31914 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31915 this.layoutItems( isInstant );
31917 // flag for initalized
31918 this._isLayoutInited = true;
31921 layoutItems : function( isInstant )
31923 //var items = this._getItemsForLayout( this.items );
31924 // original code supports filtering layout items.. we just ignore it..
31926 this._layoutItems( this.bricks , isInstant );
31928 this._postLayout();
31930 _layoutItems : function ( items , isInstant)
31932 //this.fireEvent( 'layout', this, items );
31935 if ( !items || !items.elements.length ) {
31936 // no items, emit event with empty array
31941 items.each(function(item) {
31942 Roo.log("layout item");
31944 // get x/y object from method
31945 var position = this._getItemLayoutPosition( item );
31947 position.item = item;
31948 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31949 queue.push( position );
31952 this._processLayoutQueue( queue );
31954 /** Sets position of item in DOM
31955 * @param {Element} item
31956 * @param {Number} x - horizontal position
31957 * @param {Number} y - vertical position
31958 * @param {Boolean} isInstant - disables transitions
31960 _processLayoutQueue : function( queue )
31962 for ( var i=0, len = queue.length; i < len; i++ ) {
31963 var obj = queue[i];
31964 obj.item.position('absolute');
31965 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31971 * Any logic you want to do after each layout,
31972 * i.e. size the container
31974 _postLayout : function()
31976 this.resizeContainer();
31979 resizeContainer : function()
31981 if ( !this.isResizingContainer ) {
31984 var size = this._getContainerSize();
31986 this.el.setSize(size.width,size.height);
31987 this.boxesEl.setSize(size.width,size.height);
31993 _resetLayout : function()
31995 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31996 this.colWidth = this.el.getWidth();
31997 //this.gutter = this.el.getWidth();
31999 this.measureColumns();
32005 this.colYs.push( 0 );
32011 measureColumns : function()
32013 this.getContainerWidth();
32014 // if columnWidth is 0, default to outerWidth of first item
32015 if ( !this.columnWidth ) {
32016 var firstItem = this.bricks.first();
32017 Roo.log(firstItem);
32018 this.columnWidth = this.containerWidth;
32019 if (firstItem && firstItem.attr('originalwidth') ) {
32020 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32022 // columnWidth fall back to item of first element
32023 Roo.log("set column width?");
32024 this.initialColumnWidth = this.columnWidth ;
32026 // if first elem has no width, default to size of container
32031 if (this.initialColumnWidth) {
32032 this.columnWidth = this.initialColumnWidth;
32037 // column width is fixed at the top - however if container width get's smaller we should
32040 // this bit calcs how man columns..
32042 var columnWidth = this.columnWidth += this.gutter;
32044 // calculate columns
32045 var containerWidth = this.containerWidth + this.gutter;
32047 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32048 // fix rounding errors, typically with gutters
32049 var excess = columnWidth - containerWidth % columnWidth;
32052 // if overshoot is less than a pixel, round up, otherwise floor it
32053 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32054 cols = Math[ mathMethod ]( cols );
32055 this.cols = Math.max( cols, 1 );
32056 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32058 // padding positioning..
32059 var totalColWidth = this.cols * this.columnWidth;
32060 var padavail = this.containerWidth - totalColWidth;
32061 // so for 2 columns - we need 3 'pads'
32063 var padNeeded = (1+this.cols) * this.padWidth;
32065 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32067 this.columnWidth += padExtra
32068 //this.padWidth = Math.floor(padavail / ( this.cols));
32070 // adjust colum width so that padding is fixed??
32072 // we have 3 columns ... total = width * 3
32073 // we have X left over... that should be used by
32075 //if (this.expandC) {
32083 getContainerWidth : function()
32085 /* // container is parent if fit width
32086 var container = this.isFitWidth ? this.element.parentNode : this.element;
32087 // check that this.size and size are there
32088 // IE8 triggers resize on body size change, so they might not be
32090 var size = getSize( container ); //FIXME
32091 this.containerWidth = size && size.innerWidth; //FIXME
32094 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32098 _getItemLayoutPosition : function( item ) // what is item?
32100 // we resize the item to our columnWidth..
32102 item.setWidth(this.columnWidth);
32103 item.autoBoxAdjust = false;
32105 var sz = item.getSize();
32107 // how many columns does this brick span
32108 var remainder = this.containerWidth % this.columnWidth;
32110 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32111 // round if off by 1 pixel, otherwise use ceil
32112 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32113 colSpan = Math.min( colSpan, this.cols );
32115 // normally this should be '1' as we dont' currently allow multi width columns..
32117 var colGroup = this._getColGroup( colSpan );
32118 // get the minimum Y value from the columns
32119 var minimumY = Math.min.apply( Math, colGroup );
32120 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32122 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32124 // position the brick
32126 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32127 y: this.currentSize.y + minimumY + this.padHeight
32131 // apply setHeight to necessary columns
32132 var setHeight = minimumY + sz.height + this.padHeight;
32133 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32135 var setSpan = this.cols + 1 - colGroup.length;
32136 for ( var i = 0; i < setSpan; i++ ) {
32137 this.colYs[ shortColIndex + i ] = setHeight ;
32144 * @param {Number} colSpan - number of columns the element spans
32145 * @returns {Array} colGroup
32147 _getColGroup : function( colSpan )
32149 if ( colSpan < 2 ) {
32150 // if brick spans only one column, use all the column Ys
32155 // how many different places could this brick fit horizontally
32156 var groupCount = this.cols + 1 - colSpan;
32157 // for each group potential horizontal position
32158 for ( var i = 0; i < groupCount; i++ ) {
32159 // make an array of colY values for that one group
32160 var groupColYs = this.colYs.slice( i, i + colSpan );
32161 // and get the max value of the array
32162 colGroup[i] = Math.max.apply( Math, groupColYs );
32167 _manageStamp : function( stamp )
32169 var stampSize = stamp.getSize();
32170 var offset = stamp.getBox();
32171 // get the columns that this stamp affects
32172 var firstX = this.isOriginLeft ? offset.x : offset.right;
32173 var lastX = firstX + stampSize.width;
32174 var firstCol = Math.floor( firstX / this.columnWidth );
32175 firstCol = Math.max( 0, firstCol );
32177 var lastCol = Math.floor( lastX / this.columnWidth );
32178 // lastCol should not go over if multiple of columnWidth #425
32179 lastCol -= lastX % this.columnWidth ? 0 : 1;
32180 lastCol = Math.min( this.cols - 1, lastCol );
32182 // set colYs to bottom of the stamp
32183 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32186 for ( var i = firstCol; i <= lastCol; i++ ) {
32187 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32192 _getContainerSize : function()
32194 this.maxY = Math.max.apply( Math, this.colYs );
32199 if ( this.isFitWidth ) {
32200 size.width = this._getContainerFitWidth();
32206 _getContainerFitWidth : function()
32208 var unusedCols = 0;
32209 // count unused columns
32212 if ( this.colYs[i] !== 0 ) {
32217 // fit container to columns that have been used
32218 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32221 needsResizeLayout : function()
32223 var previousWidth = this.containerWidth;
32224 this.getContainerWidth();
32225 return previousWidth !== this.containerWidth;
32240 * @class Roo.bootstrap.MasonryBrick
32241 * @extends Roo.bootstrap.Component
32242 * Bootstrap MasonryBrick class
32245 * Create a new MasonryBrick
32246 * @param {Object} config The config object
32249 Roo.bootstrap.MasonryBrick = function(config){
32251 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32253 Roo.bootstrap.MasonryBrick.register(this);
32259 * When a MasonryBrick is clcik
32260 * @param {Roo.bootstrap.MasonryBrick} this
32261 * @param {Roo.EventObject} e
32267 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32270 * @cfg {String} title
32274 * @cfg {String} html
32278 * @cfg {String} bgimage
32282 * @cfg {String} videourl
32286 * @cfg {String} cls
32290 * @cfg {String} href
32294 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32299 * @cfg {String} placetitle (center|bottom)
32304 * @cfg {Boolean} isFitContainer defalut true
32306 isFitContainer : true,
32309 * @cfg {Boolean} preventDefault defalut false
32311 preventDefault : false,
32314 * @cfg {Boolean} inverse defalut false
32316 maskInverse : false,
32318 getAutoCreate : function()
32320 if(!this.isFitContainer){
32321 return this.getSplitAutoCreate();
32324 var cls = 'masonry-brick masonry-brick-full';
32326 if(this.href.length){
32327 cls += ' masonry-brick-link';
32330 if(this.bgimage.length){
32331 cls += ' masonry-brick-image';
32334 if(this.maskInverse){
32335 cls += ' mask-inverse';
32338 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32339 cls += ' enable-mask';
32343 cls += ' masonry-' + this.size + '-brick';
32346 if(this.placetitle.length){
32348 switch (this.placetitle) {
32350 cls += ' masonry-center-title';
32353 cls += ' masonry-bottom-title';
32360 if(!this.html.length && !this.bgimage.length){
32361 cls += ' masonry-center-title';
32364 if(!this.html.length && this.bgimage.length){
32365 cls += ' masonry-bottom-title';
32370 cls += ' ' + this.cls;
32374 tag: (this.href.length) ? 'a' : 'div',
32379 cls: 'masonry-brick-mask'
32383 cls: 'masonry-brick-paragraph',
32389 if(this.href.length){
32390 cfg.href = this.href;
32393 var cn = cfg.cn[1].cn;
32395 if(this.title.length){
32398 cls: 'masonry-brick-title',
32403 if(this.html.length){
32406 cls: 'masonry-brick-text',
32411 if (!this.title.length && !this.html.length) {
32412 cfg.cn[1].cls += ' hide';
32415 if(this.bgimage.length){
32418 cls: 'masonry-brick-image-view',
32423 if(this.videourl.length){
32424 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32425 // youtube support only?
32428 cls: 'masonry-brick-image-view',
32431 allowfullscreen : true
32439 getSplitAutoCreate : function()
32441 var cls = 'masonry-brick masonry-brick-split';
32443 if(this.href.length){
32444 cls += ' masonry-brick-link';
32447 if(this.bgimage.length){
32448 cls += ' masonry-brick-image';
32452 cls += ' masonry-' + this.size + '-brick';
32455 switch (this.placetitle) {
32457 cls += ' masonry-center-title';
32460 cls += ' masonry-bottom-title';
32463 if(!this.bgimage.length){
32464 cls += ' masonry-center-title';
32467 if(this.bgimage.length){
32468 cls += ' masonry-bottom-title';
32474 cls += ' ' + this.cls;
32478 tag: (this.href.length) ? 'a' : 'div',
32483 cls: 'masonry-brick-split-head',
32487 cls: 'masonry-brick-paragraph',
32494 cls: 'masonry-brick-split-body',
32500 if(this.href.length){
32501 cfg.href = this.href;
32504 if(this.title.length){
32505 cfg.cn[0].cn[0].cn.push({
32507 cls: 'masonry-brick-title',
32512 if(this.html.length){
32513 cfg.cn[1].cn.push({
32515 cls: 'masonry-brick-text',
32520 if(this.bgimage.length){
32521 cfg.cn[0].cn.push({
32523 cls: 'masonry-brick-image-view',
32528 if(this.videourl.length){
32529 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32530 // youtube support only?
32531 cfg.cn[0].cn.cn.push({
32533 cls: 'masonry-brick-image-view',
32536 allowfullscreen : true
32543 initEvents: function()
32545 switch (this.size) {
32578 this.el.on('touchstart', this.onTouchStart, this);
32579 this.el.on('touchmove', this.onTouchMove, this);
32580 this.el.on('touchend', this.onTouchEnd, this);
32581 this.el.on('contextmenu', this.onContextMenu, this);
32583 this.el.on('mouseenter' ,this.enter, this);
32584 this.el.on('mouseleave', this.leave, this);
32585 this.el.on('click', this.onClick, this);
32588 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32589 this.parent().bricks.push(this);
32594 onClick: function(e, el)
32596 var time = this.endTimer - this.startTimer;
32597 // Roo.log(e.preventDefault());
32600 e.preventDefault();
32605 if(!this.preventDefault){
32609 e.preventDefault();
32611 if (this.activcClass != '') {
32612 this.selectBrick();
32615 this.fireEvent('click', this);
32618 enter: function(e, el)
32620 e.preventDefault();
32622 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32626 if(this.bgimage.length && this.html.length){
32627 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32631 leave: function(e, el)
32633 e.preventDefault();
32635 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32639 if(this.bgimage.length && this.html.length){
32640 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32644 onTouchStart: function(e, el)
32646 // e.preventDefault();
32648 this.touchmoved = false;
32650 if(!this.isFitContainer){
32654 if(!this.bgimage.length || !this.html.length){
32658 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32660 this.timer = new Date().getTime();
32664 onTouchMove: function(e, el)
32666 this.touchmoved = true;
32669 onContextMenu : function(e,el)
32671 e.preventDefault();
32672 e.stopPropagation();
32676 onTouchEnd: function(e, el)
32678 // e.preventDefault();
32680 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32687 if(!this.bgimage.length || !this.html.length){
32689 if(this.href.length){
32690 window.location.href = this.href;
32696 if(!this.isFitContainer){
32700 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32702 window.location.href = this.href;
32705 //selection on single brick only
32706 selectBrick : function() {
32708 if (!this.parentId) {
32712 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32713 var index = m.selectedBrick.indexOf(this.id);
32716 m.selectedBrick.splice(index,1);
32717 this.el.removeClass(this.activeClass);
32721 for(var i = 0; i < m.selectedBrick.length; i++) {
32722 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32723 b.el.removeClass(b.activeClass);
32726 m.selectedBrick = [];
32728 m.selectedBrick.push(this.id);
32729 this.el.addClass(this.activeClass);
32735 Roo.apply(Roo.bootstrap.MasonryBrick, {
32738 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32740 * register a Masonry Brick
32741 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32744 register : function(brick)
32746 //this.groups[brick.id] = brick;
32747 this.groups.add(brick.id, brick);
32750 * fetch a masonry brick based on the masonry brick ID
32751 * @param {string} the masonry brick to add
32752 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32755 get: function(brick_id)
32757 // if (typeof(this.groups[brick_id]) == 'undefined') {
32760 // return this.groups[brick_id] ;
32762 if(this.groups.key(brick_id)) {
32763 return this.groups.key(brick_id);
32781 * @class Roo.bootstrap.Brick
32782 * @extends Roo.bootstrap.Component
32783 * Bootstrap Brick class
32786 * Create a new Brick
32787 * @param {Object} config The config object
32790 Roo.bootstrap.Brick = function(config){
32791 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32797 * When a Brick is click
32798 * @param {Roo.bootstrap.Brick} this
32799 * @param {Roo.EventObject} e
32805 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32808 * @cfg {String} title
32812 * @cfg {String} html
32816 * @cfg {String} bgimage
32820 * @cfg {String} cls
32824 * @cfg {String} href
32828 * @cfg {String} video
32832 * @cfg {Boolean} square
32836 getAutoCreate : function()
32838 var cls = 'roo-brick';
32840 if(this.href.length){
32841 cls += ' roo-brick-link';
32844 if(this.bgimage.length){
32845 cls += ' roo-brick-image';
32848 if(!this.html.length && !this.bgimage.length){
32849 cls += ' roo-brick-center-title';
32852 if(!this.html.length && this.bgimage.length){
32853 cls += ' roo-brick-bottom-title';
32857 cls += ' ' + this.cls;
32861 tag: (this.href.length) ? 'a' : 'div',
32866 cls: 'roo-brick-paragraph',
32872 if(this.href.length){
32873 cfg.href = this.href;
32876 var cn = cfg.cn[0].cn;
32878 if(this.title.length){
32881 cls: 'roo-brick-title',
32886 if(this.html.length){
32889 cls: 'roo-brick-text',
32896 if(this.bgimage.length){
32899 cls: 'roo-brick-image-view',
32907 initEvents: function()
32909 if(this.title.length || this.html.length){
32910 this.el.on('mouseenter' ,this.enter, this);
32911 this.el.on('mouseleave', this.leave, this);
32914 Roo.EventManager.onWindowResize(this.resize, this);
32916 if(this.bgimage.length){
32917 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32918 this.imageEl.on('load', this.onImageLoad, this);
32925 onImageLoad : function()
32930 resize : function()
32932 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32934 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32936 if(this.bgimage.length){
32937 var image = this.el.select('.roo-brick-image-view', true).first();
32939 image.setWidth(paragraph.getWidth());
32942 image.setHeight(paragraph.getWidth());
32945 this.el.setHeight(image.getHeight());
32946 paragraph.setHeight(image.getHeight());
32952 enter: function(e, el)
32954 e.preventDefault();
32956 if(this.bgimage.length){
32957 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32958 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32962 leave: function(e, el)
32964 e.preventDefault();
32966 if(this.bgimage.length){
32967 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32968 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32984 * @class Roo.bootstrap.NumberField
32985 * @extends Roo.bootstrap.Input
32986 * Bootstrap NumberField class
32992 * Create a new NumberField
32993 * @param {Object} config The config object
32996 Roo.bootstrap.NumberField = function(config){
32997 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33000 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33003 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33005 allowDecimals : true,
33007 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33009 decimalSeparator : ".",
33011 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33013 decimalPrecision : 2,
33015 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33017 allowNegative : true,
33019 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33021 minValue : Number.NEGATIVE_INFINITY,
33023 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33025 maxValue : Number.MAX_VALUE,
33027 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33029 minText : "The minimum value for this field is {0}",
33031 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33033 maxText : "The maximum value for this field is {0}",
33035 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33036 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33038 nanText : "{0} is not a valid number",
33040 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33045 initEvents : function()
33047 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33049 var allowed = "0123456789";
33051 if(this.allowDecimals){
33052 allowed += this.decimalSeparator;
33055 if(this.allowNegative){
33059 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33061 var keyPress = function(e){
33063 var k = e.getKey();
33065 var c = e.getCharCode();
33068 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33069 allowed.indexOf(String.fromCharCode(c)) === -1
33075 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33079 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33084 this.el.on("keypress", keyPress, this);
33087 validateValue : function(value)
33090 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33094 var num = this.parseValue(value);
33097 this.markInvalid(String.format(this.nanText, value));
33101 if(num < this.minValue){
33102 this.markInvalid(String.format(this.minText, this.minValue));
33106 if(num > this.maxValue){
33107 this.markInvalid(String.format(this.maxText, this.maxValue));
33114 getValue : function()
33116 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33119 parseValue : function(value)
33121 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33122 return isNaN(value) ? '' : value;
33125 fixPrecision : function(value)
33127 var nan = isNaN(value);
33129 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33130 return nan ? '' : value;
33132 return parseFloat(value).toFixed(this.decimalPrecision);
33135 setValue : function(v)
33137 v = this.fixPrecision(v);
33138 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33141 decimalPrecisionFcn : function(v)
33143 return Math.floor(v);
33146 beforeBlur : function()
33152 var v = this.parseValue(this.getRawValue());
33167 * @class Roo.bootstrap.DocumentSlider
33168 * @extends Roo.bootstrap.Component
33169 * Bootstrap DocumentSlider class
33172 * Create a new DocumentViewer
33173 * @param {Object} config The config object
33176 Roo.bootstrap.DocumentSlider = function(config){
33177 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33184 * Fire after initEvent
33185 * @param {Roo.bootstrap.DocumentSlider} this
33190 * Fire after update
33191 * @param {Roo.bootstrap.DocumentSlider} this
33197 * @param {Roo.bootstrap.DocumentSlider} this
33203 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33209 getAutoCreate : function()
33213 cls : 'roo-document-slider',
33217 cls : 'roo-document-slider-header',
33221 cls : 'roo-document-slider-header-title'
33227 cls : 'roo-document-slider-body',
33231 cls : 'roo-document-slider-prev',
33235 cls : 'fa fa-chevron-left'
33241 cls : 'roo-document-slider-thumb',
33245 cls : 'roo-document-slider-image'
33251 cls : 'roo-document-slider-next',
33255 cls : 'fa fa-chevron-right'
33267 initEvents : function()
33269 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33270 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33272 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33273 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33275 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33276 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33278 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33279 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33281 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33282 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33284 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33285 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33287 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33288 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33290 this.thumbEl.on('click', this.onClick, this);
33292 this.prevIndicator.on('click', this.prev, this);
33294 this.nextIndicator.on('click', this.next, this);
33298 initial : function()
33300 if(this.files.length){
33301 this.indicator = 1;
33305 this.fireEvent('initial', this);
33308 update : function()
33310 this.imageEl.attr('src', this.files[this.indicator - 1]);
33312 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33314 this.prevIndicator.show();
33316 if(this.indicator == 1){
33317 this.prevIndicator.hide();
33320 this.nextIndicator.show();
33322 if(this.indicator == this.files.length){
33323 this.nextIndicator.hide();
33326 this.thumbEl.scrollTo('top');
33328 this.fireEvent('update', this);
33331 onClick : function(e)
33333 e.preventDefault();
33335 this.fireEvent('click', this);
33340 e.preventDefault();
33342 this.indicator = Math.max(1, this.indicator - 1);
33349 e.preventDefault();
33351 this.indicator = Math.min(this.files.length, this.indicator + 1);
33365 * @class Roo.bootstrap.RadioSet
33366 * @extends Roo.bootstrap.Input
33367 * Bootstrap RadioSet class
33368 * @cfg {String} indicatorpos (left|right) default left
33369 * @cfg {Boolean} inline (true|false) inline the element (default true)
33370 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33372 * Create a new RadioSet
33373 * @param {Object} config The config object
33376 Roo.bootstrap.RadioSet = function(config){
33378 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33382 Roo.bootstrap.RadioSet.register(this);
33387 * Fires when the element is checked or unchecked.
33388 * @param {Roo.bootstrap.RadioSet} this This radio
33389 * @param {Roo.bootstrap.Radio} item The checked item
33396 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33404 indicatorpos : 'left',
33406 getAutoCreate : function()
33410 cls : 'roo-radio-set-label',
33414 html : this.fieldLabel
33419 if(this.indicatorpos == 'left'){
33422 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33423 tooltip : 'This field is required'
33428 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33429 tooltip : 'This field is required'
33435 cls : 'roo-radio-set-items'
33438 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33440 if (align === 'left' && this.fieldLabel.length) {
33443 cls : "roo-radio-set-right",
33449 if(this.labelWidth > 12){
33450 label.style = "width: " + this.labelWidth + 'px';
33453 if(this.labelWidth < 13 && this.labelmd == 0){
33454 this.labelmd = this.labelWidth;
33457 if(this.labellg > 0){
33458 label.cls += ' col-lg-' + this.labellg;
33459 items.cls += ' col-lg-' + (12 - this.labellg);
33462 if(this.labelmd > 0){
33463 label.cls += ' col-md-' + this.labelmd;
33464 items.cls += ' col-md-' + (12 - this.labelmd);
33467 if(this.labelsm > 0){
33468 label.cls += ' col-sm-' + this.labelsm;
33469 items.cls += ' col-sm-' + (12 - this.labelsm);
33472 if(this.labelxs > 0){
33473 label.cls += ' col-xs-' + this.labelxs;
33474 items.cls += ' col-xs-' + (12 - this.labelxs);
33480 cls : 'roo-radio-set',
33484 cls : 'roo-radio-set-input',
33487 value : this.value ? this.value : ''
33494 if(this.weight.length){
33495 cfg.cls += ' roo-radio-' + this.weight;
33499 cfg.cls += ' roo-radio-set-inline';
33503 ['xs','sm','md','lg'].map(function(size){
33504 if (settings[size]) {
33505 cfg.cls += ' col-' + size + '-' + settings[size];
33513 initEvents : function()
33515 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33516 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33518 if(!this.fieldLabel.length){
33519 this.labelEl.hide();
33522 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33523 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33525 this.indicatorEl().addClass('invisible');
33527 this.originalValue = this.getValue();
33531 inputEl: function ()
33533 return this.el.select('.roo-radio-set-input', true).first();
33536 getChildContainer : function()
33538 return this.itemsEl;
33541 register : function(item)
33543 this.radioes.push(item);
33547 validate : function()
33551 Roo.each(this.radioes, function(i){
33560 if(this.allowBlank) {
33564 if(this.disabled || valid){
33569 this.markInvalid();
33574 markValid : function()
33576 if(this.labelEl.isVisible(true)){
33577 this.indicatorEl().removeClass('visible');
33578 this.indicatorEl().addClass('invisible');
33581 this.el.removeClass([this.invalidClass, this.validClass]);
33582 this.el.addClass(this.validClass);
33584 this.fireEvent('valid', this);
33587 markInvalid : function(msg)
33589 if(this.allowBlank || this.disabled){
33593 if(this.labelEl.isVisible(true)){
33594 this.indicatorEl().removeClass('invisible');
33595 this.indicatorEl().addClass('visible');
33598 this.el.removeClass([this.invalidClass, this.validClass]);
33599 this.el.addClass(this.invalidClass);
33601 this.fireEvent('invalid', this, msg);
33605 setValue : function(v, suppressEvent)
33607 if(this.value === v){
33614 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33617 Roo.each(this.radioes, function(i){
33620 i.el.removeClass('checked');
33622 if(i.value === v || i.value.toString() === v.toString()){
33624 i.el.addClass('checked');
33626 if(suppressEvent !== true){
33627 this.fireEvent('check', this, i);
33636 clearInvalid : function(){
33638 if(!this.el || this.preventMark){
33642 this.el.removeClass([this.invalidClass]);
33644 this.fireEvent('valid', this);
33649 Roo.apply(Roo.bootstrap.RadioSet, {
33653 register : function(set)
33655 this.groups[set.name] = set;
33658 get: function(name)
33660 if (typeof(this.groups[name]) == 'undefined') {
33664 return this.groups[name] ;
33670 * Ext JS Library 1.1.1
33671 * Copyright(c) 2006-2007, Ext JS, LLC.
33673 * Originally Released Under LGPL - original licence link has changed is not relivant.
33676 * <script type="text/javascript">
33681 * @class Roo.bootstrap.SplitBar
33682 * @extends Roo.util.Observable
33683 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33687 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33688 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33689 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33690 split.minSize = 100;
33691 split.maxSize = 600;
33692 split.animate = true;
33693 split.on('moved', splitterMoved);
33696 * Create a new SplitBar
33697 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33698 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33699 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33700 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33701 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33702 position of the SplitBar).
33704 Roo.bootstrap.SplitBar = function(cfg){
33709 // dragElement : elm
33710 // resizingElement: el,
33712 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33713 // placement : Roo.bootstrap.SplitBar.LEFT ,
33714 // existingProxy ???
33717 this.el = Roo.get(cfg.dragElement, true);
33718 this.el.dom.unselectable = "on";
33720 this.resizingEl = Roo.get(cfg.resizingElement, true);
33724 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33725 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33728 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33731 * The minimum size of the resizing element. (Defaults to 0)
33737 * The maximum size of the resizing element. (Defaults to 2000)
33740 this.maxSize = 2000;
33743 * Whether to animate the transition to the new size
33746 this.animate = false;
33749 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33752 this.useShim = false;
33757 if(!cfg.existingProxy){
33759 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33761 this.proxy = Roo.get(cfg.existingProxy).dom;
33764 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33767 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33770 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33773 this.dragSpecs = {};
33776 * @private The adapter to use to positon and resize elements
33778 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33779 this.adapter.init(this);
33781 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33783 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33784 this.el.addClass("roo-splitbar-h");
33787 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33788 this.el.addClass("roo-splitbar-v");
33794 * Fires when the splitter is moved (alias for {@link #event-moved})
33795 * @param {Roo.bootstrap.SplitBar} this
33796 * @param {Number} newSize the new width or height
33801 * Fires when the splitter is moved
33802 * @param {Roo.bootstrap.SplitBar} this
33803 * @param {Number} newSize the new width or height
33807 * @event beforeresize
33808 * Fires before the splitter is dragged
33809 * @param {Roo.bootstrap.SplitBar} this
33811 "beforeresize" : true,
33813 "beforeapply" : true
33816 Roo.util.Observable.call(this);
33819 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33820 onStartProxyDrag : function(x, y){
33821 this.fireEvent("beforeresize", this);
33823 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33825 o.enableDisplayMode("block");
33826 // all splitbars share the same overlay
33827 Roo.bootstrap.SplitBar.prototype.overlay = o;
33829 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33830 this.overlay.show();
33831 Roo.get(this.proxy).setDisplayed("block");
33832 var size = this.adapter.getElementSize(this);
33833 this.activeMinSize = this.getMinimumSize();;
33834 this.activeMaxSize = this.getMaximumSize();;
33835 var c1 = size - this.activeMinSize;
33836 var c2 = Math.max(this.activeMaxSize - size, 0);
33837 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33838 this.dd.resetConstraints();
33839 this.dd.setXConstraint(
33840 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33841 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33843 this.dd.setYConstraint(0, 0);
33845 this.dd.resetConstraints();
33846 this.dd.setXConstraint(0, 0);
33847 this.dd.setYConstraint(
33848 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33849 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33852 this.dragSpecs.startSize = size;
33853 this.dragSpecs.startPoint = [x, y];
33854 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33858 * @private Called after the drag operation by the DDProxy
33860 onEndProxyDrag : function(e){
33861 Roo.get(this.proxy).setDisplayed(false);
33862 var endPoint = Roo.lib.Event.getXY(e);
33864 this.overlay.hide();
33867 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33868 newSize = this.dragSpecs.startSize +
33869 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33870 endPoint[0] - this.dragSpecs.startPoint[0] :
33871 this.dragSpecs.startPoint[0] - endPoint[0]
33874 newSize = this.dragSpecs.startSize +
33875 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33876 endPoint[1] - this.dragSpecs.startPoint[1] :
33877 this.dragSpecs.startPoint[1] - endPoint[1]
33880 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33881 if(newSize != this.dragSpecs.startSize){
33882 if(this.fireEvent('beforeapply', this, newSize) !== false){
33883 this.adapter.setElementSize(this, newSize);
33884 this.fireEvent("moved", this, newSize);
33885 this.fireEvent("resize", this, newSize);
33891 * Get the adapter this SplitBar uses
33892 * @return The adapter object
33894 getAdapter : function(){
33895 return this.adapter;
33899 * Set the adapter this SplitBar uses
33900 * @param {Object} adapter A SplitBar adapter object
33902 setAdapter : function(adapter){
33903 this.adapter = adapter;
33904 this.adapter.init(this);
33908 * Gets the minimum size for the resizing element
33909 * @return {Number} The minimum size
33911 getMinimumSize : function(){
33912 return this.minSize;
33916 * Sets the minimum size for the resizing element
33917 * @param {Number} minSize The minimum size
33919 setMinimumSize : function(minSize){
33920 this.minSize = minSize;
33924 * Gets the maximum size for the resizing element
33925 * @return {Number} The maximum size
33927 getMaximumSize : function(){
33928 return this.maxSize;
33932 * Sets the maximum size for the resizing element
33933 * @param {Number} maxSize The maximum size
33935 setMaximumSize : function(maxSize){
33936 this.maxSize = maxSize;
33940 * Sets the initialize size for the resizing element
33941 * @param {Number} size The initial size
33943 setCurrentSize : function(size){
33944 var oldAnimate = this.animate;
33945 this.animate = false;
33946 this.adapter.setElementSize(this, size);
33947 this.animate = oldAnimate;
33951 * Destroy this splitbar.
33952 * @param {Boolean} removeEl True to remove the element
33954 destroy : function(removeEl){
33956 this.shim.remove();
33959 this.proxy.parentNode.removeChild(this.proxy);
33967 * @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.
33969 Roo.bootstrap.SplitBar.createProxy = function(dir){
33970 var proxy = new Roo.Element(document.createElement("div"));
33971 proxy.unselectable();
33972 var cls = 'roo-splitbar-proxy';
33973 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33974 document.body.appendChild(proxy.dom);
33979 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33980 * Default Adapter. It assumes the splitter and resizing element are not positioned
33981 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33983 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33986 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33987 // do nothing for now
33988 init : function(s){
33992 * Called before drag operations to get the current size of the resizing element.
33993 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33995 getElementSize : function(s){
33996 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33997 return s.resizingEl.getWidth();
33999 return s.resizingEl.getHeight();
34004 * Called after drag operations to set the size of the resizing element.
34005 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34006 * @param {Number} newSize The new size to set
34007 * @param {Function} onComplete A function to be invoked when resizing is complete
34009 setElementSize : function(s, newSize, onComplete){
34010 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34012 s.resizingEl.setWidth(newSize);
34014 onComplete(s, newSize);
34017 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34022 s.resizingEl.setHeight(newSize);
34024 onComplete(s, newSize);
34027 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34034 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34035 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34036 * Adapter that moves the splitter element to align with the resized sizing element.
34037 * Used with an absolute positioned SplitBar.
34038 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34039 * document.body, make sure you assign an id to the body element.
34041 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34042 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34043 this.container = Roo.get(container);
34046 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34047 init : function(s){
34048 this.basic.init(s);
34051 getElementSize : function(s){
34052 return this.basic.getElementSize(s);
34055 setElementSize : function(s, newSize, onComplete){
34056 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34059 moveSplitter : function(s){
34060 var yes = Roo.bootstrap.SplitBar;
34061 switch(s.placement){
34063 s.el.setX(s.resizingEl.getRight());
34066 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34069 s.el.setY(s.resizingEl.getBottom());
34072 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34079 * Orientation constant - Create a vertical SplitBar
34083 Roo.bootstrap.SplitBar.VERTICAL = 1;
34086 * Orientation constant - Create a horizontal SplitBar
34090 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34093 * Placement constant - The resizing element is to the left of the splitter element
34097 Roo.bootstrap.SplitBar.LEFT = 1;
34100 * Placement constant - The resizing element is to the right of the splitter element
34104 Roo.bootstrap.SplitBar.RIGHT = 2;
34107 * Placement constant - The resizing element is positioned above the splitter element
34111 Roo.bootstrap.SplitBar.TOP = 3;
34114 * Placement constant - The resizing element is positioned under splitter element
34118 Roo.bootstrap.SplitBar.BOTTOM = 4;
34119 Roo.namespace("Roo.bootstrap.layout");/*
34121 * Ext JS Library 1.1.1
34122 * Copyright(c) 2006-2007, Ext JS, LLC.
34124 * Originally Released Under LGPL - original licence link has changed is not relivant.
34127 * <script type="text/javascript">
34131 * @class Roo.bootstrap.layout.Manager
34132 * @extends Roo.bootstrap.Component
34133 * Base class for layout managers.
34135 Roo.bootstrap.layout.Manager = function(config)
34137 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34143 /** false to disable window resize monitoring @type Boolean */
34144 this.monitorWindowResize = true;
34149 * Fires when a layout is performed.
34150 * @param {Roo.LayoutManager} this
34154 * @event regionresized
34155 * Fires when the user resizes a region.
34156 * @param {Roo.LayoutRegion} region The resized region
34157 * @param {Number} newSize The new size (width for east/west, height for north/south)
34159 "regionresized" : true,
34161 * @event regioncollapsed
34162 * Fires when a region is collapsed.
34163 * @param {Roo.LayoutRegion} region The collapsed region
34165 "regioncollapsed" : true,
34167 * @event regionexpanded
34168 * Fires when a region is expanded.
34169 * @param {Roo.LayoutRegion} region The expanded region
34171 "regionexpanded" : true
34173 this.updating = false;
34176 this.el = Roo.get(config.el);
34182 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34187 monitorWindowResize : true,
34193 onRender : function(ct, position)
34196 this.el = Roo.get(ct);
34199 //this.fireEvent('render',this);
34203 initEvents: function()
34207 // ie scrollbar fix
34208 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34209 document.body.scroll = "no";
34210 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34211 this.el.position('relative');
34213 this.id = this.el.id;
34214 this.el.addClass("roo-layout-container");
34215 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34216 if(this.el.dom != document.body ) {
34217 this.el.on('resize', this.layout,this);
34218 this.el.on('show', this.layout,this);
34224 * Returns true if this layout is currently being updated
34225 * @return {Boolean}
34227 isUpdating : function(){
34228 return this.updating;
34232 * Suspend the LayoutManager from doing auto-layouts while
34233 * making multiple add or remove calls
34235 beginUpdate : function(){
34236 this.updating = true;
34240 * Restore auto-layouts and optionally disable the manager from performing a layout
34241 * @param {Boolean} noLayout true to disable a layout update
34243 endUpdate : function(noLayout){
34244 this.updating = false;
34250 layout: function(){
34254 onRegionResized : function(region, newSize){
34255 this.fireEvent("regionresized", region, newSize);
34259 onRegionCollapsed : function(region){
34260 this.fireEvent("regioncollapsed", region);
34263 onRegionExpanded : function(region){
34264 this.fireEvent("regionexpanded", region);
34268 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34269 * performs box-model adjustments.
34270 * @return {Object} The size as an object {width: (the width), height: (the height)}
34272 getViewSize : function()
34275 if(this.el.dom != document.body){
34276 size = this.el.getSize();
34278 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34280 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34281 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34286 * Returns the Element this layout is bound to.
34287 * @return {Roo.Element}
34289 getEl : function(){
34294 * Returns the specified region.
34295 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34296 * @return {Roo.LayoutRegion}
34298 getRegion : function(target){
34299 return this.regions[target.toLowerCase()];
34302 onWindowResize : function(){
34303 if(this.monitorWindowResize){
34310 * Ext JS Library 1.1.1
34311 * Copyright(c) 2006-2007, Ext JS, LLC.
34313 * Originally Released Under LGPL - original licence link has changed is not relivant.
34316 * <script type="text/javascript">
34319 * @class Roo.bootstrap.layout.Border
34320 * @extends Roo.bootstrap.layout.Manager
34321 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34322 * please see: examples/bootstrap/nested.html<br><br>
34324 <b>The container the layout is rendered into can be either the body element or any other element.
34325 If it is not the body element, the container needs to either be an absolute positioned element,
34326 or you will need to add "position:relative" to the css of the container. You will also need to specify
34327 the container size if it is not the body element.</b>
34330 * Create a new Border
34331 * @param {Object} config Configuration options
34333 Roo.bootstrap.layout.Border = function(config){
34334 config = config || {};
34335 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34339 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34340 if(config[region]){
34341 config[region].region = region;
34342 this.addRegion(config[region]);
34348 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34350 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34352 * Creates and adds a new region if it doesn't already exist.
34353 * @param {String} target The target region key (north, south, east, west or center).
34354 * @param {Object} config The regions config object
34355 * @return {BorderLayoutRegion} The new region
34357 addRegion : function(config)
34359 if(!this.regions[config.region]){
34360 var r = this.factory(config);
34361 this.bindRegion(r);
34363 return this.regions[config.region];
34367 bindRegion : function(r){
34368 this.regions[r.config.region] = r;
34370 r.on("visibilitychange", this.layout, this);
34371 r.on("paneladded", this.layout, this);
34372 r.on("panelremoved", this.layout, this);
34373 r.on("invalidated", this.layout, this);
34374 r.on("resized", this.onRegionResized, this);
34375 r.on("collapsed", this.onRegionCollapsed, this);
34376 r.on("expanded", this.onRegionExpanded, this);
34380 * Performs a layout update.
34382 layout : function()
34384 if(this.updating) {
34388 // render all the rebions if they have not been done alreayd?
34389 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34390 if(this.regions[region] && !this.regions[region].bodyEl){
34391 this.regions[region].onRender(this.el)
34395 var size = this.getViewSize();
34396 var w = size.width;
34397 var h = size.height;
34402 //var x = 0, y = 0;
34404 var rs = this.regions;
34405 var north = rs["north"];
34406 var south = rs["south"];
34407 var west = rs["west"];
34408 var east = rs["east"];
34409 var center = rs["center"];
34410 //if(this.hideOnLayout){ // not supported anymore
34411 //c.el.setStyle("display", "none");
34413 if(north && north.isVisible()){
34414 var b = north.getBox();
34415 var m = north.getMargins();
34416 b.width = w - (m.left+m.right);
34419 centerY = b.height + b.y + m.bottom;
34420 centerH -= centerY;
34421 north.updateBox(this.safeBox(b));
34423 if(south && south.isVisible()){
34424 var b = south.getBox();
34425 var m = south.getMargins();
34426 b.width = w - (m.left+m.right);
34428 var totalHeight = (b.height + m.top + m.bottom);
34429 b.y = h - totalHeight + m.top;
34430 centerH -= totalHeight;
34431 south.updateBox(this.safeBox(b));
34433 if(west && west.isVisible()){
34434 var b = west.getBox();
34435 var m = west.getMargins();
34436 b.height = centerH - (m.top+m.bottom);
34438 b.y = centerY + m.top;
34439 var totalWidth = (b.width + m.left + m.right);
34440 centerX += totalWidth;
34441 centerW -= totalWidth;
34442 west.updateBox(this.safeBox(b));
34444 if(east && east.isVisible()){
34445 var b = east.getBox();
34446 var m = east.getMargins();
34447 b.height = centerH - (m.top+m.bottom);
34448 var totalWidth = (b.width + m.left + m.right);
34449 b.x = w - totalWidth + m.left;
34450 b.y = centerY + m.top;
34451 centerW -= totalWidth;
34452 east.updateBox(this.safeBox(b));
34455 var m = center.getMargins();
34457 x: centerX + m.left,
34458 y: centerY + m.top,
34459 width: centerW - (m.left+m.right),
34460 height: centerH - (m.top+m.bottom)
34462 //if(this.hideOnLayout){
34463 //center.el.setStyle("display", "block");
34465 center.updateBox(this.safeBox(centerBox));
34468 this.fireEvent("layout", this);
34472 safeBox : function(box){
34473 box.width = Math.max(0, box.width);
34474 box.height = Math.max(0, box.height);
34479 * Adds a ContentPanel (or subclass) to this layout.
34480 * @param {String} target The target region key (north, south, east, west or center).
34481 * @param {Roo.ContentPanel} panel The panel to add
34482 * @return {Roo.ContentPanel} The added panel
34484 add : function(target, panel){
34486 target = target.toLowerCase();
34487 return this.regions[target].add(panel);
34491 * Remove a ContentPanel (or subclass) to this layout.
34492 * @param {String} target The target region key (north, south, east, west or center).
34493 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34494 * @return {Roo.ContentPanel} The removed panel
34496 remove : function(target, panel){
34497 target = target.toLowerCase();
34498 return this.regions[target].remove(panel);
34502 * Searches all regions for a panel with the specified id
34503 * @param {String} panelId
34504 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34506 findPanel : function(panelId){
34507 var rs = this.regions;
34508 for(var target in rs){
34509 if(typeof rs[target] != "function"){
34510 var p = rs[target].getPanel(panelId);
34520 * Searches all regions for a panel with the specified id and activates (shows) it.
34521 * @param {String/ContentPanel} panelId The panels id or the panel itself
34522 * @return {Roo.ContentPanel} The shown panel or null
34524 showPanel : function(panelId) {
34525 var rs = this.regions;
34526 for(var target in rs){
34527 var r = rs[target];
34528 if(typeof r != "function"){
34529 if(r.hasPanel(panelId)){
34530 return r.showPanel(panelId);
34538 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34539 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34542 restoreState : function(provider){
34544 provider = Roo.state.Manager;
34546 var sm = new Roo.LayoutStateManager();
34547 sm.init(this, provider);
34553 * Adds a xtype elements to the layout.
34557 xtype : 'ContentPanel',
34564 xtype : 'NestedLayoutPanel',
34570 items : [ ... list of content panels or nested layout panels.. ]
34574 * @param {Object} cfg Xtype definition of item to add.
34576 addxtype : function(cfg)
34578 // basically accepts a pannel...
34579 // can accept a layout region..!?!?
34580 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34583 // theory? children can only be panels??
34585 //if (!cfg.xtype.match(/Panel$/)) {
34590 if (typeof(cfg.region) == 'undefined') {
34591 Roo.log("Failed to add Panel, region was not set");
34595 var region = cfg.region;
34601 xitems = cfg.items;
34608 case 'Content': // ContentPanel (el, cfg)
34609 case 'Scroll': // ContentPanel (el, cfg)
34611 cfg.autoCreate = true;
34612 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34614 // var el = this.el.createChild();
34615 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34618 this.add(region, ret);
34622 case 'TreePanel': // our new panel!
34623 cfg.el = this.el.createChild();
34624 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34625 this.add(region, ret);
34630 // create a new Layout (which is a Border Layout...
34632 var clayout = cfg.layout;
34633 clayout.el = this.el.createChild();
34634 clayout.items = clayout.items || [];
34638 // replace this exitems with the clayout ones..
34639 xitems = clayout.items;
34641 // force background off if it's in center...
34642 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34643 cfg.background = false;
34645 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34648 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34649 //console.log('adding nested layout panel ' + cfg.toSource());
34650 this.add(region, ret);
34651 nb = {}; /// find first...
34656 // needs grid and region
34658 //var el = this.getRegion(region).el.createChild();
34660 *var el = this.el.createChild();
34661 // create the grid first...
34662 cfg.grid.container = el;
34663 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34666 if (region == 'center' && this.active ) {
34667 cfg.background = false;
34670 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34672 this.add(region, ret);
34674 if (cfg.background) {
34675 // render grid on panel activation (if panel background)
34676 ret.on('activate', function(gp) {
34677 if (!gp.grid.rendered) {
34678 // gp.grid.render(el);
34682 // cfg.grid.render(el);
34688 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34689 // it was the old xcomponent building that caused this before.
34690 // espeically if border is the top element in the tree.
34700 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34702 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34703 this.add(region, ret);
34707 throw "Can not add '" + cfg.xtype + "' to Border";
34713 this.beginUpdate();
34717 Roo.each(xitems, function(i) {
34718 region = nb && i.region ? i.region : false;
34720 var add = ret.addxtype(i);
34723 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34724 if (!i.background) {
34725 abn[region] = nb[region] ;
34732 // make the last non-background panel active..
34733 //if (nb) { Roo.log(abn); }
34736 for(var r in abn) {
34737 region = this.getRegion(r);
34739 // tried using nb[r], but it does not work..
34741 region.showPanel(abn[r]);
34752 factory : function(cfg)
34755 var validRegions = Roo.bootstrap.layout.Border.regions;
34757 var target = cfg.region;
34760 var r = Roo.bootstrap.layout;
34764 return new r.North(cfg);
34766 return new r.South(cfg);
34768 return new r.East(cfg);
34770 return new r.West(cfg);
34772 return new r.Center(cfg);
34774 throw 'Layout region "'+target+'" not supported.';
34781 * Ext JS Library 1.1.1
34782 * Copyright(c) 2006-2007, Ext JS, LLC.
34784 * Originally Released Under LGPL - original licence link has changed is not relivant.
34787 * <script type="text/javascript">
34791 * @class Roo.bootstrap.layout.Basic
34792 * @extends Roo.util.Observable
34793 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34794 * and does not have a titlebar, tabs or any other features. All it does is size and position
34795 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34796 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34797 * @cfg {string} region the region that it inhabits..
34798 * @cfg {bool} skipConfig skip config?
34802 Roo.bootstrap.layout.Basic = function(config){
34804 this.mgr = config.mgr;
34806 this.position = config.region;
34808 var skipConfig = config.skipConfig;
34812 * @scope Roo.BasicLayoutRegion
34816 * @event beforeremove
34817 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34818 * @param {Roo.LayoutRegion} this
34819 * @param {Roo.ContentPanel} panel The panel
34820 * @param {Object} e The cancel event object
34822 "beforeremove" : true,
34824 * @event invalidated
34825 * Fires when the layout for this region is changed.
34826 * @param {Roo.LayoutRegion} this
34828 "invalidated" : true,
34830 * @event visibilitychange
34831 * Fires when this region is shown or hidden
34832 * @param {Roo.LayoutRegion} this
34833 * @param {Boolean} visibility true or false
34835 "visibilitychange" : true,
34837 * @event paneladded
34838 * Fires when a panel is added.
34839 * @param {Roo.LayoutRegion} this
34840 * @param {Roo.ContentPanel} panel The panel
34842 "paneladded" : true,
34844 * @event panelremoved
34845 * Fires when a panel is removed.
34846 * @param {Roo.LayoutRegion} this
34847 * @param {Roo.ContentPanel} panel The panel
34849 "panelremoved" : true,
34851 * @event beforecollapse
34852 * Fires when this region before collapse.
34853 * @param {Roo.LayoutRegion} this
34855 "beforecollapse" : true,
34858 * Fires when this region is collapsed.
34859 * @param {Roo.LayoutRegion} this
34861 "collapsed" : true,
34864 * Fires when this region is expanded.
34865 * @param {Roo.LayoutRegion} this
34870 * Fires when this region is slid into view.
34871 * @param {Roo.LayoutRegion} this
34873 "slideshow" : true,
34876 * Fires when this region slides out of view.
34877 * @param {Roo.LayoutRegion} this
34879 "slidehide" : true,
34881 * @event panelactivated
34882 * Fires when a panel is activated.
34883 * @param {Roo.LayoutRegion} this
34884 * @param {Roo.ContentPanel} panel The activated panel
34886 "panelactivated" : true,
34889 * Fires when the user resizes this region.
34890 * @param {Roo.LayoutRegion} this
34891 * @param {Number} newSize The new size (width for east/west, height for north/south)
34895 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34896 this.panels = new Roo.util.MixedCollection();
34897 this.panels.getKey = this.getPanelId.createDelegate(this);
34899 this.activePanel = null;
34900 // ensure listeners are added...
34902 if (config.listeners || config.events) {
34903 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34904 listeners : config.listeners || {},
34905 events : config.events || {}
34909 if(skipConfig !== true){
34910 this.applyConfig(config);
34914 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34916 getPanelId : function(p){
34920 applyConfig : function(config){
34921 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34922 this.config = config;
34927 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34928 * the width, for horizontal (north, south) the height.
34929 * @param {Number} newSize The new width or height
34931 resizeTo : function(newSize){
34932 var el = this.el ? this.el :
34933 (this.activePanel ? this.activePanel.getEl() : null);
34935 switch(this.position){
34938 el.setWidth(newSize);
34939 this.fireEvent("resized", this, newSize);
34943 el.setHeight(newSize);
34944 this.fireEvent("resized", this, newSize);
34950 getBox : function(){
34951 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34954 getMargins : function(){
34955 return this.margins;
34958 updateBox : function(box){
34960 var el = this.activePanel.getEl();
34961 el.dom.style.left = box.x + "px";
34962 el.dom.style.top = box.y + "px";
34963 this.activePanel.setSize(box.width, box.height);
34967 * Returns the container element for this region.
34968 * @return {Roo.Element}
34970 getEl : function(){
34971 return this.activePanel;
34975 * Returns true if this region is currently visible.
34976 * @return {Boolean}
34978 isVisible : function(){
34979 return this.activePanel ? true : false;
34982 setActivePanel : function(panel){
34983 panel = this.getPanel(panel);
34984 if(this.activePanel && this.activePanel != panel){
34985 this.activePanel.setActiveState(false);
34986 this.activePanel.getEl().setLeftTop(-10000,-10000);
34988 this.activePanel = panel;
34989 panel.setActiveState(true);
34991 panel.setSize(this.box.width, this.box.height);
34993 this.fireEvent("panelactivated", this, panel);
34994 this.fireEvent("invalidated");
34998 * Show the specified panel.
34999 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35000 * @return {Roo.ContentPanel} The shown panel or null
35002 showPanel : function(panel){
35003 panel = this.getPanel(panel);
35005 this.setActivePanel(panel);
35011 * Get the active panel for this region.
35012 * @return {Roo.ContentPanel} The active panel or null
35014 getActivePanel : function(){
35015 return this.activePanel;
35019 * Add the passed ContentPanel(s)
35020 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35021 * @return {Roo.ContentPanel} The panel added (if only one was added)
35023 add : function(panel){
35024 if(arguments.length > 1){
35025 for(var i = 0, len = arguments.length; i < len; i++) {
35026 this.add(arguments[i]);
35030 if(this.hasPanel(panel)){
35031 this.showPanel(panel);
35034 var el = panel.getEl();
35035 if(el.dom.parentNode != this.mgr.el.dom){
35036 this.mgr.el.dom.appendChild(el.dom);
35038 if(panel.setRegion){
35039 panel.setRegion(this);
35041 this.panels.add(panel);
35042 el.setStyle("position", "absolute");
35043 if(!panel.background){
35044 this.setActivePanel(panel);
35045 if(this.config.initialSize && this.panels.getCount()==1){
35046 this.resizeTo(this.config.initialSize);
35049 this.fireEvent("paneladded", this, panel);
35054 * Returns true if the panel is in this region.
35055 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35056 * @return {Boolean}
35058 hasPanel : function(panel){
35059 if(typeof panel == "object"){ // must be panel obj
35060 panel = panel.getId();
35062 return this.getPanel(panel) ? true : false;
35066 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35067 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35068 * @param {Boolean} preservePanel Overrides the config preservePanel option
35069 * @return {Roo.ContentPanel} The panel that was removed
35071 remove : function(panel, preservePanel){
35072 panel = this.getPanel(panel);
35077 this.fireEvent("beforeremove", this, panel, e);
35078 if(e.cancel === true){
35081 var panelId = panel.getId();
35082 this.panels.removeKey(panelId);
35087 * Returns the panel specified or null if it's not in this region.
35088 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35089 * @return {Roo.ContentPanel}
35091 getPanel : function(id){
35092 if(typeof id == "object"){ // must be panel obj
35095 return this.panels.get(id);
35099 * Returns this regions position (north/south/east/west/center).
35102 getPosition: function(){
35103 return this.position;
35107 * Ext JS Library 1.1.1
35108 * Copyright(c) 2006-2007, Ext JS, LLC.
35110 * Originally Released Under LGPL - original licence link has changed is not relivant.
35113 * <script type="text/javascript">
35117 * @class Roo.bootstrap.layout.Region
35118 * @extends Roo.bootstrap.layout.Basic
35119 * This class represents a region in a layout manager.
35121 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35122 * @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})
35123 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35124 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35125 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35126 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35127 * @cfg {String} title The title for the region (overrides panel titles)
35128 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35129 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35130 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35131 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35132 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35133 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35134 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35135 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35136 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35137 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35139 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35140 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35141 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35142 * @cfg {Number} width For East/West panels
35143 * @cfg {Number} height For North/South panels
35144 * @cfg {Boolean} split To show the splitter
35145 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35147 * @cfg {string} cls Extra CSS classes to add to region
35149 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35150 * @cfg {string} region the region that it inhabits..
35153 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35154 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35156 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35157 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35158 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35160 Roo.bootstrap.layout.Region = function(config)
35162 this.applyConfig(config);
35164 var mgr = config.mgr;
35165 var pos = config.region;
35166 config.skipConfig = true;
35167 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35170 this.onRender(mgr.el);
35173 this.visible = true;
35174 this.collapsed = false;
35175 this.unrendered_panels = [];
35178 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35180 position: '', // set by wrapper (eg. north/south etc..)
35181 unrendered_panels : null, // unrendered panels.
35182 createBody : function(){
35183 /** This region's body element
35184 * @type Roo.Element */
35185 this.bodyEl = this.el.createChild({
35187 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35191 onRender: function(ctr, pos)
35193 var dh = Roo.DomHelper;
35194 /** This region's container element
35195 * @type Roo.Element */
35196 this.el = dh.append(ctr.dom, {
35198 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35200 /** This region's title element
35201 * @type Roo.Element */
35203 this.titleEl = dh.append(this.el.dom,
35206 unselectable: "on",
35207 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35209 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35210 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35213 this.titleEl.enableDisplayMode();
35214 /** This region's title text element
35215 * @type HTMLElement */
35216 this.titleTextEl = this.titleEl.dom.firstChild;
35217 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35219 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35220 this.closeBtn.enableDisplayMode();
35221 this.closeBtn.on("click", this.closeClicked, this);
35222 this.closeBtn.hide();
35224 this.createBody(this.config);
35225 if(this.config.hideWhenEmpty){
35227 this.on("paneladded", this.validateVisibility, this);
35228 this.on("panelremoved", this.validateVisibility, this);
35230 if(this.autoScroll){
35231 this.bodyEl.setStyle("overflow", "auto");
35233 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35235 //if(c.titlebar !== false){
35236 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35237 this.titleEl.hide();
35239 this.titleEl.show();
35240 if(this.config.title){
35241 this.titleTextEl.innerHTML = this.config.title;
35245 if(this.config.collapsed){
35246 this.collapse(true);
35248 if(this.config.hidden){
35252 if (this.unrendered_panels && this.unrendered_panels.length) {
35253 for (var i =0;i< this.unrendered_panels.length; i++) {
35254 this.add(this.unrendered_panels[i]);
35256 this.unrendered_panels = null;
35262 applyConfig : function(c)
35265 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35266 var dh = Roo.DomHelper;
35267 if(c.titlebar !== false){
35268 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35269 this.collapseBtn.on("click", this.collapse, this);
35270 this.collapseBtn.enableDisplayMode();
35272 if(c.showPin === true || this.showPin){
35273 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35274 this.stickBtn.enableDisplayMode();
35275 this.stickBtn.on("click", this.expand, this);
35276 this.stickBtn.hide();
35281 /** This region's collapsed element
35282 * @type Roo.Element */
35285 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35286 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35289 if(c.floatable !== false){
35290 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35291 this.collapsedEl.on("click", this.collapseClick, this);
35294 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35295 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35296 id: "message", unselectable: "on", style:{"float":"left"}});
35297 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35299 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35300 this.expandBtn.on("click", this.expand, this);
35304 if(this.collapseBtn){
35305 this.collapseBtn.setVisible(c.collapsible == true);
35308 this.cmargins = c.cmargins || this.cmargins ||
35309 (this.position == "west" || this.position == "east" ?
35310 {top: 0, left: 2, right:2, bottom: 0} :
35311 {top: 2, left: 0, right:0, bottom: 2});
35313 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35316 this.bottomTabs = c.tabPosition != "top";
35318 this.autoScroll = c.autoScroll || false;
35323 this.duration = c.duration || .30;
35324 this.slideDuration = c.slideDuration || .45;
35329 * Returns true if this region is currently visible.
35330 * @return {Boolean}
35332 isVisible : function(){
35333 return this.visible;
35337 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35338 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35340 //setCollapsedTitle : function(title){
35341 // title = title || " ";
35342 // if(this.collapsedTitleTextEl){
35343 // this.collapsedTitleTextEl.innerHTML = title;
35347 getBox : function(){
35349 // if(!this.collapsed){
35350 b = this.el.getBox(false, true);
35352 // b = this.collapsedEl.getBox(false, true);
35357 getMargins : function(){
35358 return this.margins;
35359 //return this.collapsed ? this.cmargins : this.margins;
35362 highlight : function(){
35363 this.el.addClass("x-layout-panel-dragover");
35366 unhighlight : function(){
35367 this.el.removeClass("x-layout-panel-dragover");
35370 updateBox : function(box)
35372 if (!this.bodyEl) {
35373 return; // not rendered yet..
35377 if(!this.collapsed){
35378 this.el.dom.style.left = box.x + "px";
35379 this.el.dom.style.top = box.y + "px";
35380 this.updateBody(box.width, box.height);
35382 this.collapsedEl.dom.style.left = box.x + "px";
35383 this.collapsedEl.dom.style.top = box.y + "px";
35384 this.collapsedEl.setSize(box.width, box.height);
35387 this.tabs.autoSizeTabs();
35391 updateBody : function(w, h)
35394 this.el.setWidth(w);
35395 w -= this.el.getBorderWidth("rl");
35396 if(this.config.adjustments){
35397 w += this.config.adjustments[0];
35400 if(h !== null && h > 0){
35401 this.el.setHeight(h);
35402 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35403 h -= this.el.getBorderWidth("tb");
35404 if(this.config.adjustments){
35405 h += this.config.adjustments[1];
35407 this.bodyEl.setHeight(h);
35409 h = this.tabs.syncHeight(h);
35412 if(this.panelSize){
35413 w = w !== null ? w : this.panelSize.width;
35414 h = h !== null ? h : this.panelSize.height;
35416 if(this.activePanel){
35417 var el = this.activePanel.getEl();
35418 w = w !== null ? w : el.getWidth();
35419 h = h !== null ? h : el.getHeight();
35420 this.panelSize = {width: w, height: h};
35421 this.activePanel.setSize(w, h);
35423 if(Roo.isIE && this.tabs){
35424 this.tabs.el.repaint();
35429 * Returns the container element for this region.
35430 * @return {Roo.Element}
35432 getEl : function(){
35437 * Hides this region.
35440 //if(!this.collapsed){
35441 this.el.dom.style.left = "-2000px";
35444 // this.collapsedEl.dom.style.left = "-2000px";
35445 // this.collapsedEl.hide();
35447 this.visible = false;
35448 this.fireEvent("visibilitychange", this, false);
35452 * Shows this region if it was previously hidden.
35455 //if(!this.collapsed){
35458 // this.collapsedEl.show();
35460 this.visible = true;
35461 this.fireEvent("visibilitychange", this, true);
35464 closeClicked : function(){
35465 if(this.activePanel){
35466 this.remove(this.activePanel);
35470 collapseClick : function(e){
35472 e.stopPropagation();
35475 e.stopPropagation();
35481 * Collapses this region.
35482 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35485 collapse : function(skipAnim, skipCheck = false){
35486 if(this.collapsed) {
35490 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35492 this.collapsed = true;
35494 this.split.el.hide();
35496 if(this.config.animate && skipAnim !== true){
35497 this.fireEvent("invalidated", this);
35498 this.animateCollapse();
35500 this.el.setLocation(-20000,-20000);
35502 this.collapsedEl.show();
35503 this.fireEvent("collapsed", this);
35504 this.fireEvent("invalidated", this);
35510 animateCollapse : function(){
35515 * Expands this region if it was previously collapsed.
35516 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35517 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35520 expand : function(e, skipAnim){
35522 e.stopPropagation();
35524 if(!this.collapsed || this.el.hasActiveFx()) {
35528 this.afterSlideIn();
35531 this.collapsed = false;
35532 if(this.config.animate && skipAnim !== true){
35533 this.animateExpand();
35537 this.split.el.show();
35539 this.collapsedEl.setLocation(-2000,-2000);
35540 this.collapsedEl.hide();
35541 this.fireEvent("invalidated", this);
35542 this.fireEvent("expanded", this);
35546 animateExpand : function(){
35550 initTabs : function()
35552 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35554 var ts = new Roo.bootstrap.panel.Tabs({
35555 el: this.bodyEl.dom,
35556 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35557 disableTooltips: this.config.disableTabTips,
35558 toolbar : this.config.toolbar
35561 if(this.config.hideTabs){
35562 ts.stripWrap.setDisplayed(false);
35565 ts.resizeTabs = this.config.resizeTabs === true;
35566 ts.minTabWidth = this.config.minTabWidth || 40;
35567 ts.maxTabWidth = this.config.maxTabWidth || 250;
35568 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35569 ts.monitorResize = false;
35570 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35571 ts.bodyEl.addClass('roo-layout-tabs-body');
35572 this.panels.each(this.initPanelAsTab, this);
35575 initPanelAsTab : function(panel){
35576 var ti = this.tabs.addTab(
35580 this.config.closeOnTab && panel.isClosable(),
35583 if(panel.tabTip !== undefined){
35584 ti.setTooltip(panel.tabTip);
35586 ti.on("activate", function(){
35587 this.setActivePanel(panel);
35590 if(this.config.closeOnTab){
35591 ti.on("beforeclose", function(t, e){
35593 this.remove(panel);
35597 panel.tabItem = ti;
35602 updatePanelTitle : function(panel, title)
35604 if(this.activePanel == panel){
35605 this.updateTitle(title);
35608 var ti = this.tabs.getTab(panel.getEl().id);
35610 if(panel.tabTip !== undefined){
35611 ti.setTooltip(panel.tabTip);
35616 updateTitle : function(title){
35617 if(this.titleTextEl && !this.config.title){
35618 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35622 setActivePanel : function(panel)
35624 panel = this.getPanel(panel);
35625 if(this.activePanel && this.activePanel != panel){
35626 if(this.activePanel.setActiveState(false) === false){
35630 this.activePanel = panel;
35631 panel.setActiveState(true);
35632 if(this.panelSize){
35633 panel.setSize(this.panelSize.width, this.panelSize.height);
35636 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35638 this.updateTitle(panel.getTitle());
35640 this.fireEvent("invalidated", this);
35642 this.fireEvent("panelactivated", this, panel);
35646 * Shows the specified panel.
35647 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35648 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35650 showPanel : function(panel)
35652 panel = this.getPanel(panel);
35655 var tab = this.tabs.getTab(panel.getEl().id);
35656 if(tab.isHidden()){
35657 this.tabs.unhideTab(tab.id);
35661 this.setActivePanel(panel);
35668 * Get the active panel for this region.
35669 * @return {Roo.ContentPanel} The active panel or null
35671 getActivePanel : function(){
35672 return this.activePanel;
35675 validateVisibility : function(){
35676 if(this.panels.getCount() < 1){
35677 this.updateTitle(" ");
35678 this.closeBtn.hide();
35681 if(!this.isVisible()){
35688 * Adds the passed ContentPanel(s) to this region.
35689 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35690 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35692 add : function(panel)
35694 if(arguments.length > 1){
35695 for(var i = 0, len = arguments.length; i < len; i++) {
35696 this.add(arguments[i]);
35701 // if we have not been rendered yet, then we can not really do much of this..
35702 if (!this.bodyEl) {
35703 this.unrendered_panels.push(panel);
35710 if(this.hasPanel(panel)){
35711 this.showPanel(panel);
35714 panel.setRegion(this);
35715 this.panels.add(panel);
35716 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35717 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35718 // and hide them... ???
35719 this.bodyEl.dom.appendChild(panel.getEl().dom);
35720 if(panel.background !== true){
35721 this.setActivePanel(panel);
35723 this.fireEvent("paneladded", this, panel);
35730 this.initPanelAsTab(panel);
35734 if(panel.background !== true){
35735 this.tabs.activate(panel.getEl().id);
35737 this.fireEvent("paneladded", this, panel);
35742 * Hides the tab for the specified panel.
35743 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35745 hidePanel : function(panel){
35746 if(this.tabs && (panel = this.getPanel(panel))){
35747 this.tabs.hideTab(panel.getEl().id);
35752 * Unhides the tab for a previously hidden panel.
35753 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35755 unhidePanel : function(panel){
35756 if(this.tabs && (panel = this.getPanel(panel))){
35757 this.tabs.unhideTab(panel.getEl().id);
35761 clearPanels : function(){
35762 while(this.panels.getCount() > 0){
35763 this.remove(this.panels.first());
35768 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35769 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35770 * @param {Boolean} preservePanel Overrides the config preservePanel option
35771 * @return {Roo.ContentPanel} The panel that was removed
35773 remove : function(panel, preservePanel)
35775 panel = this.getPanel(panel);
35780 this.fireEvent("beforeremove", this, panel, e);
35781 if(e.cancel === true){
35784 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35785 var panelId = panel.getId();
35786 this.panels.removeKey(panelId);
35788 document.body.appendChild(panel.getEl().dom);
35791 this.tabs.removeTab(panel.getEl().id);
35792 }else if (!preservePanel){
35793 this.bodyEl.dom.removeChild(panel.getEl().dom);
35795 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35796 var p = this.panels.first();
35797 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35798 tempEl.appendChild(p.getEl().dom);
35799 this.bodyEl.update("");
35800 this.bodyEl.dom.appendChild(p.getEl().dom);
35802 this.updateTitle(p.getTitle());
35804 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35805 this.setActivePanel(p);
35807 panel.setRegion(null);
35808 if(this.activePanel == panel){
35809 this.activePanel = null;
35811 if(this.config.autoDestroy !== false && preservePanel !== true){
35812 try{panel.destroy();}catch(e){}
35814 this.fireEvent("panelremoved", this, panel);
35819 * Returns the TabPanel component used by this region
35820 * @return {Roo.TabPanel}
35822 getTabs : function(){
35826 createTool : function(parentEl, className){
35827 var btn = Roo.DomHelper.append(parentEl, {
35829 cls: "x-layout-tools-button",
35832 cls: "roo-layout-tools-button-inner " + className,
35836 btn.addClassOnOver("roo-layout-tools-button-over");
35841 * Ext JS Library 1.1.1
35842 * Copyright(c) 2006-2007, Ext JS, LLC.
35844 * Originally Released Under LGPL - original licence link has changed is not relivant.
35847 * <script type="text/javascript">
35853 * @class Roo.SplitLayoutRegion
35854 * @extends Roo.LayoutRegion
35855 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35857 Roo.bootstrap.layout.Split = function(config){
35858 this.cursor = config.cursor;
35859 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35862 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35864 splitTip : "Drag to resize.",
35865 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35866 useSplitTips : false,
35868 applyConfig : function(config){
35869 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35872 onRender : function(ctr,pos) {
35874 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35875 if(!this.config.split){
35880 var splitEl = Roo.DomHelper.append(ctr.dom, {
35882 id: this.el.id + "-split",
35883 cls: "roo-layout-split roo-layout-split-"+this.position,
35886 /** The SplitBar for this region
35887 * @type Roo.SplitBar */
35888 // does not exist yet...
35889 Roo.log([this.position, this.orientation]);
35891 this.split = new Roo.bootstrap.SplitBar({
35892 dragElement : splitEl,
35893 resizingElement: this.el,
35894 orientation : this.orientation
35897 this.split.on("moved", this.onSplitMove, this);
35898 this.split.useShim = this.config.useShim === true;
35899 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35900 if(this.useSplitTips){
35901 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35903 //if(config.collapsible){
35904 // this.split.el.on("dblclick", this.collapse, this);
35907 if(typeof this.config.minSize != "undefined"){
35908 this.split.minSize = this.config.minSize;
35910 if(typeof this.config.maxSize != "undefined"){
35911 this.split.maxSize = this.config.maxSize;
35913 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35914 this.hideSplitter();
35919 getHMaxSize : function(){
35920 var cmax = this.config.maxSize || 10000;
35921 var center = this.mgr.getRegion("center");
35922 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35925 getVMaxSize : function(){
35926 var cmax = this.config.maxSize || 10000;
35927 var center = this.mgr.getRegion("center");
35928 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35931 onSplitMove : function(split, newSize){
35932 this.fireEvent("resized", this, newSize);
35936 * Returns the {@link Roo.SplitBar} for this region.
35937 * @return {Roo.SplitBar}
35939 getSplitBar : function(){
35944 this.hideSplitter();
35945 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35948 hideSplitter : function(){
35950 this.split.el.setLocation(-2000,-2000);
35951 this.split.el.hide();
35957 this.split.el.show();
35959 Roo.bootstrap.layout.Split.superclass.show.call(this);
35962 beforeSlide: function(){
35963 if(Roo.isGecko){// firefox overflow auto bug workaround
35964 this.bodyEl.clip();
35966 this.tabs.bodyEl.clip();
35968 if(this.activePanel){
35969 this.activePanel.getEl().clip();
35971 if(this.activePanel.beforeSlide){
35972 this.activePanel.beforeSlide();
35978 afterSlide : function(){
35979 if(Roo.isGecko){// firefox overflow auto bug workaround
35980 this.bodyEl.unclip();
35982 this.tabs.bodyEl.unclip();
35984 if(this.activePanel){
35985 this.activePanel.getEl().unclip();
35986 if(this.activePanel.afterSlide){
35987 this.activePanel.afterSlide();
35993 initAutoHide : function(){
35994 if(this.autoHide !== false){
35995 if(!this.autoHideHd){
35996 var st = new Roo.util.DelayedTask(this.slideIn, this);
35997 this.autoHideHd = {
35998 "mouseout": function(e){
35999 if(!e.within(this.el, true)){
36003 "mouseover" : function(e){
36009 this.el.on(this.autoHideHd);
36013 clearAutoHide : function(){
36014 if(this.autoHide !== false){
36015 this.el.un("mouseout", this.autoHideHd.mouseout);
36016 this.el.un("mouseover", this.autoHideHd.mouseover);
36020 clearMonitor : function(){
36021 Roo.get(document).un("click", this.slideInIf, this);
36024 // these names are backwards but not changed for compat
36025 slideOut : function(){
36026 if(this.isSlid || this.el.hasActiveFx()){
36029 this.isSlid = true;
36030 if(this.collapseBtn){
36031 this.collapseBtn.hide();
36033 this.closeBtnState = this.closeBtn.getStyle('display');
36034 this.closeBtn.hide();
36036 this.stickBtn.show();
36039 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36040 this.beforeSlide();
36041 this.el.setStyle("z-index", 10001);
36042 this.el.slideIn(this.getSlideAnchor(), {
36043 callback: function(){
36045 this.initAutoHide();
36046 Roo.get(document).on("click", this.slideInIf, this);
36047 this.fireEvent("slideshow", this);
36054 afterSlideIn : function(){
36055 this.clearAutoHide();
36056 this.isSlid = false;
36057 this.clearMonitor();
36058 this.el.setStyle("z-index", "");
36059 if(this.collapseBtn){
36060 this.collapseBtn.show();
36062 this.closeBtn.setStyle('display', this.closeBtnState);
36064 this.stickBtn.hide();
36066 this.fireEvent("slidehide", this);
36069 slideIn : function(cb){
36070 if(!this.isSlid || this.el.hasActiveFx()){
36074 this.isSlid = false;
36075 this.beforeSlide();
36076 this.el.slideOut(this.getSlideAnchor(), {
36077 callback: function(){
36078 this.el.setLeftTop(-10000, -10000);
36080 this.afterSlideIn();
36088 slideInIf : function(e){
36089 if(!e.within(this.el)){
36094 animateCollapse : function(){
36095 this.beforeSlide();
36096 this.el.setStyle("z-index", 20000);
36097 var anchor = this.getSlideAnchor();
36098 this.el.slideOut(anchor, {
36099 callback : function(){
36100 this.el.setStyle("z-index", "");
36101 this.collapsedEl.slideIn(anchor, {duration:.3});
36103 this.el.setLocation(-10000,-10000);
36105 this.fireEvent("collapsed", this);
36112 animateExpand : function(){
36113 this.beforeSlide();
36114 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36115 this.el.setStyle("z-index", 20000);
36116 this.collapsedEl.hide({
36119 this.el.slideIn(this.getSlideAnchor(), {
36120 callback : function(){
36121 this.el.setStyle("z-index", "");
36124 this.split.el.show();
36126 this.fireEvent("invalidated", this);
36127 this.fireEvent("expanded", this);
36155 getAnchor : function(){
36156 return this.anchors[this.position];
36159 getCollapseAnchor : function(){
36160 return this.canchors[this.position];
36163 getSlideAnchor : function(){
36164 return this.sanchors[this.position];
36167 getAlignAdj : function(){
36168 var cm = this.cmargins;
36169 switch(this.position){
36185 getExpandAdj : function(){
36186 var c = this.collapsedEl, cm = this.cmargins;
36187 switch(this.position){
36189 return [-(cm.right+c.getWidth()+cm.left), 0];
36192 return [cm.right+c.getWidth()+cm.left, 0];
36195 return [0, -(cm.top+cm.bottom+c.getHeight())];
36198 return [0, cm.top+cm.bottom+c.getHeight()];
36204 * Ext JS Library 1.1.1
36205 * Copyright(c) 2006-2007, Ext JS, LLC.
36207 * Originally Released Under LGPL - original licence link has changed is not relivant.
36210 * <script type="text/javascript">
36213 * These classes are private internal classes
36215 Roo.bootstrap.layout.Center = function(config){
36216 config.region = "center";
36217 Roo.bootstrap.layout.Region.call(this, config);
36218 this.visible = true;
36219 this.minWidth = config.minWidth || 20;
36220 this.minHeight = config.minHeight || 20;
36223 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36225 // center panel can't be hidden
36229 // center panel can't be hidden
36232 getMinWidth: function(){
36233 return this.minWidth;
36236 getMinHeight: function(){
36237 return this.minHeight;
36250 Roo.bootstrap.layout.North = function(config)
36252 config.region = 'north';
36253 config.cursor = 'n-resize';
36255 Roo.bootstrap.layout.Split.call(this, config);
36259 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36260 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36261 this.split.el.addClass("roo-layout-split-v");
36263 var size = config.initialSize || config.height;
36264 if(typeof size != "undefined"){
36265 this.el.setHeight(size);
36268 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36270 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36274 getBox : function(){
36275 if(this.collapsed){
36276 return this.collapsedEl.getBox();
36278 var box = this.el.getBox();
36280 box.height += this.split.el.getHeight();
36285 updateBox : function(box){
36286 if(this.split && !this.collapsed){
36287 box.height -= this.split.el.getHeight();
36288 this.split.el.setLeft(box.x);
36289 this.split.el.setTop(box.y+box.height);
36290 this.split.el.setWidth(box.width);
36292 if(this.collapsed){
36293 this.updateBody(box.width, null);
36295 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36303 Roo.bootstrap.layout.South = function(config){
36304 config.region = 'south';
36305 config.cursor = 's-resize';
36306 Roo.bootstrap.layout.Split.call(this, config);
36308 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36309 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36310 this.split.el.addClass("roo-layout-split-v");
36312 var size = config.initialSize || config.height;
36313 if(typeof size != "undefined"){
36314 this.el.setHeight(size);
36318 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36319 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36320 getBox : function(){
36321 if(this.collapsed){
36322 return this.collapsedEl.getBox();
36324 var box = this.el.getBox();
36326 var sh = this.split.el.getHeight();
36333 updateBox : function(box){
36334 if(this.split && !this.collapsed){
36335 var sh = this.split.el.getHeight();
36338 this.split.el.setLeft(box.x);
36339 this.split.el.setTop(box.y-sh);
36340 this.split.el.setWidth(box.width);
36342 if(this.collapsed){
36343 this.updateBody(box.width, null);
36345 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36349 Roo.bootstrap.layout.East = function(config){
36350 config.region = "east";
36351 config.cursor = "e-resize";
36352 Roo.bootstrap.layout.Split.call(this, config);
36354 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36355 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36356 this.split.el.addClass("roo-layout-split-h");
36358 var size = config.initialSize || config.width;
36359 if(typeof size != "undefined"){
36360 this.el.setWidth(size);
36363 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36364 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36365 getBox : function(){
36366 if(this.collapsed){
36367 return this.collapsedEl.getBox();
36369 var box = this.el.getBox();
36371 var sw = this.split.el.getWidth();
36378 updateBox : function(box){
36379 if(this.split && !this.collapsed){
36380 var sw = this.split.el.getWidth();
36382 this.split.el.setLeft(box.x);
36383 this.split.el.setTop(box.y);
36384 this.split.el.setHeight(box.height);
36387 if(this.collapsed){
36388 this.updateBody(null, box.height);
36390 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36394 Roo.bootstrap.layout.West = function(config){
36395 config.region = "west";
36396 config.cursor = "w-resize";
36398 Roo.bootstrap.layout.Split.call(this, config);
36400 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36401 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36402 this.split.el.addClass("roo-layout-split-h");
36406 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36407 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36409 onRender: function(ctr, pos)
36411 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36412 var size = this.config.initialSize || this.config.width;
36413 if(typeof size != "undefined"){
36414 this.el.setWidth(size);
36418 getBox : function(){
36419 if(this.collapsed){
36420 return this.collapsedEl.getBox();
36422 var box = this.el.getBox();
36424 box.width += this.split.el.getWidth();
36429 updateBox : function(box){
36430 if(this.split && !this.collapsed){
36431 var sw = this.split.el.getWidth();
36433 this.split.el.setLeft(box.x+box.width);
36434 this.split.el.setTop(box.y);
36435 this.split.el.setHeight(box.height);
36437 if(this.collapsed){
36438 this.updateBody(null, box.height);
36440 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36443 Roo.namespace("Roo.bootstrap.panel");/*
36445 * Ext JS Library 1.1.1
36446 * Copyright(c) 2006-2007, Ext JS, LLC.
36448 * Originally Released Under LGPL - original licence link has changed is not relivant.
36451 * <script type="text/javascript">
36454 * @class Roo.ContentPanel
36455 * @extends Roo.util.Observable
36456 * A basic ContentPanel element.
36457 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36458 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36459 * @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
36460 * @cfg {Boolean} closable True if the panel can be closed/removed
36461 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36462 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36463 * @cfg {Toolbar} toolbar A toolbar for this panel
36464 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36465 * @cfg {String} title The title for this panel
36466 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36467 * @cfg {String} url Calls {@link #setUrl} with this value
36468 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36469 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36470 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36471 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36472 * @cfg {Boolean} badges render the badges
36475 * Create a new ContentPanel.
36476 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36477 * @param {String/Object} config A string to set only the title or a config object
36478 * @param {String} content (optional) Set the HTML content for this panel
36479 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36481 Roo.bootstrap.panel.Content = function( config){
36483 this.tpl = config.tpl || false;
36485 var el = config.el;
36486 var content = config.content;
36488 if(config.autoCreate){ // xtype is available if this is called from factory
36491 this.el = Roo.get(el);
36492 if(!this.el && config && config.autoCreate){
36493 if(typeof config.autoCreate == "object"){
36494 if(!config.autoCreate.id){
36495 config.autoCreate.id = config.id||el;
36497 this.el = Roo.DomHelper.append(document.body,
36498 config.autoCreate, true);
36500 var elcfg = { tag: "div",
36501 cls: "roo-layout-inactive-content",
36505 elcfg.html = config.html;
36509 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36512 this.closable = false;
36513 this.loaded = false;
36514 this.active = false;
36517 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36519 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36521 this.wrapEl = this.el; //this.el.wrap();
36523 if (config.toolbar.items) {
36524 ti = config.toolbar.items ;
36525 delete config.toolbar.items ;
36529 this.toolbar.render(this.wrapEl, 'before');
36530 for(var i =0;i < ti.length;i++) {
36531 // Roo.log(['add child', items[i]]);
36532 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36534 this.toolbar.items = nitems;
36535 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36536 delete config.toolbar;
36540 // xtype created footer. - not sure if will work as we normally have to render first..
36541 if (this.footer && !this.footer.el && this.footer.xtype) {
36542 if (!this.wrapEl) {
36543 this.wrapEl = this.el.wrap();
36546 this.footer.container = this.wrapEl.createChild();
36548 this.footer = Roo.factory(this.footer, Roo);
36553 if(typeof config == "string"){
36554 this.title = config;
36556 Roo.apply(this, config);
36560 this.resizeEl = Roo.get(this.resizeEl, true);
36562 this.resizeEl = this.el;
36564 // handle view.xtype
36572 * Fires when this panel is activated.
36573 * @param {Roo.ContentPanel} this
36577 * @event deactivate
36578 * Fires when this panel is activated.
36579 * @param {Roo.ContentPanel} this
36581 "deactivate" : true,
36585 * Fires when this panel is resized if fitToFrame is true.
36586 * @param {Roo.ContentPanel} this
36587 * @param {Number} width The width after any component adjustments
36588 * @param {Number} height The height after any component adjustments
36594 * Fires when this tab is created
36595 * @param {Roo.ContentPanel} this
36606 if(this.autoScroll){
36607 this.resizeEl.setStyle("overflow", "auto");
36609 // fix randome scrolling
36610 //this.el.on('scroll', function() {
36611 // Roo.log('fix random scolling');
36612 // this.scrollTo('top',0);
36615 content = content || this.content;
36617 this.setContent(content);
36619 if(config && config.url){
36620 this.setUrl(this.url, this.params, this.loadOnce);
36625 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36627 if (this.view && typeof(this.view.xtype) != 'undefined') {
36628 this.view.el = this.el.appendChild(document.createElement("div"));
36629 this.view = Roo.factory(this.view);
36630 this.view.render && this.view.render(false, '');
36634 this.fireEvent('render', this);
36637 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36641 setRegion : function(region){
36642 this.region = region;
36643 this.setActiveClass(region && !this.background);
36647 setActiveClass: function(state)
36650 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36651 this.el.setStyle('position','relative');
36653 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36654 this.el.setStyle('position', 'absolute');
36659 * Returns the toolbar for this Panel if one was configured.
36660 * @return {Roo.Toolbar}
36662 getToolbar : function(){
36663 return this.toolbar;
36666 setActiveState : function(active)
36668 this.active = active;
36669 this.setActiveClass(active);
36671 if(this.fireEvent("deactivate", this) === false){
36676 this.fireEvent("activate", this);
36680 * Updates this panel's element
36681 * @param {String} content The new content
36682 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36684 setContent : function(content, loadScripts){
36685 this.el.update(content, loadScripts);
36688 ignoreResize : function(w, h){
36689 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36692 this.lastSize = {width: w, height: h};
36697 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36698 * @return {Roo.UpdateManager} The UpdateManager
36700 getUpdateManager : function(){
36701 return this.el.getUpdateManager();
36704 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36705 * @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:
36708 url: "your-url.php",
36709 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36710 callback: yourFunction,
36711 scope: yourObject, //(optional scope)
36714 text: "Loading...",
36719 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36720 * 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.
36721 * @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}
36722 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36723 * @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.
36724 * @return {Roo.ContentPanel} this
36727 var um = this.el.getUpdateManager();
36728 um.update.apply(um, arguments);
36734 * 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.
36735 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36736 * @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)
36737 * @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)
36738 * @return {Roo.UpdateManager} The UpdateManager
36740 setUrl : function(url, params, loadOnce){
36741 if(this.refreshDelegate){
36742 this.removeListener("activate", this.refreshDelegate);
36744 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36745 this.on("activate", this.refreshDelegate);
36746 return this.el.getUpdateManager();
36749 _handleRefresh : function(url, params, loadOnce){
36750 if(!loadOnce || !this.loaded){
36751 var updater = this.el.getUpdateManager();
36752 updater.update(url, params, this._setLoaded.createDelegate(this));
36756 _setLoaded : function(){
36757 this.loaded = true;
36761 * Returns this panel's id
36764 getId : function(){
36769 * Returns this panel's element - used by regiosn to add.
36770 * @return {Roo.Element}
36772 getEl : function(){
36773 return this.wrapEl || this.el;
36778 adjustForComponents : function(width, height)
36780 //Roo.log('adjustForComponents ');
36781 if(this.resizeEl != this.el){
36782 width -= this.el.getFrameWidth('lr');
36783 height -= this.el.getFrameWidth('tb');
36786 var te = this.toolbar.getEl();
36787 te.setWidth(width);
36788 height -= te.getHeight();
36791 var te = this.footer.getEl();
36792 te.setWidth(width);
36793 height -= te.getHeight();
36797 if(this.adjustments){
36798 width += this.adjustments[0];
36799 height += this.adjustments[1];
36801 return {"width": width, "height": height};
36804 setSize : function(width, height){
36805 if(this.fitToFrame && !this.ignoreResize(width, height)){
36806 if(this.fitContainer && this.resizeEl != this.el){
36807 this.el.setSize(width, height);
36809 var size = this.adjustForComponents(width, height);
36810 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36811 this.fireEvent('resize', this, size.width, size.height);
36816 * Returns this panel's title
36819 getTitle : function(){
36821 if (typeof(this.title) != 'object') {
36826 for (var k in this.title) {
36827 if (!this.title.hasOwnProperty(k)) {
36831 if (k.indexOf('-') >= 0) {
36832 var s = k.split('-');
36833 for (var i = 0; i<s.length; i++) {
36834 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36837 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36844 * Set this panel's title
36845 * @param {String} title
36847 setTitle : function(title){
36848 this.title = title;
36850 this.region.updatePanelTitle(this, title);
36855 * Returns true is this panel was configured to be closable
36856 * @return {Boolean}
36858 isClosable : function(){
36859 return this.closable;
36862 beforeSlide : function(){
36864 this.resizeEl.clip();
36867 afterSlide : function(){
36869 this.resizeEl.unclip();
36873 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36874 * Will fail silently if the {@link #setUrl} method has not been called.
36875 * This does not activate the panel, just updates its content.
36877 refresh : function(){
36878 if(this.refreshDelegate){
36879 this.loaded = false;
36880 this.refreshDelegate();
36885 * Destroys this panel
36887 destroy : function(){
36888 this.el.removeAllListeners();
36889 var tempEl = document.createElement("span");
36890 tempEl.appendChild(this.el.dom);
36891 tempEl.innerHTML = "";
36897 * form - if the content panel contains a form - this is a reference to it.
36898 * @type {Roo.form.Form}
36902 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36903 * This contains a reference to it.
36909 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36919 * @param {Object} cfg Xtype definition of item to add.
36923 getChildContainer: function () {
36924 return this.getEl();
36929 var ret = new Roo.factory(cfg);
36934 if (cfg.xtype.match(/^Form$/)) {
36937 //if (this.footer) {
36938 // el = this.footer.container.insertSibling(false, 'before');
36940 el = this.el.createChild();
36943 this.form = new Roo.form.Form(cfg);
36946 if ( this.form.allItems.length) {
36947 this.form.render(el.dom);
36951 // should only have one of theses..
36952 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36953 // views.. should not be just added - used named prop 'view''
36955 cfg.el = this.el.appendChild(document.createElement("div"));
36958 var ret = new Roo.factory(cfg);
36960 ret.render && ret.render(false, ''); // render blank..
36970 * @class Roo.bootstrap.panel.Grid
36971 * @extends Roo.bootstrap.panel.Content
36973 * Create a new GridPanel.
36974 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36975 * @param {Object} config A the config object
36981 Roo.bootstrap.panel.Grid = function(config)
36985 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36986 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36988 config.el = this.wrapper;
36989 //this.el = this.wrapper;
36991 if (config.container) {
36992 // ctor'ed from a Border/panel.grid
36995 this.wrapper.setStyle("overflow", "hidden");
36996 this.wrapper.addClass('roo-grid-container');
37001 if(config.toolbar){
37002 var tool_el = this.wrapper.createChild();
37003 this.toolbar = Roo.factory(config.toolbar);
37005 if (config.toolbar.items) {
37006 ti = config.toolbar.items ;
37007 delete config.toolbar.items ;
37011 this.toolbar.render(tool_el);
37012 for(var i =0;i < ti.length;i++) {
37013 // Roo.log(['add child', items[i]]);
37014 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37016 this.toolbar.items = nitems;
37018 delete config.toolbar;
37021 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37022 config.grid.scrollBody = true;;
37023 config.grid.monitorWindowResize = false; // turn off autosizing
37024 config.grid.autoHeight = false;
37025 config.grid.autoWidth = false;
37027 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37029 if (config.background) {
37030 // render grid on panel activation (if panel background)
37031 this.on('activate', function(gp) {
37032 if (!gp.grid.rendered) {
37033 gp.grid.render(this.wrapper);
37034 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37039 this.grid.render(this.wrapper);
37040 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37043 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37044 // ??? needed ??? config.el = this.wrapper;
37049 // xtype created footer. - not sure if will work as we normally have to render first..
37050 if (this.footer && !this.footer.el && this.footer.xtype) {
37052 var ctr = this.grid.getView().getFooterPanel(true);
37053 this.footer.dataSource = this.grid.dataSource;
37054 this.footer = Roo.factory(this.footer, Roo);
37055 this.footer.render(ctr);
37065 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37066 getId : function(){
37067 return this.grid.id;
37071 * Returns the grid for this panel
37072 * @return {Roo.bootstrap.Table}
37074 getGrid : function(){
37078 setSize : function(width, height){
37079 if(!this.ignoreResize(width, height)){
37080 var grid = this.grid;
37081 var size = this.adjustForComponents(width, height);
37082 var gridel = grid.getGridEl();
37083 gridel.setSize(size.width, size.height);
37085 var thd = grid.getGridEl().select('thead',true).first();
37086 var tbd = grid.getGridEl().select('tbody', true).first();
37088 tbd.setSize(width, height - thd.getHeight());
37097 beforeSlide : function(){
37098 this.grid.getView().scroller.clip();
37101 afterSlide : function(){
37102 this.grid.getView().scroller.unclip();
37105 destroy : function(){
37106 this.grid.destroy();
37108 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37113 * @class Roo.bootstrap.panel.Nest
37114 * @extends Roo.bootstrap.panel.Content
37116 * Create a new Panel, that can contain a layout.Border.
37119 * @param {Roo.BorderLayout} layout The layout for this panel
37120 * @param {String/Object} config A string to set only the title or a config object
37122 Roo.bootstrap.panel.Nest = function(config)
37124 // construct with only one argument..
37125 /* FIXME - implement nicer consturctors
37126 if (layout.layout) {
37128 layout = config.layout;
37129 delete config.layout;
37131 if (layout.xtype && !layout.getEl) {
37132 // then layout needs constructing..
37133 layout = Roo.factory(layout, Roo);
37137 config.el = config.layout.getEl();
37139 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37141 config.layout.monitorWindowResize = false; // turn off autosizing
37142 this.layout = config.layout;
37143 this.layout.getEl().addClass("roo-layout-nested-layout");
37150 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37152 setSize : function(width, height){
37153 if(!this.ignoreResize(width, height)){
37154 var size = this.adjustForComponents(width, height);
37155 var el = this.layout.getEl();
37156 if (size.height < 1) {
37157 el.setWidth(size.width);
37159 el.setSize(size.width, size.height);
37161 var touch = el.dom.offsetWidth;
37162 this.layout.layout();
37163 // ie requires a double layout on the first pass
37164 if(Roo.isIE && !this.initialized){
37165 this.initialized = true;
37166 this.layout.layout();
37171 // activate all subpanels if not currently active..
37173 setActiveState : function(active){
37174 this.active = active;
37175 this.setActiveClass(active);
37178 this.fireEvent("deactivate", this);
37182 this.fireEvent("activate", this);
37183 // not sure if this should happen before or after..
37184 if (!this.layout) {
37185 return; // should not happen..
37188 for (var r in this.layout.regions) {
37189 reg = this.layout.getRegion(r);
37190 if (reg.getActivePanel()) {
37191 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37192 reg.setActivePanel(reg.getActivePanel());
37195 if (!reg.panels.length) {
37198 reg.showPanel(reg.getPanel(0));
37207 * Returns the nested BorderLayout for this panel
37208 * @return {Roo.BorderLayout}
37210 getLayout : function(){
37211 return this.layout;
37215 * Adds a xtype elements to the layout of the nested panel
37219 xtype : 'ContentPanel',
37226 xtype : 'NestedLayoutPanel',
37232 items : [ ... list of content panels or nested layout panels.. ]
37236 * @param {Object} cfg Xtype definition of item to add.
37238 addxtype : function(cfg) {
37239 return this.layout.addxtype(cfg);
37244 * Ext JS Library 1.1.1
37245 * Copyright(c) 2006-2007, Ext JS, LLC.
37247 * Originally Released Under LGPL - original licence link has changed is not relivant.
37250 * <script type="text/javascript">
37253 * @class Roo.TabPanel
37254 * @extends Roo.util.Observable
37255 * A lightweight tab container.
37259 // basic tabs 1, built from existing content
37260 var tabs = new Roo.TabPanel("tabs1");
37261 tabs.addTab("script", "View Script");
37262 tabs.addTab("markup", "View Markup");
37263 tabs.activate("script");
37265 // more advanced tabs, built from javascript
37266 var jtabs = new Roo.TabPanel("jtabs");
37267 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37269 // set up the UpdateManager
37270 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37271 var updater = tab2.getUpdateManager();
37272 updater.setDefaultUrl("ajax1.htm");
37273 tab2.on('activate', updater.refresh, updater, true);
37275 // Use setUrl for Ajax loading
37276 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37277 tab3.setUrl("ajax2.htm", null, true);
37280 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37283 jtabs.activate("jtabs-1");
37286 * Create a new TabPanel.
37287 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37288 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37290 Roo.bootstrap.panel.Tabs = function(config){
37292 * The container element for this TabPanel.
37293 * @type Roo.Element
37295 this.el = Roo.get(config.el);
37298 if(typeof config == "boolean"){
37299 this.tabPosition = config ? "bottom" : "top";
37301 Roo.apply(this, config);
37305 if(this.tabPosition == "bottom"){
37306 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37307 this.el.addClass("roo-tabs-bottom");
37309 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37310 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37311 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37313 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37315 if(this.tabPosition != "bottom"){
37316 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37317 * @type Roo.Element
37319 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37320 this.el.addClass("roo-tabs-top");
37324 this.bodyEl.setStyle("position", "relative");
37326 this.active = null;
37327 this.activateDelegate = this.activate.createDelegate(this);
37332 * Fires when the active tab changes
37333 * @param {Roo.TabPanel} this
37334 * @param {Roo.TabPanelItem} activePanel The new active tab
37338 * @event beforetabchange
37339 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37340 * @param {Roo.TabPanel} this
37341 * @param {Object} e Set cancel to true on this object to cancel the tab change
37342 * @param {Roo.TabPanelItem} tab The tab being changed to
37344 "beforetabchange" : true
37347 Roo.EventManager.onWindowResize(this.onResize, this);
37348 this.cpad = this.el.getPadding("lr");
37349 this.hiddenCount = 0;
37352 // toolbar on the tabbar support...
37353 if (this.toolbar) {
37354 alert("no toolbar support yet");
37355 this.toolbar = false;
37357 var tcfg = this.toolbar;
37358 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37359 this.toolbar = new Roo.Toolbar(tcfg);
37360 if (Roo.isSafari) {
37361 var tbl = tcfg.container.child('table', true);
37362 tbl.setAttribute('width', '100%');
37370 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37373 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37375 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37377 tabPosition : "top",
37379 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37381 currentTabWidth : 0,
37383 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37387 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37391 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37393 preferredTabWidth : 175,
37395 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37397 resizeTabs : false,
37399 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37401 monitorResize : true,
37403 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37408 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37409 * @param {String} id The id of the div to use <b>or create</b>
37410 * @param {String} text The text for the tab
37411 * @param {String} content (optional) Content to put in the TabPanelItem body
37412 * @param {Boolean} closable (optional) True to create a close icon on the tab
37413 * @return {Roo.TabPanelItem} The created TabPanelItem
37415 addTab : function(id, text, content, closable, tpl)
37417 var item = new Roo.bootstrap.panel.TabItem({
37421 closable : closable,
37424 this.addTabItem(item);
37426 item.setContent(content);
37432 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37433 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37434 * @return {Roo.TabPanelItem}
37436 getTab : function(id){
37437 return this.items[id];
37441 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37442 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37444 hideTab : function(id){
37445 var t = this.items[id];
37448 this.hiddenCount++;
37449 this.autoSizeTabs();
37454 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37455 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37457 unhideTab : function(id){
37458 var t = this.items[id];
37460 t.setHidden(false);
37461 this.hiddenCount--;
37462 this.autoSizeTabs();
37467 * Adds an existing {@link Roo.TabPanelItem}.
37468 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37470 addTabItem : function(item){
37471 this.items[item.id] = item;
37472 this.items.push(item);
37473 // if(this.resizeTabs){
37474 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37475 // this.autoSizeTabs();
37477 // item.autoSize();
37482 * Removes a {@link Roo.TabPanelItem}.
37483 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37485 removeTab : function(id){
37486 var items = this.items;
37487 var tab = items[id];
37488 if(!tab) { return; }
37489 var index = items.indexOf(tab);
37490 if(this.active == tab && items.length > 1){
37491 var newTab = this.getNextAvailable(index);
37496 this.stripEl.dom.removeChild(tab.pnode.dom);
37497 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37498 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37500 items.splice(index, 1);
37501 delete this.items[tab.id];
37502 tab.fireEvent("close", tab);
37503 tab.purgeListeners();
37504 this.autoSizeTabs();
37507 getNextAvailable : function(start){
37508 var items = this.items;
37510 // look for a next tab that will slide over to
37511 // replace the one being removed
37512 while(index < items.length){
37513 var item = items[++index];
37514 if(item && !item.isHidden()){
37518 // if one isn't found select the previous tab (on the left)
37521 var item = items[--index];
37522 if(item && !item.isHidden()){
37530 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37531 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37533 disableTab : function(id){
37534 var tab = this.items[id];
37535 if(tab && this.active != tab){
37541 * Enables a {@link Roo.TabPanelItem} that is disabled.
37542 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37544 enableTab : function(id){
37545 var tab = this.items[id];
37550 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37551 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37552 * @return {Roo.TabPanelItem} The TabPanelItem.
37554 activate : function(id){
37555 var tab = this.items[id];
37559 if(tab == this.active || tab.disabled){
37563 this.fireEvent("beforetabchange", this, e, tab);
37564 if(e.cancel !== true && !tab.disabled){
37566 this.active.hide();
37568 this.active = this.items[id];
37569 this.active.show();
37570 this.fireEvent("tabchange", this, this.active);
37576 * Gets the active {@link Roo.TabPanelItem}.
37577 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37579 getActiveTab : function(){
37580 return this.active;
37584 * Updates the tab body element to fit the height of the container element
37585 * for overflow scrolling
37586 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37588 syncHeight : function(targetHeight){
37589 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37590 var bm = this.bodyEl.getMargins();
37591 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37592 this.bodyEl.setHeight(newHeight);
37596 onResize : function(){
37597 if(this.monitorResize){
37598 this.autoSizeTabs();
37603 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37605 beginUpdate : function(){
37606 this.updating = true;
37610 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37612 endUpdate : function(){
37613 this.updating = false;
37614 this.autoSizeTabs();
37618 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37620 autoSizeTabs : function(){
37621 var count = this.items.length;
37622 var vcount = count - this.hiddenCount;
37623 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37626 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37627 var availWidth = Math.floor(w / vcount);
37628 var b = this.stripBody;
37629 if(b.getWidth() > w){
37630 var tabs = this.items;
37631 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37632 if(availWidth < this.minTabWidth){
37633 /*if(!this.sleft){ // incomplete scrolling code
37634 this.createScrollButtons();
37637 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37640 if(this.currentTabWidth < this.preferredTabWidth){
37641 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37647 * Returns the number of tabs in this TabPanel.
37650 getCount : function(){
37651 return this.items.length;
37655 * Resizes all the tabs to the passed width
37656 * @param {Number} The new width
37658 setTabWidth : function(width){
37659 this.currentTabWidth = width;
37660 for(var i = 0, len = this.items.length; i < len; i++) {
37661 if(!this.items[i].isHidden()) {
37662 this.items[i].setWidth(width);
37668 * Destroys this TabPanel
37669 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37671 destroy : function(removeEl){
37672 Roo.EventManager.removeResizeListener(this.onResize, this);
37673 for(var i = 0, len = this.items.length; i < len; i++){
37674 this.items[i].purgeListeners();
37676 if(removeEl === true){
37677 this.el.update("");
37682 createStrip : function(container)
37684 var strip = document.createElement("nav");
37685 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37686 container.appendChild(strip);
37690 createStripList : function(strip)
37692 // div wrapper for retard IE
37693 // returns the "tr" element.
37694 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37695 //'<div class="x-tabs-strip-wrap">'+
37696 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37697 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37698 return strip.firstChild; //.firstChild.firstChild.firstChild;
37700 createBody : function(container)
37702 var body = document.createElement("div");
37703 Roo.id(body, "tab-body");
37704 //Roo.fly(body).addClass("x-tabs-body");
37705 Roo.fly(body).addClass("tab-content");
37706 container.appendChild(body);
37709 createItemBody :function(bodyEl, id){
37710 var body = Roo.getDom(id);
37712 body = document.createElement("div");
37715 //Roo.fly(body).addClass("x-tabs-item-body");
37716 Roo.fly(body).addClass("tab-pane");
37717 bodyEl.insertBefore(body, bodyEl.firstChild);
37721 createStripElements : function(stripEl, text, closable, tpl)
37723 var td = document.createElement("li"); // was td..
37726 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37729 stripEl.appendChild(td);
37731 td.className = "x-tabs-closable";
37732 if(!this.closeTpl){
37733 this.closeTpl = new Roo.Template(
37734 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37735 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37736 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37739 var el = this.closeTpl.overwrite(td, {"text": text});
37740 var close = el.getElementsByTagName("div")[0];
37741 var inner = el.getElementsByTagName("em")[0];
37742 return {"el": el, "close": close, "inner": inner};
37745 // not sure what this is..
37746 // if(!this.tabTpl){
37747 //this.tabTpl = new Roo.Template(
37748 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37749 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37751 // this.tabTpl = new Roo.Template(
37752 // '<a href="#">' +
37753 // '<span unselectable="on"' +
37754 // (this.disableTooltips ? '' : ' title="{text}"') +
37755 // ' >{text}</span></a>'
37761 var template = tpl || this.tabTpl || false;
37765 template = new Roo.Template(
37767 '<span unselectable="on"' +
37768 (this.disableTooltips ? '' : ' title="{text}"') +
37769 ' >{text}</span></a>'
37773 switch (typeof(template)) {
37777 template = new Roo.Template(template);
37783 var el = template.overwrite(td, {"text": text});
37785 var inner = el.getElementsByTagName("span")[0];
37787 return {"el": el, "inner": inner};
37795 * @class Roo.TabPanelItem
37796 * @extends Roo.util.Observable
37797 * Represents an individual item (tab plus body) in a TabPanel.
37798 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37799 * @param {String} id The id of this TabPanelItem
37800 * @param {String} text The text for the tab of this TabPanelItem
37801 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37803 Roo.bootstrap.panel.TabItem = function(config){
37805 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37806 * @type Roo.TabPanel
37808 this.tabPanel = config.panel;
37810 * The id for this TabPanelItem
37813 this.id = config.id;
37815 this.disabled = false;
37817 this.text = config.text;
37819 this.loaded = false;
37820 this.closable = config.closable;
37823 * The body element for this TabPanelItem.
37824 * @type Roo.Element
37826 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37827 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37828 this.bodyEl.setStyle("display", "block");
37829 this.bodyEl.setStyle("zoom", "1");
37830 //this.hideAction();
37832 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37834 this.el = Roo.get(els.el);
37835 this.inner = Roo.get(els.inner, true);
37836 this.textEl = Roo.get(this.el.dom.firstChild, true);
37837 this.pnode = Roo.get(els.el.parentNode, true);
37838 // this.el.on("mousedown", this.onTabMouseDown, this);
37839 this.el.on("click", this.onTabClick, this);
37841 if(config.closable){
37842 var c = Roo.get(els.close, true);
37843 c.dom.title = this.closeText;
37844 c.addClassOnOver("close-over");
37845 c.on("click", this.closeClick, this);
37851 * Fires when this tab becomes the active tab.
37852 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37853 * @param {Roo.TabPanelItem} this
37857 * @event beforeclose
37858 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37859 * @param {Roo.TabPanelItem} this
37860 * @param {Object} e Set cancel to true on this object to cancel the close.
37862 "beforeclose": true,
37865 * Fires when this tab is closed.
37866 * @param {Roo.TabPanelItem} this
37870 * @event deactivate
37871 * Fires when this tab is no longer the active tab.
37872 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37873 * @param {Roo.TabPanelItem} this
37875 "deactivate" : true
37877 this.hidden = false;
37879 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37882 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37884 purgeListeners : function(){
37885 Roo.util.Observable.prototype.purgeListeners.call(this);
37886 this.el.removeAllListeners();
37889 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37892 this.pnode.addClass("active");
37895 this.tabPanel.stripWrap.repaint();
37897 this.fireEvent("activate", this.tabPanel, this);
37901 * Returns true if this tab is the active tab.
37902 * @return {Boolean}
37904 isActive : function(){
37905 return this.tabPanel.getActiveTab() == this;
37909 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37912 this.pnode.removeClass("active");
37914 this.fireEvent("deactivate", this.tabPanel, this);
37917 hideAction : function(){
37918 this.bodyEl.hide();
37919 this.bodyEl.setStyle("position", "absolute");
37920 this.bodyEl.setLeft("-20000px");
37921 this.bodyEl.setTop("-20000px");
37924 showAction : function(){
37925 this.bodyEl.setStyle("position", "relative");
37926 this.bodyEl.setTop("");
37927 this.bodyEl.setLeft("");
37928 this.bodyEl.show();
37932 * Set the tooltip for the tab.
37933 * @param {String} tooltip The tab's tooltip
37935 setTooltip : function(text){
37936 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37937 this.textEl.dom.qtip = text;
37938 this.textEl.dom.removeAttribute('title');
37940 this.textEl.dom.title = text;
37944 onTabClick : function(e){
37945 e.preventDefault();
37946 this.tabPanel.activate(this.id);
37949 onTabMouseDown : function(e){
37950 e.preventDefault();
37951 this.tabPanel.activate(this.id);
37954 getWidth : function(){
37955 return this.inner.getWidth();
37958 setWidth : function(width){
37959 var iwidth = width - this.pnode.getPadding("lr");
37960 this.inner.setWidth(iwidth);
37961 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37962 this.pnode.setWidth(width);
37966 * Show or hide the tab
37967 * @param {Boolean} hidden True to hide or false to show.
37969 setHidden : function(hidden){
37970 this.hidden = hidden;
37971 this.pnode.setStyle("display", hidden ? "none" : "");
37975 * Returns true if this tab is "hidden"
37976 * @return {Boolean}
37978 isHidden : function(){
37979 return this.hidden;
37983 * Returns the text for this tab
37986 getText : function(){
37990 autoSize : function(){
37991 //this.el.beginMeasure();
37992 this.textEl.setWidth(1);
37994 * #2804 [new] Tabs in Roojs
37995 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37997 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37998 //this.el.endMeasure();
38002 * Sets the text for the tab (Note: this also sets the tooltip text)
38003 * @param {String} text The tab's text and tooltip
38005 setText : function(text){
38007 this.textEl.update(text);
38008 this.setTooltip(text);
38009 //if(!this.tabPanel.resizeTabs){
38010 // this.autoSize();
38014 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38016 activate : function(){
38017 this.tabPanel.activate(this.id);
38021 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38023 disable : function(){
38024 if(this.tabPanel.active != this){
38025 this.disabled = true;
38026 this.pnode.addClass("disabled");
38031 * Enables this TabPanelItem if it was previously disabled.
38033 enable : function(){
38034 this.disabled = false;
38035 this.pnode.removeClass("disabled");
38039 * Sets the content for this TabPanelItem.
38040 * @param {String} content The content
38041 * @param {Boolean} loadScripts true to look for and load scripts
38043 setContent : function(content, loadScripts){
38044 this.bodyEl.update(content, loadScripts);
38048 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38049 * @return {Roo.UpdateManager} The UpdateManager
38051 getUpdateManager : function(){
38052 return this.bodyEl.getUpdateManager();
38056 * Set a URL to be used to load the content for this TabPanelItem.
38057 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38058 * @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)
38059 * @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)
38060 * @return {Roo.UpdateManager} The UpdateManager
38062 setUrl : function(url, params, loadOnce){
38063 if(this.refreshDelegate){
38064 this.un('activate', this.refreshDelegate);
38066 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38067 this.on("activate", this.refreshDelegate);
38068 return this.bodyEl.getUpdateManager();
38072 _handleRefresh : function(url, params, loadOnce){
38073 if(!loadOnce || !this.loaded){
38074 var updater = this.bodyEl.getUpdateManager();
38075 updater.update(url, params, this._setLoaded.createDelegate(this));
38080 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38081 * Will fail silently if the setUrl method has not been called.
38082 * This does not activate the panel, just updates its content.
38084 refresh : function(){
38085 if(this.refreshDelegate){
38086 this.loaded = false;
38087 this.refreshDelegate();
38092 _setLoaded : function(){
38093 this.loaded = true;
38097 closeClick : function(e){
38100 this.fireEvent("beforeclose", this, o);
38101 if(o.cancel !== true){
38102 this.tabPanel.removeTab(this.id);
38106 * The text displayed in the tooltip for the close icon.
38109 closeText : "Close this tab"
38112 * This script refer to:
38113 * Title: International Telephone Input
38114 * Author: Jack O'Connor
38115 * Code version: v12.1.12
38116 * Availability: https://github.com/jackocnr/intl-tel-input.git
38119 Roo.bootstrap.PhoneInputData = function() {
38122 "Afghanistan (افغانستان)",
38127 "Albania (Shqipëri)",
38132 "Algeria (الجزائر)",
38157 "Antigua and Barbuda",
38167 "Armenia (Հայաստան)",
38183 "Austria (Österreich)",
38188 "Azerbaijan (Azərbaycan)",
38198 "Bahrain (البحرين)",
38203 "Bangladesh (বাংলাদেশ)",
38213 "Belarus (Беларусь)",
38218 "Belgium (België)",
38248 "Bosnia and Herzegovina (Босна и Херцеговина)",
38263 "British Indian Ocean Territory",
38268 "British Virgin Islands",
38278 "Bulgaria (България)",
38288 "Burundi (Uburundi)",
38293 "Cambodia (កម្ពុជា)",
38298 "Cameroon (Cameroun)",
38307 ["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"]
38310 "Cape Verde (Kabu Verdi)",
38315 "Caribbean Netherlands",
38326 "Central African Republic (République centrafricaine)",
38346 "Christmas Island",
38352 "Cocos (Keeling) Islands",
38363 "Comoros (جزر القمر)",
38368 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38373 "Congo (Republic) (Congo-Brazzaville)",
38393 "Croatia (Hrvatska)",
38414 "Czech Republic (Česká republika)",
38419 "Denmark (Danmark)",
38434 "Dominican Republic (República Dominicana)",
38438 ["809", "829", "849"]
38456 "Equatorial Guinea (Guinea Ecuatorial)",
38476 "Falkland Islands (Islas Malvinas)",
38481 "Faroe Islands (Føroyar)",
38502 "French Guiana (Guyane française)",
38507 "French Polynesia (Polynésie française)",
38522 "Georgia (საქართველო)",
38527 "Germany (Deutschland)",
38547 "Greenland (Kalaallit Nunaat)",
38584 "Guinea-Bissau (Guiné Bissau)",
38609 "Hungary (Magyarország)",
38614 "Iceland (Ísland)",
38634 "Iraq (العراق)",
38650 "Israel (ישראל)",
38677 "Jordan (الأردن)",
38682 "Kazakhstan (Казахстан)",
38703 "Kuwait (الكويت)",
38708 "Kyrgyzstan (Кыргызстан)",
38718 "Latvia (Latvija)",
38723 "Lebanon (لبنان)",
38738 "Libya (ليبيا)",
38748 "Lithuania (Lietuva)",
38763 "Macedonia (FYROM) (Македонија)",
38768 "Madagascar (Madagasikara)",
38798 "Marshall Islands",
38808 "Mauritania (موريتانيا)",
38813 "Mauritius (Moris)",
38834 "Moldova (Republica Moldova)",
38844 "Mongolia (Монгол)",
38849 "Montenegro (Crna Gora)",
38859 "Morocco (المغرب)",
38865 "Mozambique (Moçambique)",
38870 "Myanmar (Burma) (မြန်မာ)",
38875 "Namibia (Namibië)",
38890 "Netherlands (Nederland)",
38895 "New Caledonia (Nouvelle-Calédonie)",
38930 "North Korea (조선 민주주의 인민 공화국)",
38935 "Northern Mariana Islands",
38951 "Pakistan (پاکستان)",
38961 "Palestine (فلسطين)",
38971 "Papua New Guinea",
39013 "Réunion (La Réunion)",
39019 "Romania (România)",
39035 "Saint Barthélemy",
39046 "Saint Kitts and Nevis",
39056 "Saint Martin (Saint-Martin (partie française))",
39062 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39067 "Saint Vincent and the Grenadines",
39082 "São Tomé and Príncipe (São Tomé e Príncipe)",
39087 "Saudi Arabia (المملكة العربية السعودية)",
39092 "Senegal (Sénégal)",
39122 "Slovakia (Slovensko)",
39127 "Slovenia (Slovenija)",
39137 "Somalia (Soomaaliya)",
39147 "South Korea (대한민국)",
39152 "South Sudan (جنوب السودان)",
39162 "Sri Lanka (ශ්රී ලංකාව)",
39167 "Sudan (السودان)",
39177 "Svalbard and Jan Mayen",
39188 "Sweden (Sverige)",
39193 "Switzerland (Schweiz)",
39198 "Syria (سوريا)",
39243 "Trinidad and Tobago",
39248 "Tunisia (تونس)",
39253 "Turkey (Türkiye)",
39263 "Turks and Caicos Islands",
39273 "U.S. Virgin Islands",
39283 "Ukraine (Україна)",
39288 "United Arab Emirates (الإمارات العربية المتحدة)",
39310 "Uzbekistan (Oʻzbekiston)",
39320 "Vatican City (Città del Vaticano)",
39331 "Vietnam (Việt Nam)",
39336 "Wallis and Futuna (Wallis-et-Futuna)",
39341 "Western Sahara (الصحراء الغربية)",
39347 "Yemen (اليمن)",
39371 * This script refer to:
39372 * Title: International Telephone Input
39373 * Author: Jack O'Connor
39374 * Code version: v12.1.12
39375 * Availability: https://github.com/jackocnr/intl-tel-input.git
39379 * @class Roo.bootstrap.PhoneInput
39380 * @extends Roo.bootstrap.TriggerField
39381 * An input with International dial-code selection
39383 * @cfg {String} defaultDialCode default '+852'
39384 * @cfg {Array} preferedCountries default []
39387 * Create a new PhoneInput.
39388 * @param {Object} config Configuration options
39391 Roo.bootstrap.PhoneInput = function(config) {
39392 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39395 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39397 listWidth: undefined,
39399 selectedClass: 'active',
39401 invalidClass : "has-warning",
39403 validClass: 'has-success',
39405 allowed: '0123456789',
39408 * @cfg {String} defaultDialCode The default dial code when initializing the input
39410 defaultDialCode: '+852',
39413 * @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
39415 preferedCountries: false,
39417 getAutoCreate : function()
39419 var data = Roo.bootstrap.PhoneInputData();
39420 var align = this.labelAlign || this.parentLabelAlign();
39423 this.allCountries = [];
39424 this.dialCodeMapping = [];
39426 for (var i = 0; i < data.length; i++) {
39428 this.allCountries[i] = {
39432 priority: c[3] || 0,
39433 areaCodes: c[4] || null
39435 this.dialCodeMapping[c[2]] = {
39438 priority: c[3] || 0,
39439 areaCodes: c[4] || null
39451 cls : 'form-control tel-input',
39452 autocomplete: 'new-password'
39455 var hiddenInput = {
39458 cls: 'hidden-tel-input'
39462 hiddenInput.name = this.name;
39465 if (this.disabled) {
39466 input.disabled = true;
39469 var flag_container = {
39486 cls: this.hasFeedback ? 'has-feedback' : '',
39492 cls: 'dial-code-holder',
39499 cls: 'roo-select2-container input-group',
39506 if (this.fieldLabel.length) {
39509 tooltip: 'This field is required'
39515 cls: 'control-label',
39521 html: this.fieldLabel
39524 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39530 if(this.indicatorpos == 'right') {
39531 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39538 if(align == 'left') {
39546 if(this.labelWidth > 12){
39547 label.style = "width: " + this.labelWidth + 'px';
39549 if(this.labelWidth < 13 && this.labelmd == 0){
39550 this.labelmd = this.labelWidth;
39552 if(this.labellg > 0){
39553 label.cls += ' col-lg-' + this.labellg;
39554 input.cls += ' col-lg-' + (12 - this.labellg);
39556 if(this.labelmd > 0){
39557 label.cls += ' col-md-' + this.labelmd;
39558 container.cls += ' col-md-' + (12 - this.labelmd);
39560 if(this.labelsm > 0){
39561 label.cls += ' col-sm-' + this.labelsm;
39562 container.cls += ' col-sm-' + (12 - this.labelsm);
39564 if(this.labelxs > 0){
39565 label.cls += ' col-xs-' + this.labelxs;
39566 container.cls += ' col-xs-' + (12 - this.labelxs);
39576 var settings = this;
39578 ['xs','sm','md','lg'].map(function(size){
39579 if (settings[size]) {
39580 cfg.cls += ' col-' + size + '-' + settings[size];
39584 this.store = new Roo.data.Store({
39585 proxy : new Roo.data.MemoryProxy({}),
39586 reader : new Roo.data.JsonReader({
39597 'name' : 'dialCode',
39601 'name' : 'priority',
39605 'name' : 'areaCodes',
39612 if(!this.preferedCountries) {
39613 this.preferedCountries = [
39620 var p = this.preferedCountries.reverse();
39623 for (var i = 0; i < p.length; i++) {
39624 for (var j = 0; j < this.allCountries.length; j++) {
39625 if(this.allCountries[j].iso2 == p[i]) {
39626 var t = this.allCountries[j];
39627 this.allCountries.splice(j,1);
39628 this.allCountries.unshift(t);
39634 this.store.proxy.data = {
39636 data: this.allCountries
39642 initEvents : function()
39645 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39647 this.indicator = this.indicatorEl();
39648 this.flag = this.flagEl();
39649 this.dialCodeHolder = this.dialCodeHolderEl();
39651 this.trigger = this.el.select('div.flag-box',true).first();
39652 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39657 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39658 _this.list.setWidth(lw);
39661 this.list.on('mouseover', this.onViewOver, this);
39662 this.list.on('mousemove', this.onViewMove, this);
39663 this.inputEl().on("keyup", this.onKeyUp, this);
39665 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39667 this.view = new Roo.View(this.list, this.tpl, {
39668 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39671 this.view.on('click', this.onViewClick, this);
39672 this.setValue(this.defaultDialCode);
39675 onTriggerClick : function(e)
39677 Roo.log('trigger click');
39682 if(this.isExpanded()){
39684 this.hasFocus = false;
39686 this.store.load({});
39687 this.hasFocus = true;
39692 isExpanded : function()
39694 return this.list.isVisible();
39697 collapse : function()
39699 if(!this.isExpanded()){
39703 Roo.get(document).un('mousedown', this.collapseIf, this);
39704 Roo.get(document).un('mousewheel', this.collapseIf, this);
39705 this.fireEvent('collapse', this);
39709 expand : function()
39713 if(this.isExpanded() || !this.hasFocus){
39717 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39718 this.list.setWidth(lw);
39721 this.restrictHeight();
39723 Roo.get(document).on('mousedown', this.collapseIf, this);
39724 Roo.get(document).on('mousewheel', this.collapseIf, this);
39726 this.fireEvent('expand', this);
39729 restrictHeight : function()
39731 this.list.alignTo(this.inputEl(), this.listAlign);
39732 this.list.alignTo(this.inputEl(), this.listAlign);
39735 onViewOver : function(e, t)
39737 if(this.inKeyMode){
39740 var item = this.view.findItemFromChild(t);
39743 var index = this.view.indexOf(item);
39744 this.select(index, false);
39749 onViewClick : function(view, doFocus, el, e)
39751 var index = this.view.getSelectedIndexes()[0];
39753 var r = this.store.getAt(index);
39756 this.onSelect(r, index);
39758 if(doFocus !== false && !this.blockFocus){
39759 this.inputEl().focus();
39763 onViewMove : function(e, t)
39765 this.inKeyMode = false;
39768 select : function(index, scrollIntoView)
39770 this.selectedIndex = index;
39771 this.view.select(index);
39772 if(scrollIntoView !== false){
39773 var el = this.view.getNode(index);
39775 this.list.scrollChildIntoView(el, false);
39780 createList : function()
39782 this.list = Roo.get(document.body).createChild({
39784 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39785 style: 'display:none'
39787 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39790 collapseIf : function(e)
39792 var in_combo = e.within(this.el);
39793 var in_list = e.within(this.list);
39794 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39796 if (in_combo || in_list || is_list) {
39802 onSelect : function(record, index)
39804 if(this.fireEvent('beforeselect', this, record, index) !== false){
39806 this.setFlagClass(record.data.iso2);
39807 this.setDialCode(record.data.dialCode);
39808 this.hasFocus = false;
39810 this.fireEvent('select', this, record, index);
39814 flagEl : function()
39816 var flag = this.el.select('div.flag',true).first();
39823 dialCodeHolderEl : function()
39825 var d = this.el.select('input.dial-code-holder',true).first();
39832 setDialCode : function(v)
39834 this.dialCodeHolder.dom.value = '+'+v;
39837 setFlagClass : function(n)
39839 this.flag.dom.className = 'flag '+n;
39842 getValue : function()
39844 var v = this.inputEl().getValue();
39845 if(this.dialCodeHolder) {
39846 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39851 setValue : function(v)
39853 var d = this.getDialCode(v);
39855 //invalid dial code
39856 if(v.length == 0 || !d || d.length == 0) {
39858 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39859 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39865 this.setFlagClass(this.dialCodeMapping[d].iso2);
39866 this.setDialCode(d);
39867 this.inputEl().dom.value = v.replace('+'+d,'');
39868 this.hiddenEl().dom.value = this.getValue();
39873 getDialCode : function(v = '')
39875 if (v.length == 0) {
39876 return this.dialCodeHolder.dom.value;
39880 if (v.charAt(0) != "+") {
39883 var numericChars = "";
39884 for (var i = 1; i < v.length; i++) {
39885 var c = v.charAt(i);
39888 if (this.dialCodeMapping[numericChars]) {
39889 dialCode = v.substr(1, i);
39891 if (numericChars.length == 4) {
39901 this.setValue(this.defaultDialCode);
39905 hiddenEl : function()
39907 return this.el.select('input.hidden-tel-input',true).first();
39910 onKeyUp : function(e){
39912 var k = e.getKey();
39913 var c = e.getCharCode();
39916 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39917 this.allowed.indexOf(String.fromCharCode(c)) === -1
39922 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39925 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39929 this.setValue(this.getValue());
39934 * @class Roo.bootstrap.MoneyField
39935 * @extends Roo.bootstrap.ComboBox
39936 * Bootstrap MoneyField class
39939 * Create a new MoneyField.
39940 * @param {Object} config Configuration options
39943 Roo.bootstrap.MoneyField = function(config) {
39945 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39949 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39952 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39954 allowDecimals : true,
39956 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39958 decimalSeparator : ".",
39960 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39962 decimalPrecision : 2,
39964 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39966 allowNegative : true,
39968 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39970 minValue : Number.NEGATIVE_INFINITY,
39972 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39974 maxValue : Number.MAX_VALUE,
39976 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39978 minText : "The minimum value for this field is {0}",
39980 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39982 maxText : "The maximum value for this field is {0}",
39984 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39985 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39987 nanText : "{0} is not a valid number",
39989 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39993 * @cfg {String} defaults currency of the MoneyField
39994 * value should be in lkey
39996 defaultCurrency : false,
40006 getAutoCreate : function()
40008 var align = this.labelAlign || this.parentLabelAlign();
40020 cls : 'form-control roo-money-amount-input',
40021 autocomplete: 'new-password'
40025 input.name = this.name;
40028 if (this.disabled) {
40029 input.disabled = true;
40032 var clg = 12 - this.inputlg;
40033 var cmd = 12 - this.inputmd;
40034 var csm = 12 - this.inputsm;
40035 var cxs = 12 - this.inputxs;
40039 cls : 'row roo-money-field',
40043 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40047 cls: 'roo-select2-container input-group',
40051 cls : 'form-control roo-money-currency-input',
40052 autocomplete: 'new-password',
40054 name : this.currencyName
40058 cls : 'input-group-addon',
40072 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40076 cls: this.hasFeedback ? 'has-feedback' : '',
40087 if (this.fieldLabel.length) {
40090 tooltip: 'This field is required'
40096 cls: 'control-label',
40102 html: this.fieldLabel
40105 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40111 if(this.indicatorpos == 'right') {
40112 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40119 if(align == 'left') {
40127 if(this.labelWidth > 12){
40128 label.style = "width: " + this.labelWidth + 'px';
40130 if(this.labelWidth < 13 && this.labelmd == 0){
40131 this.labelmd = this.labelWidth;
40133 if(this.labellg > 0){
40134 label.cls += ' col-lg-' + this.labellg;
40135 input.cls += ' col-lg-' + (12 - this.labellg);
40137 if(this.labelmd > 0){
40138 label.cls += ' col-md-' + this.labelmd;
40139 container.cls += ' col-md-' + (12 - this.labelmd);
40141 if(this.labelsm > 0){
40142 label.cls += ' col-sm-' + this.labelsm;
40143 container.cls += ' col-sm-' + (12 - this.labelsm);
40145 if(this.labelxs > 0){
40146 label.cls += ' col-xs-' + this.labelxs;
40147 container.cls += ' col-xs-' + (12 - this.labelxs);
40157 var settings = this;
40159 ['xs','sm','md','lg'].map(function(size){
40160 if (settings[size]) {
40161 cfg.cls += ' col-' + size + '-' + settings[size];
40169 initEvents : function()
40171 this.indicator = this.indicatorEl();
40173 this.initCurrencyEvent();
40175 this.initNumberEvent();
40179 initCurrencyEvent : function()
40182 throw "can not find store for combo";
40185 this.store = Roo.factory(this.store, Roo.data);
40186 this.store.parent = this;
40190 this.triggerEl = this.el.select('.input-group-addon', true).first();
40192 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40197 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40198 _this.list.setWidth(lw);
40201 this.list.on('mouseover', this.onViewOver, this);
40202 this.list.on('mousemove', this.onViewMove, this);
40203 this.list.on('scroll', this.onViewScroll, this);
40206 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40209 this.view = new Roo.View(this.list, this.tpl, {
40210 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40213 this.view.on('click', this.onViewClick, this);
40215 this.store.on('beforeload', this.onBeforeLoad, this);
40216 this.store.on('load', this.onLoad, this);
40217 this.store.on('loadexception', this.onLoadException, this);
40219 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40220 "up" : function(e){
40221 this.inKeyMode = true;
40225 "down" : function(e){
40226 if(!this.isExpanded()){
40227 this.onTriggerClick();
40229 this.inKeyMode = true;
40234 "enter" : function(e){
40237 if(this.fireEvent("specialkey", this, e)){
40238 this.onViewClick(false);
40244 "esc" : function(e){
40248 "tab" : function(e){
40251 if(this.fireEvent("specialkey", this, e)){
40252 this.onViewClick(false);
40260 doRelay : function(foo, bar, hname){
40261 if(hname == 'down' || this.scope.isExpanded()){
40262 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40270 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40274 initNumberEvent : function(e)
40276 this.inputEl().on("keydown" , this.fireKey, this);
40277 this.inputEl().on("focus", this.onFocus, this);
40278 this.inputEl().on("blur", this.onBlur, this);
40280 this.inputEl().relayEvent('keyup', this);
40282 if(this.indicator){
40283 this.indicator.addClass('invisible');
40286 this.originalValue = this.getValue();
40288 if(this.validationEvent == 'keyup'){
40289 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40290 this.inputEl().on('keyup', this.filterValidation, this);
40292 else if(this.validationEvent !== false){
40293 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40296 if(this.selectOnFocus){
40297 this.on("focus", this.preFocus, this);
40300 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40301 this.inputEl().on("keypress", this.filterKeys, this);
40303 this.inputEl().relayEvent('keypress', this);
40306 var allowed = "0123456789";
40308 if(this.allowDecimals){
40309 allowed += this.decimalSeparator;
40312 if(this.allowNegative){
40316 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40318 var keyPress = function(e){
40320 var k = e.getKey();
40322 var c = e.getCharCode();
40325 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40326 allowed.indexOf(String.fromCharCode(c)) === -1
40332 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40336 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40341 this.inputEl().on("keypress", keyPress, this);
40345 onTriggerClick : function(e)
40352 this.loadNext = false;
40354 if(this.isExpanded()){
40359 this.hasFocus = true;
40361 if(this.triggerAction == 'all') {
40362 this.doQuery(this.allQuery, true);
40366 this.doQuery(this.getRawValue());
40369 getCurrency : function()
40371 var v = this.currencyEl().getValue();
40376 restrictHeight : function()
40378 this.list.alignTo(this.currencyEl(), this.listAlign);
40379 this.list.alignTo(this.currencyEl(), this.listAlign);
40382 onViewClick : function(view, doFocus, el, e)
40384 var index = this.view.getSelectedIndexes()[0];
40386 var r = this.store.getAt(index);
40389 this.onSelect(r, index);
40393 onSelect : function(record, index){
40395 if(this.fireEvent('beforeselect', this, record, index) !== false){
40397 this.setFromCurrencyData(index > -1 ? record.data : false);
40401 this.fireEvent('select', this, record, index);
40405 setFromCurrencyData : function(o)
40409 this.lastCurrency = o;
40411 if (this.currencyField) {
40412 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40414 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40417 this.lastSelectionText = currency;
40419 //setting default currency
40420 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40421 this.setCurrency(this.defaultCurrency);
40425 this.setCurrency(currency);
40428 setFromData : function(o)
40432 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40434 this.setFromCurrencyData(c);
40439 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40441 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40444 this.setValue(value);
40448 setCurrency : function(v)
40450 this.currencyValue = v;
40453 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40458 setValue : function(v)
40460 v = this.fixPrecision(v);
40462 v = String(v).replace(".", this.decimalSeparator);
40467 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40472 getRawValue : function()
40474 var v = this.inputEl().getValue();
40479 getValue : function()
40481 return this.fixPrecision(this.parseValue(this.getRawValue()));
40484 parseValue : function(value)
40486 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40487 return isNaN(value) ? '' : value;
40490 fixPrecision : function(value)
40492 var nan = isNaN(value);
40494 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40495 return nan ? '' : value;
40498 return parseFloat(value).toFixed(this.decimalPrecision);
40501 decimalPrecisionFcn : function(v)
40503 return Math.floor(v);
40506 validateValue : function(value)
40508 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40512 var num = this.parseValue(value);
40515 this.markInvalid(String.format(this.nanText, value));
40519 if(num < this.minValue){
40520 this.markInvalid(String.format(this.minText, this.minValue));
40524 if(num > this.maxValue){
40525 this.markInvalid(String.format(this.maxText, this.maxValue));
40532 validate : function()
40534 if(this.disabled || this.allowBlank){
40539 var currency = this.getCurrency();
40541 if(this.validateValue(this.getRawValue()) && currency.length){
40546 this.markInvalid();
40550 getName: function()
40555 beforeBlur : function()
40561 var v = this.parseValue(this.getRawValue());
40568 onBlur : function()
40572 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40573 //this.el.removeClass(this.focusClass);
40576 this.hasFocus = false;
40578 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40582 var v = this.getValue();
40584 if(String(v) !== String(this.startValue)){
40585 this.fireEvent('change', this, v, this.startValue);
40588 this.fireEvent("blur", this);
40591 inputEl : function()
40593 return this.el.select('.roo-money-amount-input', true).first();
40596 currencyEl : function()
40598 return this.el.select('.roo-money-currency-input', true).first();