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);
6137 onContextMenu : function(e, t)
6139 this.processEvent("contextmenu", e);
6142 processEvent : function(name, e)
6144 if (name != 'touchstart' ) {
6145 this.fireEvent(name, e);
6148 var t = e.getTarget();
6150 var cell = Roo.get(t);
6156 if(cell.findParent('tfoot', false, true)){
6160 if(cell.findParent('thead', false, true)){
6162 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6163 cell = Roo.get(t).findParent('th', false, true);
6165 Roo.log("failed to find th in thead?");
6166 Roo.log(e.getTarget());
6171 var cellIndex = cell.dom.cellIndex;
6173 var ename = name == 'touchstart' ? 'click' : name;
6174 this.fireEvent("header" + ename, this, cellIndex, e);
6179 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6180 cell = Roo.get(t).findParent('td', false, true);
6182 Roo.log("failed to find th in tbody?");
6183 Roo.log(e.getTarget());
6188 var row = cell.findParent('tr', false, true);
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = row.dom.rowIndex - 1;
6194 this.fireEvent("row" + name, this, rowIndex, e);
6198 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6204 onMouseover : function(e, el)
6206 var cell = Roo.get(el);
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 var row = cell.findParent('tr', false, true);
6217 var cellIndex = cell.dom.cellIndex;
6218 var rowIndex = row.dom.rowIndex - 1; // start from 0
6220 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6224 onMouseout : function(e, el)
6226 var cell = Roo.get(el);
6232 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6233 cell = cell.findParent('td', false, true);
6236 var row = cell.findParent('tr', false, true);
6237 var cellIndex = cell.dom.cellIndex;
6238 var rowIndex = row.dom.rowIndex - 1; // start from 0
6240 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6244 onClick : function(e, el)
6246 var cell = Roo.get(el);
6248 if(!cell || (!this.cellSelection && !this.rowSelection)){
6252 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6253 cell = cell.findParent('td', false, true);
6256 if(!cell || typeof(cell) == 'undefined'){
6260 var row = cell.findParent('tr', false, true);
6262 if(!row || typeof(row) == 'undefined'){
6266 var cellIndex = cell.dom.cellIndex;
6267 var rowIndex = this.getRowIndex(row);
6269 // why??? - should these not be based on SelectionModel?
6270 if(this.cellSelection){
6271 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6274 if(this.rowSelection){
6275 this.fireEvent('rowclick', this, row, rowIndex, e);
6281 onDblClick : function(e,el)
6283 var cell = Roo.get(el);
6285 if(!cell || (!this.cellSelection && !this.rowSelection)){
6289 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6290 cell = cell.findParent('td', false, true);
6293 if(!cell || typeof(cell) == 'undefined'){
6297 var row = cell.findParent('tr', false, true);
6299 if(!row || typeof(row) == 'undefined'){
6303 var cellIndex = cell.dom.cellIndex;
6304 var rowIndex = this.getRowIndex(row);
6306 if(this.cellSelection){
6307 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6310 if(this.rowSelection){
6311 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6315 sort : function(e,el)
6317 var col = Roo.get(el);
6319 if(!col.hasClass('sortable')){
6323 var sort = col.attr('sort');
6326 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6330 this.store.sortInfo = {field : sort, direction : dir};
6333 Roo.log("calling footer first");
6334 this.footer.onClick('first');
6337 this.store.load({ params : { start : 0 } });
6341 renderHeader : function()
6349 this.totalWidth = 0;
6351 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6353 var config = cm.config[i];
6358 html: cm.getColumnHeader(i)
6363 if(typeof(config.sortable) != 'undefined' && config.sortable){
6365 c.html = '<i class="glyphicon"></i>' + c.html;
6368 if(typeof(config.lgHeader) != 'undefined'){
6369 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6372 if(typeof(config.mdHeader) != 'undefined'){
6373 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6376 if(typeof(config.smHeader) != 'undefined'){
6377 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6380 if(typeof(config.xsHeader) != 'undefined'){
6381 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6388 if(typeof(config.tooltip) != 'undefined'){
6389 c.tooltip = config.tooltip;
6392 if(typeof(config.colspan) != 'undefined'){
6393 c.colspan = config.colspan;
6396 if(typeof(config.hidden) != 'undefined' && config.hidden){
6397 c.style += ' display:none;';
6400 if(typeof(config.dataIndex) != 'undefined'){
6401 c.sort = config.dataIndex;
6406 if(typeof(config.align) != 'undefined' && config.align.length){
6407 c.style += ' text-align:' + config.align + ';';
6410 if(typeof(config.width) != 'undefined'){
6411 c.style += ' width:' + config.width + 'px;';
6412 this.totalWidth += config.width;
6414 this.totalWidth += 100; // assume minimum of 100 per column?
6417 if(typeof(config.cls) != 'undefined'){
6418 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6421 ['xs','sm','md','lg'].map(function(size){
6423 if(typeof(config[size]) == 'undefined'){
6427 if (!config[size]) { // 0 = hidden
6428 c.cls += ' hidden-' + size;
6432 c.cls += ' col-' + size + '-' + config[size];
6442 renderBody : function()
6452 colspan : this.cm.getColumnCount()
6462 renderFooter : function()
6472 colspan : this.cm.getColumnCount()
6486 // Roo.log('ds onload');
6491 var ds = this.store;
6493 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6494 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6495 if (_this.store.sortInfo) {
6497 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6498 e.select('i', true).addClass(['glyphicon-arrow-up']);
6501 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6502 e.select('i', true).addClass(['glyphicon-arrow-down']);
6507 var tbody = this.mainBody;
6509 if(ds.getCount() > 0){
6510 ds.data.each(function(d,rowIndex){
6511 var row = this.renderRow(cm, ds, rowIndex);
6513 tbody.createChild(row);
6517 if(row.cellObjects.length){
6518 Roo.each(row.cellObjects, function(r){
6519 _this.renderCellObject(r);
6526 Roo.each(this.el.select('tbody td', true).elements, function(e){
6527 e.on('mouseover', _this.onMouseover, _this);
6530 Roo.each(this.el.select('tbody td', true).elements, function(e){
6531 e.on('mouseout', _this.onMouseout, _this);
6533 this.fireEvent('rowsrendered', this);
6534 //if(this.loadMask){
6535 // this.maskEl.hide();
6542 onUpdate : function(ds,record)
6544 this.refreshRow(record);
6548 onRemove : function(ds, record, index, isUpdate){
6549 if(isUpdate !== true){
6550 this.fireEvent("beforerowremoved", this, index, record);
6552 var bt = this.mainBody.dom;
6554 var rows = this.el.select('tbody > tr', true).elements;
6556 if(typeof(rows[index]) != 'undefined'){
6557 bt.removeChild(rows[index].dom);
6560 // if(bt.rows[index]){
6561 // bt.removeChild(bt.rows[index]);
6564 if(isUpdate !== true){
6565 //this.stripeRows(index);
6566 //this.syncRowHeights(index, index);
6568 this.fireEvent("rowremoved", this, index, record);
6572 onAdd : function(ds, records, rowIndex)
6574 //Roo.log('on Add called');
6575 // - note this does not handle multiple adding very well..
6576 var bt = this.mainBody.dom;
6577 for (var i =0 ; i < records.length;i++) {
6578 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6579 //Roo.log(records[i]);
6580 //Roo.log(this.store.getAt(rowIndex+i));
6581 this.insertRow(this.store, rowIndex + i, false);
6588 refreshRow : function(record){
6589 var ds = this.store, index;
6590 if(typeof record == 'number'){
6592 record = ds.getAt(index);
6594 index = ds.indexOf(record);
6596 this.insertRow(ds, index, true);
6598 this.onRemove(ds, record, index+1, true);
6600 //this.syncRowHeights(index, index);
6602 this.fireEvent("rowupdated", this, index, record);
6605 insertRow : function(dm, rowIndex, isUpdate){
6608 this.fireEvent("beforerowsinserted", this, rowIndex);
6610 //var s = this.getScrollState();
6611 var row = this.renderRow(this.cm, this.store, rowIndex);
6612 // insert before rowIndex..
6613 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6617 if(row.cellObjects.length){
6618 Roo.each(row.cellObjects, function(r){
6619 _this.renderCellObject(r);
6624 this.fireEvent("rowsinserted", this, rowIndex);
6625 //this.syncRowHeights(firstRow, lastRow);
6626 //this.stripeRows(firstRow);
6633 getRowDom : function(rowIndex)
6635 var rows = this.el.select('tbody > tr', true).elements;
6637 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6640 // returns the object tree for a tr..
6643 renderRow : function(cm, ds, rowIndex)
6646 var d = ds.getAt(rowIndex);
6653 var cellObjects = [];
6655 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6656 var config = cm.config[i];
6658 var renderer = cm.getRenderer(i);
6662 if(typeof(renderer) !== 'undefined'){
6663 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6665 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6666 // and are rendered into the cells after the row is rendered - using the id for the element.
6668 if(typeof(value) === 'object'){
6678 rowIndex : rowIndex,
6683 this.fireEvent('rowclass', this, rowcfg);
6687 cls : rowcfg.rowClass,
6689 html: (typeof(value) === 'object') ? '' : value
6696 if(typeof(config.colspan) != 'undefined'){
6697 td.colspan = config.colspan;
6700 if(typeof(config.hidden) != 'undefined' && config.hidden){
6701 td.style += ' display:none;';
6704 if(typeof(config.align) != 'undefined' && config.align.length){
6705 td.style += ' text-align:' + config.align + ';';
6708 if(typeof(config.width) != 'undefined'){
6709 td.style += ' width:' + config.width + 'px;';
6712 if(typeof(config.cursor) != 'undefined'){
6713 td.style += ' cursor:' + config.cursor + ';';
6716 if(typeof(config.cls) != 'undefined'){
6717 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6720 ['xs','sm','md','lg'].map(function(size){
6722 if(typeof(config[size]) == 'undefined'){
6726 if (!config[size]) { // 0 = hidden
6727 td.cls += ' hidden-' + size;
6731 td.cls += ' col-' + size + '-' + config[size];
6739 row.cellObjects = cellObjects;
6747 onBeforeLoad : function()
6749 //Roo.log('ds onBeforeLoad');
6753 //if(this.loadMask){
6754 // this.maskEl.show();
6762 this.el.select('tbody', true).first().dom.innerHTML = '';
6765 * Show or hide a row.
6766 * @param {Number} rowIndex to show or hide
6767 * @param {Boolean} state hide
6769 setRowVisibility : function(rowIndex, state)
6771 var bt = this.mainBody.dom;
6773 var rows = this.el.select('tbody > tr', true).elements;
6775 if(typeof(rows[rowIndex]) == 'undefined'){
6778 rows[rowIndex].dom.style.display = state ? '' : 'none';
6782 getSelectionModel : function(){
6784 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6786 return this.selModel;
6789 * Render the Roo.bootstrap object from renderder
6791 renderCellObject : function(r)
6795 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6797 var t = r.cfg.render(r.container);
6800 Roo.each(r.cfg.cn, function(c){
6802 container: t.getChildContainer(),
6805 _this.renderCellObject(child);
6810 getRowIndex : function(row)
6814 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6825 * Returns the grid's underlying element = used by panel.Grid
6826 * @return {Element} The element
6828 getGridEl : function(){
6832 * Forces a resize - used by panel.Grid
6833 * @return {Element} The element
6835 autoSize : function()
6837 //var ctr = Roo.get(this.container.dom.parentElement);
6838 var ctr = Roo.get(this.el.dom);
6840 var thd = this.getGridEl().select('thead',true).first();
6841 var tbd = this.getGridEl().select('tbody', true).first();
6842 var tfd = this.getGridEl().select('tfoot', true).first();
6844 var cw = ctr.getWidth();
6848 tbd.setSize(ctr.getWidth(),
6849 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6851 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6854 cw = Math.max(cw, this.totalWidth);
6855 this.getGridEl().select('tr',true).setWidth(cw);
6856 // resize 'expandable coloumn?
6858 return; // we doe not have a view in this design..
6861 onBodyScroll: function()
6863 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6864 this.mainHead.setStyle({
6865 'position' : 'relative',
6866 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6871 var scrollHeight = this.mainBody.dom.scrollHeight;
6873 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6875 var height = this.mainBody.getHeight();
6877 if(scrollHeight - height == scrollTop) {
6879 var total = this.ds.getTotalCount();
6881 if(this.footer.cursor + this.footer.pageSize < total){
6883 this.footer.ds.load({
6885 start : this.footer.cursor + this.footer.pageSize,
6886 limit : this.footer.pageSize
6907 * @class Roo.bootstrap.TableCell
6908 * @extends Roo.bootstrap.Component
6909 * Bootstrap TableCell class
6910 * @cfg {String} html cell contain text
6911 * @cfg {String} cls cell class
6912 * @cfg {String} tag cell tag (td|th) default td
6913 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6914 * @cfg {String} align Aligns the content in a cell
6915 * @cfg {String} axis Categorizes cells
6916 * @cfg {String} bgcolor Specifies the background color of a cell
6917 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6918 * @cfg {Number} colspan Specifies the number of columns a cell should span
6919 * @cfg {String} headers Specifies one or more header cells a cell is related to
6920 * @cfg {Number} height Sets the height of a cell
6921 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6922 * @cfg {Number} rowspan Sets the number of rows a cell should span
6923 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6924 * @cfg {String} valign Vertical aligns the content in a cell
6925 * @cfg {Number} width Specifies the width of a cell
6928 * Create a new TableCell
6929 * @param {Object} config The config object
6932 Roo.bootstrap.TableCell = function(config){
6933 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6936 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6956 getAutoCreate : function(){
6957 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6977 cfg.align=this.align
6983 cfg.bgcolor=this.bgcolor
6986 cfg.charoff=this.charoff
6989 cfg.colspan=this.colspan
6992 cfg.headers=this.headers
6995 cfg.height=this.height
6998 cfg.nowrap=this.nowrap
7001 cfg.rowspan=this.rowspan
7004 cfg.scope=this.scope
7007 cfg.valign=this.valign
7010 cfg.width=this.width
7029 * @class Roo.bootstrap.TableRow
7030 * @extends Roo.bootstrap.Component
7031 * Bootstrap TableRow class
7032 * @cfg {String} cls row class
7033 * @cfg {String} align Aligns the content in a table row
7034 * @cfg {String} bgcolor Specifies a background color for a table row
7035 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7036 * @cfg {String} valign Vertical aligns the content in a table row
7039 * Create a new TableRow
7040 * @param {Object} config The config object
7043 Roo.bootstrap.TableRow = function(config){
7044 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7047 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7055 getAutoCreate : function(){
7056 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7066 cfg.align = this.align;
7069 cfg.bgcolor = this.bgcolor;
7072 cfg.charoff = this.charoff;
7075 cfg.valign = this.valign;
7093 * @class Roo.bootstrap.TableBody
7094 * @extends Roo.bootstrap.Component
7095 * Bootstrap TableBody class
7096 * @cfg {String} cls element class
7097 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7098 * @cfg {String} align Aligns the content inside the element
7099 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7100 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7103 * Create a new TableBody
7104 * @param {Object} config The config object
7107 Roo.bootstrap.TableBody = function(config){
7108 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7111 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7119 getAutoCreate : function(){
7120 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7134 cfg.align = this.align;
7137 cfg.charoff = this.charoff;
7140 cfg.valign = this.valign;
7147 // initEvents : function()
7154 // this.store = Roo.factory(this.store, Roo.data);
7155 // this.store.on('load', this.onLoad, this);
7157 // this.store.load();
7161 // onLoad: function ()
7163 // this.fireEvent('load', this);
7173 * Ext JS Library 1.1.1
7174 * Copyright(c) 2006-2007, Ext JS, LLC.
7176 * Originally Released Under LGPL - original licence link has changed is not relivant.
7179 * <script type="text/javascript">
7182 // as we use this in bootstrap.
7183 Roo.namespace('Roo.form');
7185 * @class Roo.form.Action
7186 * Internal Class used to handle form actions
7188 * @param {Roo.form.BasicForm} el The form element or its id
7189 * @param {Object} config Configuration options
7194 // define the action interface
7195 Roo.form.Action = function(form, options){
7197 this.options = options || {};
7200 * Client Validation Failed
7203 Roo.form.Action.CLIENT_INVALID = 'client';
7205 * Server Validation Failed
7208 Roo.form.Action.SERVER_INVALID = 'server';
7210 * Connect to Server Failed
7213 Roo.form.Action.CONNECT_FAILURE = 'connect';
7215 * Reading Data from Server Failed
7218 Roo.form.Action.LOAD_FAILURE = 'load';
7220 Roo.form.Action.prototype = {
7222 failureType : undefined,
7223 response : undefined,
7227 run : function(options){
7232 success : function(response){
7237 handleResponse : function(response){
7241 // default connection failure
7242 failure : function(response){
7244 this.response = response;
7245 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7246 this.form.afterAction(this, false);
7249 processResponse : function(response){
7250 this.response = response;
7251 if(!response.responseText){
7254 this.result = this.handleResponse(response);
7258 // utility functions used internally
7259 getUrl : function(appendParams){
7260 var url = this.options.url || this.form.url || this.form.el.dom.action;
7262 var p = this.getParams();
7264 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7270 getMethod : function(){
7271 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7274 getParams : function(){
7275 var bp = this.form.baseParams;
7276 var p = this.options.params;
7278 if(typeof p == "object"){
7279 p = Roo.urlEncode(Roo.applyIf(p, bp));
7280 }else if(typeof p == 'string' && bp){
7281 p += '&' + Roo.urlEncode(bp);
7284 p = Roo.urlEncode(bp);
7289 createCallback : function(){
7291 success: this.success,
7292 failure: this.failure,
7294 timeout: (this.form.timeout*1000),
7295 upload: this.form.fileUpload ? this.success : undefined
7300 Roo.form.Action.Submit = function(form, options){
7301 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7304 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7307 haveProgress : false,
7308 uploadComplete : false,
7310 // uploadProgress indicator.
7311 uploadProgress : function()
7313 if (!this.form.progressUrl) {
7317 if (!this.haveProgress) {
7318 Roo.MessageBox.progress("Uploading", "Uploading");
7320 if (this.uploadComplete) {
7321 Roo.MessageBox.hide();
7325 this.haveProgress = true;
7327 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7329 var c = new Roo.data.Connection();
7331 url : this.form.progressUrl,
7336 success : function(req){
7337 //console.log(data);
7341 rdata = Roo.decode(req.responseText)
7343 Roo.log("Invalid data from server..");
7347 if (!rdata || !rdata.success) {
7349 Roo.MessageBox.alert(Roo.encode(rdata));
7352 var data = rdata.data;
7354 if (this.uploadComplete) {
7355 Roo.MessageBox.hide();
7360 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7361 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7364 this.uploadProgress.defer(2000,this);
7367 failure: function(data) {
7368 Roo.log('progress url failed ');
7379 // run get Values on the form, so it syncs any secondary forms.
7380 this.form.getValues();
7382 var o = this.options;
7383 var method = this.getMethod();
7384 var isPost = method == 'POST';
7385 if(o.clientValidation === false || this.form.isValid()){
7387 if (this.form.progressUrl) {
7388 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7389 (new Date() * 1) + '' + Math.random());
7394 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7395 form:this.form.el.dom,
7396 url:this.getUrl(!isPost),
7398 params:isPost ? this.getParams() : null,
7399 isUpload: this.form.fileUpload
7402 this.uploadProgress();
7404 }else if (o.clientValidation !== false){ // client validation failed
7405 this.failureType = Roo.form.Action.CLIENT_INVALID;
7406 this.form.afterAction(this, false);
7410 success : function(response)
7412 this.uploadComplete= true;
7413 if (this.haveProgress) {
7414 Roo.MessageBox.hide();
7418 var result = this.processResponse(response);
7419 if(result === true || result.success){
7420 this.form.afterAction(this, true);
7424 this.form.markInvalid(result.errors);
7425 this.failureType = Roo.form.Action.SERVER_INVALID;
7427 this.form.afterAction(this, false);
7429 failure : function(response)
7431 this.uploadComplete= true;
7432 if (this.haveProgress) {
7433 Roo.MessageBox.hide();
7436 this.response = response;
7437 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7438 this.form.afterAction(this, false);
7441 handleResponse : function(response){
7442 if(this.form.errorReader){
7443 var rs = this.form.errorReader.read(response);
7446 for(var i = 0, len = rs.records.length; i < len; i++) {
7447 var r = rs.records[i];
7451 if(errors.length < 1){
7455 success : rs.success,
7461 ret = Roo.decode(response.responseText);
7465 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7475 Roo.form.Action.Load = function(form, options){
7476 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7477 this.reader = this.form.reader;
7480 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7485 Roo.Ajax.request(Roo.apply(
7486 this.createCallback(), {
7487 method:this.getMethod(),
7488 url:this.getUrl(false),
7489 params:this.getParams()
7493 success : function(response){
7495 var result = this.processResponse(response);
7496 if(result === true || !result.success || !result.data){
7497 this.failureType = Roo.form.Action.LOAD_FAILURE;
7498 this.form.afterAction(this, false);
7501 this.form.clearInvalid();
7502 this.form.setValues(result.data);
7503 this.form.afterAction(this, true);
7506 handleResponse : function(response){
7507 if(this.form.reader){
7508 var rs = this.form.reader.read(response);
7509 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7511 success : rs.success,
7515 return Roo.decode(response.responseText);
7519 Roo.form.Action.ACTION_TYPES = {
7520 'load' : Roo.form.Action.Load,
7521 'submit' : Roo.form.Action.Submit
7530 * @class Roo.bootstrap.Form
7531 * @extends Roo.bootstrap.Component
7532 * Bootstrap Form class
7533 * @cfg {String} method GET | POST (default POST)
7534 * @cfg {String} labelAlign top | left (default top)
7535 * @cfg {String} align left | right - for navbars
7536 * @cfg {Boolean} loadMask load mask when submit (default true)
7541 * @param {Object} config The config object
7545 Roo.bootstrap.Form = function(config){
7546 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7548 Roo.bootstrap.Form.popover.apply();
7552 * @event clientvalidation
7553 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7554 * @param {Form} this
7555 * @param {Boolean} valid true if the form has passed client-side validation
7557 clientvalidation: true,
7559 * @event beforeaction
7560 * Fires before any action is performed. Return false to cancel the action.
7561 * @param {Form} this
7562 * @param {Action} action The action to be performed
7566 * @event actionfailed
7567 * Fires when an action fails.
7568 * @param {Form} this
7569 * @param {Action} action The action that failed
7571 actionfailed : true,
7573 * @event actioncomplete
7574 * Fires when an action is completed.
7575 * @param {Form} this
7576 * @param {Action} action The action that completed
7578 actioncomplete : true
7583 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7586 * @cfg {String} method
7587 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7592 * The URL to use for form actions if one isn't supplied in the action options.
7595 * @cfg {Boolean} fileUpload
7596 * Set to true if this form is a file upload.
7600 * @cfg {Object} baseParams
7601 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7605 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7609 * @cfg {Sting} align (left|right) for navbar forms
7614 activeAction : null,
7617 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7618 * element by passing it or its id or mask the form itself by passing in true.
7621 waitMsgTarget : false,
7626 * @cfg {Boolean} errorMask (true|false) default false
7631 * @cfg {Number} maskOffset Default 100
7636 * @cfg {Boolean} maskBody
7640 getAutoCreate : function(){
7644 method : this.method || 'POST',
7645 id : this.id || Roo.id(),
7648 if (this.parent().xtype.match(/^Nav/)) {
7649 cfg.cls = 'navbar-form navbar-' + this.align;
7653 if (this.labelAlign == 'left' ) {
7654 cfg.cls += ' form-horizontal';
7660 initEvents : function()
7662 this.el.on('submit', this.onSubmit, this);
7663 // this was added as random key presses on the form where triggering form submit.
7664 this.el.on('keypress', function(e) {
7665 if (e.getCharCode() != 13) {
7668 // we might need to allow it for textareas.. and some other items.
7669 // check e.getTarget().
7671 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7675 Roo.log("keypress blocked");
7683 onSubmit : function(e){
7688 * Returns true if client-side validation on the form is successful.
7691 isValid : function(){
7692 var items = this.getItems();
7696 items.each(function(f){
7702 if(!target && f.el.isVisible(true)){
7708 if(this.errorMask && !valid){
7709 Roo.bootstrap.Form.popover.mask(this, target);
7716 * Returns true if any fields in this form have changed since their original load.
7719 isDirty : function(){
7721 var items = this.getItems();
7722 items.each(function(f){
7732 * Performs a predefined action (submit or load) or custom actions you define on this form.
7733 * @param {String} actionName The name of the action type
7734 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7735 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7736 * accept other config options):
7738 Property Type Description
7739 ---------------- --------------- ----------------------------------------------------------------------------------
7740 url String The url for the action (defaults to the form's url)
7741 method String The form method to use (defaults to the form's method, or POST if not defined)
7742 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7743 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7744 validate the form on the client (defaults to false)
7746 * @return {BasicForm} this
7748 doAction : function(action, options){
7749 if(typeof action == 'string'){
7750 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7752 if(this.fireEvent('beforeaction', this, action) !== false){
7753 this.beforeAction(action);
7754 action.run.defer(100, action);
7760 beforeAction : function(action){
7761 var o = action.options;
7766 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7768 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7771 // not really supported yet.. ??
7773 //if(this.waitMsgTarget === true){
7774 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7775 //}else if(this.waitMsgTarget){
7776 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7777 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7779 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7785 afterAction : function(action, success){
7786 this.activeAction = null;
7787 var o = action.options;
7792 Roo.get(document.body).unmask();
7798 //if(this.waitMsgTarget === true){
7799 // this.el.unmask();
7800 //}else if(this.waitMsgTarget){
7801 // this.waitMsgTarget.unmask();
7803 // Roo.MessageBox.updateProgress(1);
7804 // Roo.MessageBox.hide();
7811 Roo.callback(o.success, o.scope, [this, action]);
7812 this.fireEvent('actioncomplete', this, action);
7816 // failure condition..
7817 // we have a scenario where updates need confirming.
7818 // eg. if a locking scenario exists..
7819 // we look for { errors : { needs_confirm : true }} in the response.
7821 (typeof(action.result) != 'undefined') &&
7822 (typeof(action.result.errors) != 'undefined') &&
7823 (typeof(action.result.errors.needs_confirm) != 'undefined')
7826 Roo.log("not supported yet");
7829 Roo.MessageBox.confirm(
7830 "Change requires confirmation",
7831 action.result.errorMsg,
7836 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7846 Roo.callback(o.failure, o.scope, [this, action]);
7847 // show an error message if no failed handler is set..
7848 if (!this.hasListener('actionfailed')) {
7849 Roo.log("need to add dialog support");
7851 Roo.MessageBox.alert("Error",
7852 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7853 action.result.errorMsg :
7854 "Saving Failed, please check your entries or try again"
7859 this.fireEvent('actionfailed', this, action);
7864 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7865 * @param {String} id The value to search for
7868 findField : function(id){
7869 var items = this.getItems();
7870 var field = items.get(id);
7872 items.each(function(f){
7873 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7880 return field || null;
7883 * Mark fields in this form invalid in bulk.
7884 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7885 * @return {BasicForm} this
7887 markInvalid : function(errors){
7888 if(errors instanceof Array){
7889 for(var i = 0, len = errors.length; i < len; i++){
7890 var fieldError = errors[i];
7891 var f = this.findField(fieldError.id);
7893 f.markInvalid(fieldError.msg);
7899 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7900 field.markInvalid(errors[id]);
7904 //Roo.each(this.childForms || [], function (f) {
7905 // f.markInvalid(errors);
7912 * Set values for fields in this form in bulk.
7913 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7914 * @return {BasicForm} this
7916 setValues : function(values){
7917 if(values instanceof Array){ // array of objects
7918 for(var i = 0, len = values.length; i < len; i++){
7920 var f = this.findField(v.id);
7922 f.setValue(v.value);
7923 if(this.trackResetOnLoad){
7924 f.originalValue = f.getValue();
7928 }else{ // object hash
7931 if(typeof values[id] != 'function' && (field = this.findField(id))){
7933 if (field.setFromData &&
7935 field.displayField &&
7936 // combos' with local stores can
7937 // be queried via setValue()
7938 // to set their value..
7939 (field.store && !field.store.isLocal)
7943 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7944 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7945 field.setFromData(sd);
7947 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7949 field.setFromData(values);
7952 field.setValue(values[id]);
7956 if(this.trackResetOnLoad){
7957 field.originalValue = field.getValue();
7963 //Roo.each(this.childForms || [], function (f) {
7964 // f.setValues(values);
7971 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7972 * they are returned as an array.
7973 * @param {Boolean} asString
7976 getValues : function(asString){
7977 //if (this.childForms) {
7978 // copy values from the child forms
7979 // Roo.each(this.childForms, function (f) {
7980 // this.setValues(f.getValues());
7986 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7987 if(asString === true){
7990 return Roo.urlDecode(fs);
7994 * Returns the fields in this form as an object with key/value pairs.
7995 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7998 getFieldValues : function(with_hidden)
8000 var items = this.getItems();
8002 items.each(function(f){
8008 var v = f.getValue();
8010 if (f.inputType =='radio') {
8011 if (typeof(ret[f.getName()]) == 'undefined') {
8012 ret[f.getName()] = ''; // empty..
8015 if (!f.el.dom.checked) {
8023 if(f.xtype == 'MoneyField'){
8024 ret[f.currencyName] = f.getCurrency();
8027 // not sure if this supported any more..
8028 if ((typeof(v) == 'object') && f.getRawValue) {
8029 v = f.getRawValue() ; // dates..
8031 // combo boxes where name != hiddenName...
8032 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8033 ret[f.name] = f.getRawValue();
8035 ret[f.getName()] = v;
8042 * Clears all invalid messages in this form.
8043 * @return {BasicForm} this
8045 clearInvalid : function(){
8046 var items = this.getItems();
8048 items.each(function(f){
8059 * @return {BasicForm} this
8062 var items = this.getItems();
8063 items.each(function(f){
8067 Roo.each(this.childForms || [], function (f) {
8075 getItems : function()
8077 var r=new Roo.util.MixedCollection(false, function(o){
8078 return o.id || (o.id = Roo.id());
8080 var iter = function(el) {
8087 Roo.each(el.items,function(e) {
8101 Roo.apply(Roo.bootstrap.Form, {
8128 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8129 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8130 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8131 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8134 this.maskEl.top.enableDisplayMode("block");
8135 this.maskEl.left.enableDisplayMode("block");
8136 this.maskEl.bottom.enableDisplayMode("block");
8137 this.maskEl.right.enableDisplayMode("block");
8139 this.toolTip = new Roo.bootstrap.Tooltip({
8140 cls : 'roo-form-error-popover',
8142 'left' : ['r-l', [-2,0], 'right'],
8143 'right' : ['l-r', [2,0], 'left'],
8144 'bottom' : ['tl-bl', [0,2], 'top'],
8145 'top' : [ 'bl-tl', [0,-2], 'bottom']
8149 this.toolTip.render(Roo.get(document.body));
8151 this.toolTip.el.enableDisplayMode("block");
8153 Roo.get(document.body).on('click', function(){
8157 Roo.get(document.body).on('touchstart', function(){
8161 this.isApplied = true
8164 mask : function(form, target)
8168 this.target = target;
8170 if(!this.form.errorMask || !target.el){
8174 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8176 Roo.log(scrollable);
8178 var ot = this.target.el.calcOffsetsTo(scrollable);
8180 var scrollTo = ot[1] - this.form.maskOffset;
8182 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8184 scrollable.scrollTo('top', scrollTo);
8186 var box = this.target.el.getBox();
8188 var zIndex = Roo.bootstrap.Modal.zIndex++;
8191 this.maskEl.top.setStyle('position', 'absolute');
8192 this.maskEl.top.setStyle('z-index', zIndex);
8193 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8194 this.maskEl.top.setLeft(0);
8195 this.maskEl.top.setTop(0);
8196 this.maskEl.top.show();
8198 this.maskEl.left.setStyle('position', 'absolute');
8199 this.maskEl.left.setStyle('z-index', zIndex);
8200 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8201 this.maskEl.left.setLeft(0);
8202 this.maskEl.left.setTop(box.y - this.padding);
8203 this.maskEl.left.show();
8205 this.maskEl.bottom.setStyle('position', 'absolute');
8206 this.maskEl.bottom.setStyle('z-index', zIndex);
8207 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8208 this.maskEl.bottom.setLeft(0);
8209 this.maskEl.bottom.setTop(box.bottom + this.padding);
8210 this.maskEl.bottom.show();
8212 this.maskEl.right.setStyle('position', 'absolute');
8213 this.maskEl.right.setStyle('z-index', zIndex);
8214 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8215 this.maskEl.right.setLeft(box.right + this.padding);
8216 this.maskEl.right.setTop(box.y - this.padding);
8217 this.maskEl.right.show();
8219 this.toolTip.bindEl = this.target.el;
8221 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8223 var tip = this.target.blankText;
8225 if(this.target.getValue() !== '' ) {
8227 if (this.target.invalidText.length) {
8228 tip = this.target.invalidText;
8229 } else if (this.target.regexText.length){
8230 tip = this.target.regexText;
8234 this.toolTip.show(tip);
8236 this.intervalID = window.setInterval(function() {
8237 Roo.bootstrap.Form.popover.unmask();
8240 window.onwheel = function(){ return false;};
8242 (function(){ this.isMasked = true; }).defer(500, this);
8248 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8252 this.maskEl.top.setStyle('position', 'absolute');
8253 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8254 this.maskEl.top.hide();
8256 this.maskEl.left.setStyle('position', 'absolute');
8257 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8258 this.maskEl.left.hide();
8260 this.maskEl.bottom.setStyle('position', 'absolute');
8261 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8262 this.maskEl.bottom.hide();
8264 this.maskEl.right.setStyle('position', 'absolute');
8265 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8266 this.maskEl.right.hide();
8268 this.toolTip.hide();
8270 this.toolTip.el.hide();
8272 window.onwheel = function(){ return true;};
8274 if(this.intervalID){
8275 window.clearInterval(this.intervalID);
8276 this.intervalID = false;
8279 this.isMasked = false;
8289 * Ext JS Library 1.1.1
8290 * Copyright(c) 2006-2007, Ext JS, LLC.
8292 * Originally Released Under LGPL - original licence link has changed is not relivant.
8295 * <script type="text/javascript">
8298 * @class Roo.form.VTypes
8299 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8302 Roo.form.VTypes = function(){
8303 // closure these in so they are only created once.
8304 var alpha = /^[a-zA-Z_]+$/;
8305 var alphanum = /^[a-zA-Z0-9_]+$/;
8306 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8307 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8309 // All these messages and functions are configurable
8312 * The function used to validate email addresses
8313 * @param {String} value The email address
8315 'email' : function(v){
8316 return email.test(v);
8319 * The error text to display when the email validation function returns false
8322 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8324 * The keystroke filter mask to be applied on email input
8327 'emailMask' : /[a-z0-9_\.\-@]/i,
8330 * The function used to validate URLs
8331 * @param {String} value The URL
8333 'url' : function(v){
8337 * The error text to display when the url validation function returns false
8340 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8343 * The function used to validate alpha values
8344 * @param {String} value The value
8346 'alpha' : function(v){
8347 return alpha.test(v);
8350 * The error text to display when the alpha validation function returns false
8353 'alphaText' : 'This field should only contain letters and _',
8355 * The keystroke filter mask to be applied on alpha input
8358 'alphaMask' : /[a-z_]/i,
8361 * The function used to validate alphanumeric values
8362 * @param {String} value The value
8364 'alphanum' : function(v){
8365 return alphanum.test(v);
8368 * The error text to display when the alphanumeric validation function returns false
8371 'alphanumText' : 'This field should only contain letters, numbers and _',
8373 * The keystroke filter mask to be applied on alphanumeric input
8376 'alphanumMask' : /[a-z0-9_]/i
8386 * @class Roo.bootstrap.Input
8387 * @extends Roo.bootstrap.Component
8388 * Bootstrap Input class
8389 * @cfg {Boolean} disabled is it disabled
8390 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8391 * @cfg {String} name name of the input
8392 * @cfg {string} fieldLabel - the label associated
8393 * @cfg {string} placeholder - placeholder to put in text.
8394 * @cfg {string} before - input group add on before
8395 * @cfg {string} after - input group add on after
8396 * @cfg {string} size - (lg|sm) or leave empty..
8397 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8398 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8399 * @cfg {Number} md colspan out of 12 for computer-sized screens
8400 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8401 * @cfg {string} value default value of the input
8402 * @cfg {Number} labelWidth set the width of label
8403 * @cfg {Number} labellg set the width of label (1-12)
8404 * @cfg {Number} labelmd set the width of label (1-12)
8405 * @cfg {Number} labelsm set the width of label (1-12)
8406 * @cfg {Number} labelxs set the width of label (1-12)
8407 * @cfg {String} labelAlign (top|left)
8408 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8409 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8410 * @cfg {String} indicatorpos (left|right) default left
8412 * @cfg {String} align (left|center|right) Default left
8413 * @cfg {Boolean} forceFeedback (true|false) Default false
8419 * Create a new Input
8420 * @param {Object} config The config object
8423 Roo.bootstrap.Input = function(config){
8425 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8430 * Fires when this field receives input focus.
8431 * @param {Roo.form.Field} this
8436 * Fires when this field loses input focus.
8437 * @param {Roo.form.Field} this
8442 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8443 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8444 * @param {Roo.form.Field} this
8445 * @param {Roo.EventObject} e The event object
8450 * Fires just before the field blurs if the field value has changed.
8451 * @param {Roo.form.Field} this
8452 * @param {Mixed} newValue The new value
8453 * @param {Mixed} oldValue The original value
8458 * Fires after the field has been marked as invalid.
8459 * @param {Roo.form.Field} this
8460 * @param {String} msg The validation message
8465 * Fires after the field has been validated with no errors.
8466 * @param {Roo.form.Field} this
8471 * Fires after the key up
8472 * @param {Roo.form.Field} this
8473 * @param {Roo.EventObject} e The event Object
8479 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8481 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8482 automatic validation (defaults to "keyup").
8484 validationEvent : "keyup",
8486 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8488 validateOnBlur : true,
8490 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8492 validationDelay : 250,
8494 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8496 focusClass : "x-form-focus", // not needed???
8500 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8502 invalidClass : "has-warning",
8505 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8507 validClass : "has-success",
8510 * @cfg {Boolean} hasFeedback (true|false) default true
8515 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8517 invalidFeedbackClass : "glyphicon-warning-sign",
8520 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8522 validFeedbackClass : "glyphicon-ok",
8525 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8527 selectOnFocus : false,
8530 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8534 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8539 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8541 disableKeyFilter : false,
8544 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8548 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8552 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8554 blankText : "Please complete this mandatory field",
8557 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8561 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8563 maxLength : Number.MAX_VALUE,
8565 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8567 minLengthText : "The minimum length for this field is {0}",
8569 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8571 maxLengthText : "The maximum length for this field is {0}",
8575 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8576 * If available, this function will be called only after the basic validators all return true, and will be passed the
8577 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8581 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8582 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8583 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8587 * @cfg {String} regexText -- Depricated - use Invalid Text
8592 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8598 autocomplete: false,
8617 formatedValue : false,
8618 forceFeedback : false,
8620 indicatorpos : 'left',
8627 parentLabelAlign : function()
8630 while (parent.parent()) {
8631 parent = parent.parent();
8632 if (typeof(parent.labelAlign) !='undefined') {
8633 return parent.labelAlign;
8640 getAutoCreate : function()
8642 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8648 if(this.inputType != 'hidden'){
8649 cfg.cls = 'form-group' //input-group
8655 type : this.inputType,
8657 cls : 'form-control',
8658 placeholder : this.placeholder || '',
8659 autocomplete : this.autocomplete || 'new-password'
8663 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8666 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8667 input.maxLength = this.maxLength;
8670 if (this.disabled) {
8671 input.disabled=true;
8674 if (this.readOnly) {
8675 input.readonly=true;
8679 input.name = this.name;
8683 input.cls += ' input-' + this.size;
8687 ['xs','sm','md','lg'].map(function(size){
8688 if (settings[size]) {
8689 cfg.cls += ' col-' + size + '-' + settings[size];
8693 var inputblock = input;
8697 cls: 'glyphicon form-control-feedback'
8700 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8703 cls : 'has-feedback',
8711 if (this.before || this.after) {
8714 cls : 'input-group',
8718 if (this.before && typeof(this.before) == 'string') {
8720 inputblock.cn.push({
8722 cls : 'roo-input-before input-group-addon',
8726 if (this.before && typeof(this.before) == 'object') {
8727 this.before = Roo.factory(this.before);
8729 inputblock.cn.push({
8731 cls : 'roo-input-before input-group-' +
8732 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8736 inputblock.cn.push(input);
8738 if (this.after && typeof(this.after) == 'string') {
8739 inputblock.cn.push({
8741 cls : 'roo-input-after input-group-addon',
8745 if (this.after && typeof(this.after) == 'object') {
8746 this.after = Roo.factory(this.after);
8748 inputblock.cn.push({
8750 cls : 'roo-input-after input-group-' +
8751 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8755 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8756 inputblock.cls += ' has-feedback';
8757 inputblock.cn.push(feedback);
8761 if (align ==='left' && this.fieldLabel.length) {
8763 cfg.cls += ' roo-form-group-label-left';
8768 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8769 tooltip : 'This field is required'
8774 cls : 'control-label',
8775 html : this.fieldLabel
8786 var labelCfg = cfg.cn[1];
8787 var contentCfg = cfg.cn[2];
8789 if(this.indicatorpos == 'right'){
8794 cls : 'control-label',
8798 html : this.fieldLabel
8802 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8803 tooltip : 'This field is required'
8816 labelCfg = cfg.cn[0];
8817 contentCfg = cfg.cn[1];
8821 if(this.labelWidth > 12){
8822 labelCfg.style = "width: " + this.labelWidth + 'px';
8825 if(this.labelWidth < 13 && this.labelmd == 0){
8826 this.labelmd = this.labelWidth;
8829 if(this.labellg > 0){
8830 labelCfg.cls += ' col-lg-' + this.labellg;
8831 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8834 if(this.labelmd > 0){
8835 labelCfg.cls += ' col-md-' + this.labelmd;
8836 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8839 if(this.labelsm > 0){
8840 labelCfg.cls += ' col-sm-' + this.labelsm;
8841 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8844 if(this.labelxs > 0){
8845 labelCfg.cls += ' col-xs-' + this.labelxs;
8846 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8850 } else if ( this.fieldLabel.length) {
8855 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8856 tooltip : 'This field is required'
8860 //cls : 'input-group-addon',
8861 html : this.fieldLabel
8869 if(this.indicatorpos == 'right'){
8874 //cls : 'input-group-addon',
8875 html : this.fieldLabel
8880 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8881 tooltip : 'This field is required'
8901 if (this.parentType === 'Navbar' && this.parent().bar) {
8902 cfg.cls += ' navbar-form';
8905 if (this.parentType === 'NavGroup') {
8906 cfg.cls += ' navbar-form';
8914 * return the real input element.
8916 inputEl: function ()
8918 return this.el.select('input.form-control',true).first();
8921 tooltipEl : function()
8923 return this.inputEl();
8926 indicatorEl : function()
8928 var indicator = this.el.select('i.roo-required-indicator',true).first();
8938 setDisabled : function(v)
8940 var i = this.inputEl().dom;
8942 i.removeAttribute('disabled');
8946 i.setAttribute('disabled','true');
8948 initEvents : function()
8951 this.inputEl().on("keydown" , this.fireKey, this);
8952 this.inputEl().on("focus", this.onFocus, this);
8953 this.inputEl().on("blur", this.onBlur, this);
8955 this.inputEl().relayEvent('keyup', this);
8957 this.indicator = this.indicatorEl();
8960 this.indicator.addClass('invisible');
8964 // reference to original value for reset
8965 this.originalValue = this.getValue();
8966 //Roo.form.TextField.superclass.initEvents.call(this);
8967 if(this.validationEvent == 'keyup'){
8968 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8969 this.inputEl().on('keyup', this.filterValidation, this);
8971 else if(this.validationEvent !== false){
8972 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8975 if(this.selectOnFocus){
8976 this.on("focus", this.preFocus, this);
8979 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8980 this.inputEl().on("keypress", this.filterKeys, this);
8982 this.inputEl().relayEvent('keypress', this);
8985 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8986 this.el.on("click", this.autoSize, this);
8989 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8990 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8993 if (typeof(this.before) == 'object') {
8994 this.before.render(this.el.select('.roo-input-before',true).first());
8996 if (typeof(this.after) == 'object') {
8997 this.after.render(this.el.select('.roo-input-after',true).first());
9002 filterValidation : function(e){
9003 if(!e.isNavKeyPress()){
9004 this.validationTask.delay(this.validationDelay);
9008 * Validates the field value
9009 * @return {Boolean} True if the value is valid, else false
9011 validate : function(){
9012 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9013 if(this.disabled || this.validateValue(this.getRawValue())){
9024 * Validates a value according to the field's validation rules and marks the field as invalid
9025 * if the validation fails
9026 * @param {Mixed} value The value to validate
9027 * @return {Boolean} True if the value is valid, else false
9029 validateValue : function(value){
9030 if(value.length < 1) { // if it's blank
9031 if(this.allowBlank){
9034 return this.inputEl().hasClass('hide') ? true : false;
9037 if(value.length < this.minLength){
9040 if(value.length > this.maxLength){
9044 var vt = Roo.form.VTypes;
9045 if(!vt[this.vtype](value, this)){
9049 if(typeof this.validator == "function"){
9050 var msg = this.validator(value);
9054 if (typeof(msg) == 'string') {
9055 this.invalidText = msg;
9059 if(this.regex && !this.regex.test(value)){
9069 fireKey : function(e){
9070 //Roo.log('field ' + e.getKey());
9071 if(e.isNavKeyPress()){
9072 this.fireEvent("specialkey", this, e);
9075 focus : function (selectText){
9077 this.inputEl().focus();
9078 if(selectText === true){
9079 this.inputEl().dom.select();
9085 onFocus : function(){
9086 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9087 // this.el.addClass(this.focusClass);
9090 this.hasFocus = true;
9091 this.startValue = this.getValue();
9092 this.fireEvent("focus", this);
9096 beforeBlur : Roo.emptyFn,
9100 onBlur : function(){
9102 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9103 //this.el.removeClass(this.focusClass);
9105 this.hasFocus = false;
9106 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9109 var v = this.getValue();
9110 if(String(v) !== String(this.startValue)){
9111 this.fireEvent('change', this, v, this.startValue);
9113 this.fireEvent("blur", this);
9117 * Resets the current field value to the originally loaded value and clears any validation messages
9120 this.setValue(this.originalValue);
9124 * Returns the name of the field
9125 * @return {Mixed} name The name field
9127 getName: function(){
9131 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9132 * @return {Mixed} value The field value
9134 getValue : function(){
9136 var v = this.inputEl().getValue();
9141 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9142 * @return {Mixed} value The field value
9144 getRawValue : function(){
9145 var v = this.inputEl().getValue();
9151 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9152 * @param {Mixed} value The value to set
9154 setRawValue : function(v){
9155 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9158 selectText : function(start, end){
9159 var v = this.getRawValue();
9161 start = start === undefined ? 0 : start;
9162 end = end === undefined ? v.length : end;
9163 var d = this.inputEl().dom;
9164 if(d.setSelectionRange){
9165 d.setSelectionRange(start, end);
9166 }else if(d.createTextRange){
9167 var range = d.createTextRange();
9168 range.moveStart("character", start);
9169 range.moveEnd("character", v.length-end);
9176 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9177 * @param {Mixed} value The value to set
9179 setValue : function(v){
9182 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9188 processValue : function(value){
9189 if(this.stripCharsRe){
9190 var newValue = value.replace(this.stripCharsRe, '');
9191 if(newValue !== value){
9192 this.setRawValue(newValue);
9199 preFocus : function(){
9201 if(this.selectOnFocus){
9202 this.inputEl().dom.select();
9205 filterKeys : function(e){
9207 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9210 var c = e.getCharCode(), cc = String.fromCharCode(c);
9211 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9214 if(!this.maskRe.test(cc)){
9219 * Clear any invalid styles/messages for this field
9221 clearInvalid : function(){
9223 if(!this.el || this.preventMark){ // not rendered
9228 this.el.removeClass(this.invalidClass);
9230 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9232 var feedback = this.el.select('.form-control-feedback', true).first();
9235 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9240 this.fireEvent('valid', this);
9244 * Mark this field as valid
9246 markValid : function()
9248 if(!this.el || this.preventMark){ // not rendered...
9252 this.el.removeClass([this.invalidClass, this.validClass]);
9254 var feedback = this.el.select('.form-control-feedback', true).first();
9257 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9264 if(this.allowBlank && !this.getRawValue().length){
9269 this.indicator.removeClass('visible');
9270 this.indicator.addClass('invisible');
9273 this.el.addClass(this.validClass);
9275 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9277 var feedback = this.el.select('.form-control-feedback', true).first();
9280 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9281 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9286 this.fireEvent('valid', this);
9290 * Mark this field as invalid
9291 * @param {String} msg The validation message
9293 markInvalid : function(msg)
9295 if(!this.el || this.preventMark){ // not rendered
9299 this.el.removeClass([this.invalidClass, this.validClass]);
9301 var feedback = this.el.select('.form-control-feedback', true).first();
9304 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9311 if(this.allowBlank && !this.getRawValue().length){
9316 this.indicator.removeClass('invisible');
9317 this.indicator.addClass('visible');
9320 this.el.addClass(this.invalidClass);
9322 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9324 var feedback = this.el.select('.form-control-feedback', true).first();
9327 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9329 if(this.getValue().length || this.forceFeedback){
9330 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9337 this.fireEvent('invalid', this, msg);
9340 SafariOnKeyDown : function(event)
9342 // this is a workaround for a password hang bug on chrome/ webkit.
9343 if (this.inputEl().dom.type != 'password') {
9347 var isSelectAll = false;
9349 if(this.inputEl().dom.selectionEnd > 0){
9350 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9352 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9353 event.preventDefault();
9358 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9360 event.preventDefault();
9361 // this is very hacky as keydown always get's upper case.
9363 var cc = String.fromCharCode(event.getCharCode());
9364 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9368 adjustWidth : function(tag, w){
9369 tag = tag.toLowerCase();
9370 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9371 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9375 if(tag == 'textarea'){
9378 }else if(Roo.isOpera){
9382 if(tag == 'textarea'){
9390 setFieldLabel : function(v)
9397 var ar = this.el.select('label > span',true);
9399 if (ar.elements.length) {
9400 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9401 this.fieldLabel = v;
9405 var br = this.el.select('label',true);
9407 if(br.elements.length) {
9408 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9409 this.fieldLabel = v;
9413 Roo.log('Cannot Found any of label > span || label in input');
9417 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9418 this.fieldLabel = v;
9433 * @class Roo.bootstrap.TextArea
9434 * @extends Roo.bootstrap.Input
9435 * Bootstrap TextArea class
9436 * @cfg {Number} cols Specifies the visible width of a text area
9437 * @cfg {Number} rows Specifies the visible number of lines in a text area
9438 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9439 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9440 * @cfg {string} html text
9443 * Create a new TextArea
9444 * @param {Object} config The config object
9447 Roo.bootstrap.TextArea = function(config){
9448 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9452 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9462 getAutoCreate : function(){
9464 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9470 if(this.inputType != 'hidden'){
9471 cfg.cls = 'form-group' //input-group
9479 value : this.value || '',
9480 html: this.html || '',
9481 cls : 'form-control',
9482 placeholder : this.placeholder || ''
9486 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9487 input.maxLength = this.maxLength;
9491 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9495 input.cols = this.cols;
9498 if (this.readOnly) {
9499 input.readonly = true;
9503 input.name = this.name;
9507 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9511 ['xs','sm','md','lg'].map(function(size){
9512 if (settings[size]) {
9513 cfg.cls += ' col-' + size + '-' + settings[size];
9517 var inputblock = input;
9519 if(this.hasFeedback && !this.allowBlank){
9523 cls: 'glyphicon form-control-feedback'
9527 cls : 'has-feedback',
9536 if (this.before || this.after) {
9539 cls : 'input-group',
9543 inputblock.cn.push({
9545 cls : 'input-group-addon',
9550 inputblock.cn.push(input);
9552 if(this.hasFeedback && !this.allowBlank){
9553 inputblock.cls += ' has-feedback';
9554 inputblock.cn.push(feedback);
9558 inputblock.cn.push({
9560 cls : 'input-group-addon',
9567 if (align ==='left' && this.fieldLabel.length) {
9572 cls : 'control-label',
9573 html : this.fieldLabel
9584 if(this.labelWidth > 12){
9585 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9588 if(this.labelWidth < 13 && this.labelmd == 0){
9589 this.labelmd = this.labelWidth;
9592 if(this.labellg > 0){
9593 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9594 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9597 if(this.labelmd > 0){
9598 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9599 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9602 if(this.labelsm > 0){
9603 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9604 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9607 if(this.labelxs > 0){
9608 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9609 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9612 } else if ( this.fieldLabel.length) {
9617 //cls : 'input-group-addon',
9618 html : this.fieldLabel
9636 if (this.disabled) {
9637 input.disabled=true;
9644 * return the real textarea element.
9646 inputEl: function ()
9648 return this.el.select('textarea.form-control',true).first();
9652 * Clear any invalid styles/messages for this field
9654 clearInvalid : function()
9657 if(!this.el || this.preventMark){ // not rendered
9661 var label = this.el.select('label', true).first();
9662 var icon = this.el.select('i.fa-star', true).first();
9668 this.el.removeClass(this.invalidClass);
9670 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9672 var feedback = this.el.select('.form-control-feedback', true).first();
9675 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9680 this.fireEvent('valid', this);
9684 * Mark this field as valid
9686 markValid : function()
9688 if(!this.el || this.preventMark){ // not rendered
9692 this.el.removeClass([this.invalidClass, this.validClass]);
9694 var feedback = this.el.select('.form-control-feedback', true).first();
9697 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9700 if(this.disabled || this.allowBlank){
9704 var label = this.el.select('label', true).first();
9705 var icon = this.el.select('i.fa-star', true).first();
9711 this.el.addClass(this.validClass);
9713 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9715 var feedback = this.el.select('.form-control-feedback', true).first();
9718 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9719 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9724 this.fireEvent('valid', this);
9728 * Mark this field as invalid
9729 * @param {String} msg The validation message
9731 markInvalid : function(msg)
9733 if(!this.el || this.preventMark){ // not rendered
9737 this.el.removeClass([this.invalidClass, this.validClass]);
9739 var feedback = this.el.select('.form-control-feedback', true).first();
9742 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9745 if(this.disabled || this.allowBlank){
9749 var label = this.el.select('label', true).first();
9750 var icon = this.el.select('i.fa-star', true).first();
9752 if(!this.getValue().length && label && !icon){
9753 this.el.createChild({
9755 cls : 'text-danger fa fa-lg fa-star',
9756 tooltip : 'This field is required',
9757 style : 'margin-right:5px;'
9761 this.el.addClass(this.invalidClass);
9763 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9765 var feedback = this.el.select('.form-control-feedback', true).first();
9768 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9770 if(this.getValue().length || this.forceFeedback){
9771 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9778 this.fireEvent('invalid', this, msg);
9786 * trigger field - base class for combo..
9791 * @class Roo.bootstrap.TriggerField
9792 * @extends Roo.bootstrap.Input
9793 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9794 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9795 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9796 * for which you can provide a custom implementation. For example:
9798 var trigger = new Roo.bootstrap.TriggerField();
9799 trigger.onTriggerClick = myTriggerFn;
9800 trigger.applyTo('my-field');
9803 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9804 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9805 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9806 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9807 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9810 * Create a new TriggerField.
9811 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9812 * to the base TextField)
9814 Roo.bootstrap.TriggerField = function(config){
9815 this.mimicing = false;
9816 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9819 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9821 * @cfg {String} triggerClass A CSS class to apply to the trigger
9824 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9829 * @cfg {Boolean} removable (true|false) special filter default false
9833 /** @cfg {Boolean} grow @hide */
9834 /** @cfg {Number} growMin @hide */
9835 /** @cfg {Number} growMax @hide */
9841 autoSize: Roo.emptyFn,
9848 actionMode : 'wrap',
9853 getAutoCreate : function(){
9855 var align = this.labelAlign || this.parentLabelAlign();
9860 cls: 'form-group' //input-group
9867 type : this.inputType,
9868 cls : 'form-control',
9869 autocomplete: 'new-password',
9870 placeholder : this.placeholder || ''
9874 input.name = this.name;
9877 input.cls += ' input-' + this.size;
9880 if (this.disabled) {
9881 input.disabled=true;
9884 var inputblock = input;
9886 if(this.hasFeedback && !this.allowBlank){
9890 cls: 'glyphicon form-control-feedback'
9893 if(this.removable && !this.editable && !this.tickable){
9895 cls : 'has-feedback',
9901 cls : 'roo-combo-removable-btn close'
9908 cls : 'has-feedback',
9917 if(this.removable && !this.editable && !this.tickable){
9919 cls : 'roo-removable',
9925 cls : 'roo-combo-removable-btn close'
9932 if (this.before || this.after) {
9935 cls : 'input-group',
9939 inputblock.cn.push({
9941 cls : 'input-group-addon',
9946 inputblock.cn.push(input);
9948 if(this.hasFeedback && !this.allowBlank){
9949 inputblock.cls += ' has-feedback';
9950 inputblock.cn.push(feedback);
9954 inputblock.cn.push({
9956 cls : 'input-group-addon',
9969 cls: 'form-hidden-field'
9983 cls: 'form-hidden-field'
9987 cls: 'roo-select2-choices',
9991 cls: 'roo-select2-search-field',
10004 cls: 'roo-select2-container input-group',
10009 // cls: 'typeahead typeahead-long dropdown-menu',
10010 // style: 'display:none'
10015 if(!this.multiple && this.showToggleBtn){
10021 if (this.caret != false) {
10024 cls: 'fa fa-' + this.caret
10031 cls : 'input-group-addon btn dropdown-toggle',
10036 cls: 'combobox-clear',
10050 combobox.cls += ' roo-select2-container-multi';
10053 if (align ==='left' && this.fieldLabel.length) {
10055 cfg.cls += ' roo-form-group-label-left';
10060 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10061 tooltip : 'This field is required'
10066 cls : 'control-label',
10067 html : this.fieldLabel
10079 var labelCfg = cfg.cn[1];
10080 var contentCfg = cfg.cn[2];
10082 if(this.indicatorpos == 'right'){
10087 cls : 'control-label',
10091 html : this.fieldLabel
10095 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10096 tooltip : 'This field is required'
10109 labelCfg = cfg.cn[0];
10110 contentCfg = cfg.cn[1];
10113 if(this.labelWidth > 12){
10114 labelCfg.style = "width: " + this.labelWidth + 'px';
10117 if(this.labelWidth < 13 && this.labelmd == 0){
10118 this.labelmd = this.labelWidth;
10121 if(this.labellg > 0){
10122 labelCfg.cls += ' col-lg-' + this.labellg;
10123 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10126 if(this.labelmd > 0){
10127 labelCfg.cls += ' col-md-' + this.labelmd;
10128 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10131 if(this.labelsm > 0){
10132 labelCfg.cls += ' col-sm-' + this.labelsm;
10133 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10136 if(this.labelxs > 0){
10137 labelCfg.cls += ' col-xs-' + this.labelxs;
10138 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10141 } else if ( this.fieldLabel.length) {
10142 // Roo.log(" label");
10146 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10147 tooltip : 'This field is required'
10151 //cls : 'input-group-addon',
10152 html : this.fieldLabel
10160 if(this.indicatorpos == 'right'){
10168 html : this.fieldLabel
10172 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10173 tooltip : 'This field is required'
10186 // Roo.log(" no label && no align");
10193 ['xs','sm','md','lg'].map(function(size){
10194 if (settings[size]) {
10195 cfg.cls += ' col-' + size + '-' + settings[size];
10206 onResize : function(w, h){
10207 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10208 // if(typeof w == 'number'){
10209 // var x = w - this.trigger.getWidth();
10210 // this.inputEl().setWidth(this.adjustWidth('input', x));
10211 // this.trigger.setStyle('left', x+'px');
10216 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10219 getResizeEl : function(){
10220 return this.inputEl();
10224 getPositionEl : function(){
10225 return this.inputEl();
10229 alignErrorIcon : function(){
10230 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10234 initEvents : function(){
10238 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10239 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10240 if(!this.multiple && this.showToggleBtn){
10241 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10242 if(this.hideTrigger){
10243 this.trigger.setDisplayed(false);
10245 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10249 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10252 if(this.removable && !this.editable && !this.tickable){
10253 var close = this.closeTriggerEl();
10256 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10257 close.on('click', this.removeBtnClick, this, close);
10261 //this.trigger.addClassOnOver('x-form-trigger-over');
10262 //this.trigger.addClassOnClick('x-form-trigger-click');
10265 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10269 closeTriggerEl : function()
10271 var close = this.el.select('.roo-combo-removable-btn', true).first();
10272 return close ? close : false;
10275 removeBtnClick : function(e, h, el)
10277 e.preventDefault();
10279 if(this.fireEvent("remove", this) !== false){
10281 this.fireEvent("afterremove", this)
10285 createList : function()
10287 this.list = Roo.get(document.body).createChild({
10289 cls: 'typeahead typeahead-long dropdown-menu',
10290 style: 'display:none'
10293 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10298 initTrigger : function(){
10303 onDestroy : function(){
10305 this.trigger.removeAllListeners();
10306 // this.trigger.remove();
10309 // this.wrap.remove();
10311 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10315 onFocus : function(){
10316 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10318 if(!this.mimicing){
10319 this.wrap.addClass('x-trigger-wrap-focus');
10320 this.mimicing = true;
10321 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10322 if(this.monitorTab){
10323 this.el.on("keydown", this.checkTab, this);
10330 checkTab : function(e){
10331 if(e.getKey() == e.TAB){
10332 this.triggerBlur();
10337 onBlur : function(){
10342 mimicBlur : function(e, t){
10344 if(!this.wrap.contains(t) && this.validateBlur()){
10345 this.triggerBlur();
10351 triggerBlur : function(){
10352 this.mimicing = false;
10353 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10354 if(this.monitorTab){
10355 this.el.un("keydown", this.checkTab, this);
10357 //this.wrap.removeClass('x-trigger-wrap-focus');
10358 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10362 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10363 validateBlur : function(e, t){
10368 onDisable : function(){
10369 this.inputEl().dom.disabled = true;
10370 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10372 // this.wrap.addClass('x-item-disabled');
10377 onEnable : function(){
10378 this.inputEl().dom.disabled = false;
10379 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10381 // this.el.removeClass('x-item-disabled');
10386 onShow : function(){
10387 var ae = this.getActionEl();
10390 ae.dom.style.display = '';
10391 ae.dom.style.visibility = 'visible';
10397 onHide : function(){
10398 var ae = this.getActionEl();
10399 ae.dom.style.display = 'none';
10403 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10404 * by an implementing function.
10406 * @param {EventObject} e
10408 onTriggerClick : Roo.emptyFn
10412 * Ext JS Library 1.1.1
10413 * Copyright(c) 2006-2007, Ext JS, LLC.
10415 * Originally Released Under LGPL - original licence link has changed is not relivant.
10418 * <script type="text/javascript">
10423 * @class Roo.data.SortTypes
10425 * Defines the default sorting (casting?) comparison functions used when sorting data.
10427 Roo.data.SortTypes = {
10429 * Default sort that does nothing
10430 * @param {Mixed} s The value being converted
10431 * @return {Mixed} The comparison value
10433 none : function(s){
10438 * The regular expression used to strip tags
10442 stripTagsRE : /<\/?[^>]+>/gi,
10445 * Strips all HTML tags to sort on text only
10446 * @param {Mixed} s The value being converted
10447 * @return {String} The comparison value
10449 asText : function(s){
10450 return String(s).replace(this.stripTagsRE, "");
10454 * Strips all HTML tags to sort on text only - Case insensitive
10455 * @param {Mixed} s The value being converted
10456 * @return {String} The comparison value
10458 asUCText : function(s){
10459 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10463 * Case insensitive string
10464 * @param {Mixed} s The value being converted
10465 * @return {String} The comparison value
10467 asUCString : function(s) {
10468 return String(s).toUpperCase();
10473 * @param {Mixed} s The value being converted
10474 * @return {Number} The comparison value
10476 asDate : function(s) {
10480 if(s instanceof Date){
10481 return s.getTime();
10483 return Date.parse(String(s));
10488 * @param {Mixed} s The value being converted
10489 * @return {Float} The comparison value
10491 asFloat : function(s) {
10492 var val = parseFloat(String(s).replace(/,/g, ""));
10501 * @param {Mixed} s The value being converted
10502 * @return {Number} The comparison value
10504 asInt : function(s) {
10505 var val = parseInt(String(s).replace(/,/g, ""));
10513 * Ext JS Library 1.1.1
10514 * Copyright(c) 2006-2007, Ext JS, LLC.
10516 * Originally Released Under LGPL - original licence link has changed is not relivant.
10519 * <script type="text/javascript">
10523 * @class Roo.data.Record
10524 * Instances of this class encapsulate both record <em>definition</em> information, and record
10525 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10526 * to access Records cached in an {@link Roo.data.Store} object.<br>
10528 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10529 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10532 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10534 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10535 * {@link #create}. The parameters are the same.
10536 * @param {Array} data An associative Array of data values keyed by the field name.
10537 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10538 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10539 * not specified an integer id is generated.
10541 Roo.data.Record = function(data, id){
10542 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10547 * Generate a constructor for a specific record layout.
10548 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10549 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10550 * Each field definition object may contain the following properties: <ul>
10551 * <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,
10552 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10553 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10554 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10555 * is being used, then this is a string containing the javascript expression to reference the data relative to
10556 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10557 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10558 * this may be omitted.</p></li>
10559 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10560 * <ul><li>auto (Default, implies no conversion)</li>
10565 * <li>date</li></ul></p></li>
10566 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10567 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10568 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10569 * by the Reader into an object that will be stored in the Record. It is passed the
10570 * following parameters:<ul>
10571 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10573 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10575 * <br>usage:<br><pre><code>
10576 var TopicRecord = Roo.data.Record.create(
10577 {name: 'title', mapping: 'topic_title'},
10578 {name: 'author', mapping: 'username'},
10579 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10580 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10581 {name: 'lastPoster', mapping: 'user2'},
10582 {name: 'excerpt', mapping: 'post_text'}
10585 var myNewRecord = new TopicRecord({
10586 title: 'Do my job please',
10589 lastPost: new Date(),
10590 lastPoster: 'Animal',
10591 excerpt: 'No way dude!'
10593 myStore.add(myNewRecord);
10598 Roo.data.Record.create = function(o){
10599 var f = function(){
10600 f.superclass.constructor.apply(this, arguments);
10602 Roo.extend(f, Roo.data.Record);
10603 var p = f.prototype;
10604 p.fields = new Roo.util.MixedCollection(false, function(field){
10607 for(var i = 0, len = o.length; i < len; i++){
10608 p.fields.add(new Roo.data.Field(o[i]));
10610 f.getField = function(name){
10611 return p.fields.get(name);
10616 Roo.data.Record.AUTO_ID = 1000;
10617 Roo.data.Record.EDIT = 'edit';
10618 Roo.data.Record.REJECT = 'reject';
10619 Roo.data.Record.COMMIT = 'commit';
10621 Roo.data.Record.prototype = {
10623 * Readonly flag - true if this record has been modified.
10632 join : function(store){
10633 this.store = store;
10637 * Set the named field to the specified value.
10638 * @param {String} name The name of the field to set.
10639 * @param {Object} value The value to set the field to.
10641 set : function(name, value){
10642 if(this.data[name] == value){
10646 if(!this.modified){
10647 this.modified = {};
10649 if(typeof this.modified[name] == 'undefined'){
10650 this.modified[name] = this.data[name];
10652 this.data[name] = value;
10653 if(!this.editing && this.store){
10654 this.store.afterEdit(this);
10659 * Get the value of the named field.
10660 * @param {String} name The name of the field to get the value of.
10661 * @return {Object} The value of the field.
10663 get : function(name){
10664 return this.data[name];
10668 beginEdit : function(){
10669 this.editing = true;
10670 this.modified = {};
10674 cancelEdit : function(){
10675 this.editing = false;
10676 delete this.modified;
10680 endEdit : function(){
10681 this.editing = false;
10682 if(this.dirty && this.store){
10683 this.store.afterEdit(this);
10688 * Usually called by the {@link Roo.data.Store} which owns the Record.
10689 * Rejects all changes made to the Record since either creation, or the last commit operation.
10690 * Modified fields are reverted to their original values.
10692 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10693 * of reject operations.
10695 reject : function(){
10696 var m = this.modified;
10698 if(typeof m[n] != "function"){
10699 this.data[n] = m[n];
10702 this.dirty = false;
10703 delete this.modified;
10704 this.editing = false;
10706 this.store.afterReject(this);
10711 * Usually called by the {@link Roo.data.Store} which owns the Record.
10712 * Commits all changes made to the Record since either creation, or the last commit operation.
10714 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10715 * of commit operations.
10717 commit : function(){
10718 this.dirty = false;
10719 delete this.modified;
10720 this.editing = false;
10722 this.store.afterCommit(this);
10727 hasError : function(){
10728 return this.error != null;
10732 clearError : function(){
10737 * Creates a copy of this record.
10738 * @param {String} id (optional) A new record id if you don't want to use this record's id
10741 copy : function(newId) {
10742 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10746 * Ext JS Library 1.1.1
10747 * Copyright(c) 2006-2007, Ext JS, LLC.
10749 * Originally Released Under LGPL - original licence link has changed is not relivant.
10752 * <script type="text/javascript">
10758 * @class Roo.data.Store
10759 * @extends Roo.util.Observable
10760 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10761 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10763 * 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
10764 * has no knowledge of the format of the data returned by the Proxy.<br>
10766 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10767 * instances from the data object. These records are cached and made available through accessor functions.
10769 * Creates a new Store.
10770 * @param {Object} config A config object containing the objects needed for the Store to access data,
10771 * and read the data into Records.
10773 Roo.data.Store = function(config){
10774 this.data = new Roo.util.MixedCollection(false);
10775 this.data.getKey = function(o){
10778 this.baseParams = {};
10780 this.paramNames = {
10785 "multisort" : "_multisort"
10788 if(config && config.data){
10789 this.inlineData = config.data;
10790 delete config.data;
10793 Roo.apply(this, config);
10795 if(this.reader){ // reader passed
10796 this.reader = Roo.factory(this.reader, Roo.data);
10797 this.reader.xmodule = this.xmodule || false;
10798 if(!this.recordType){
10799 this.recordType = this.reader.recordType;
10801 if(this.reader.onMetaChange){
10802 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10806 if(this.recordType){
10807 this.fields = this.recordType.prototype.fields;
10809 this.modified = [];
10813 * @event datachanged
10814 * Fires when the data cache has changed, and a widget which is using this Store
10815 * as a Record cache should refresh its view.
10816 * @param {Store} this
10818 datachanged : true,
10820 * @event metachange
10821 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10822 * @param {Store} this
10823 * @param {Object} meta The JSON metadata
10828 * Fires when Records have been added to the Store
10829 * @param {Store} this
10830 * @param {Roo.data.Record[]} records The array of Records added
10831 * @param {Number} index The index at which the record(s) were added
10836 * Fires when a Record has been removed from the Store
10837 * @param {Store} this
10838 * @param {Roo.data.Record} record The Record that was removed
10839 * @param {Number} index The index at which the record was removed
10844 * Fires when a Record has been updated
10845 * @param {Store} this
10846 * @param {Roo.data.Record} record The Record that was updated
10847 * @param {String} operation The update operation being performed. Value may be one of:
10849 Roo.data.Record.EDIT
10850 Roo.data.Record.REJECT
10851 Roo.data.Record.COMMIT
10857 * Fires when the data cache has been cleared.
10858 * @param {Store} this
10862 * @event beforeload
10863 * Fires before a request is made for a new data object. If the beforeload handler returns false
10864 * the load action will be canceled.
10865 * @param {Store} this
10866 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10870 * @event beforeloadadd
10871 * Fires after a new set of Records has been loaded.
10872 * @param {Store} this
10873 * @param {Roo.data.Record[]} records The Records that were loaded
10874 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10876 beforeloadadd : true,
10879 * Fires after a new set of Records has been loaded, before they are added to the store.
10880 * @param {Store} this
10881 * @param {Roo.data.Record[]} records The Records that were loaded
10882 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10883 * @params {Object} return from reader
10887 * @event loadexception
10888 * Fires if an exception occurs in the Proxy during loading.
10889 * Called with the signature of the Proxy's "loadexception" event.
10890 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10893 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10894 * @param {Object} load options
10895 * @param {Object} jsonData from your request (normally this contains the Exception)
10897 loadexception : true
10901 this.proxy = Roo.factory(this.proxy, Roo.data);
10902 this.proxy.xmodule = this.xmodule || false;
10903 this.relayEvents(this.proxy, ["loadexception"]);
10905 this.sortToggle = {};
10906 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10908 Roo.data.Store.superclass.constructor.call(this);
10910 if(this.inlineData){
10911 this.loadData(this.inlineData);
10912 delete this.inlineData;
10916 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10918 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10919 * without a remote query - used by combo/forms at present.
10923 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10926 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10929 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10930 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10933 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10934 * on any HTTP request
10937 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10940 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10944 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10945 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10947 remoteSort : false,
10950 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10951 * loaded or when a record is removed. (defaults to false).
10953 pruneModifiedRecords : false,
10956 lastOptions : null,
10959 * Add Records to the Store and fires the add event.
10960 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10962 add : function(records){
10963 records = [].concat(records);
10964 for(var i = 0, len = records.length; i < len; i++){
10965 records[i].join(this);
10967 var index = this.data.length;
10968 this.data.addAll(records);
10969 this.fireEvent("add", this, records, index);
10973 * Remove a Record from the Store and fires the remove event.
10974 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10976 remove : function(record){
10977 var index = this.data.indexOf(record);
10978 this.data.removeAt(index);
10979 if(this.pruneModifiedRecords){
10980 this.modified.remove(record);
10982 this.fireEvent("remove", this, record, index);
10986 * Remove all Records from the Store and fires the clear event.
10988 removeAll : function(){
10990 if(this.pruneModifiedRecords){
10991 this.modified = [];
10993 this.fireEvent("clear", this);
10997 * Inserts Records to the Store at the given index and fires the add event.
10998 * @param {Number} index The start index at which to insert the passed Records.
10999 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11001 insert : function(index, records){
11002 records = [].concat(records);
11003 for(var i = 0, len = records.length; i < len; i++){
11004 this.data.insert(index, records[i]);
11005 records[i].join(this);
11007 this.fireEvent("add", this, records, index);
11011 * Get the index within the cache of the passed Record.
11012 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11013 * @return {Number} The index of the passed Record. Returns -1 if not found.
11015 indexOf : function(record){
11016 return this.data.indexOf(record);
11020 * Get the index within the cache of the Record with the passed id.
11021 * @param {String} id The id of the Record to find.
11022 * @return {Number} The index of the Record. Returns -1 if not found.
11024 indexOfId : function(id){
11025 return this.data.indexOfKey(id);
11029 * Get the Record with the specified id.
11030 * @param {String} id The id of the Record to find.
11031 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11033 getById : function(id){
11034 return this.data.key(id);
11038 * Get the Record at the specified index.
11039 * @param {Number} index The index of the Record to find.
11040 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11042 getAt : function(index){
11043 return this.data.itemAt(index);
11047 * Returns a range of Records between specified indices.
11048 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11049 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11050 * @return {Roo.data.Record[]} An array of Records
11052 getRange : function(start, end){
11053 return this.data.getRange(start, end);
11057 storeOptions : function(o){
11058 o = Roo.apply({}, o);
11061 this.lastOptions = o;
11065 * Loads the Record cache from the configured Proxy using the configured Reader.
11067 * If using remote paging, then the first load call must specify the <em>start</em>
11068 * and <em>limit</em> properties in the options.params property to establish the initial
11069 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11071 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11072 * and this call will return before the new data has been loaded. Perform any post-processing
11073 * in a callback function, or in a "load" event handler.</strong>
11075 * @param {Object} options An object containing properties which control loading options:<ul>
11076 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11077 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11078 * passed the following arguments:<ul>
11079 * <li>r : Roo.data.Record[]</li>
11080 * <li>options: Options object from the load call</li>
11081 * <li>success: Boolean success indicator</li></ul></li>
11082 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11083 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11086 load : function(options){
11087 options = options || {};
11088 if(this.fireEvent("beforeload", this, options) !== false){
11089 this.storeOptions(options);
11090 var p = Roo.apply(options.params || {}, this.baseParams);
11091 // if meta was not loaded from remote source.. try requesting it.
11092 if (!this.reader.metaFromRemote) {
11093 p._requestMeta = 1;
11095 if(this.sortInfo && this.remoteSort){
11096 var pn = this.paramNames;
11097 p[pn["sort"]] = this.sortInfo.field;
11098 p[pn["dir"]] = this.sortInfo.direction;
11100 if (this.multiSort) {
11101 var pn = this.paramNames;
11102 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11105 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11110 * Reloads the Record cache from the configured Proxy using the configured Reader and
11111 * the options from the last load operation performed.
11112 * @param {Object} options (optional) An object containing properties which may override the options
11113 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11114 * the most recently used options are reused).
11116 reload : function(options){
11117 this.load(Roo.applyIf(options||{}, this.lastOptions));
11121 // Called as a callback by the Reader during a load operation.
11122 loadRecords : function(o, options, success){
11123 if(!o || success === false){
11124 if(success !== false){
11125 this.fireEvent("load", this, [], options, o);
11127 if(options.callback){
11128 options.callback.call(options.scope || this, [], options, false);
11132 // if data returned failure - throw an exception.
11133 if (o.success === false) {
11134 // show a message if no listener is registered.
11135 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11136 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11138 // loadmask wil be hooked into this..
11139 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11142 var r = o.records, t = o.totalRecords || r.length;
11144 this.fireEvent("beforeloadadd", this, r, options, o);
11146 if(!options || options.add !== true){
11147 if(this.pruneModifiedRecords){
11148 this.modified = [];
11150 for(var i = 0, len = r.length; i < len; i++){
11154 this.data = this.snapshot;
11155 delete this.snapshot;
11158 this.data.addAll(r);
11159 this.totalLength = t;
11161 this.fireEvent("datachanged", this);
11163 this.totalLength = Math.max(t, this.data.length+r.length);
11167 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11169 var e = new Roo.data.Record({});
11171 e.set(this.parent.displayField, this.parent.emptyTitle);
11172 e.set(this.parent.valueField, '');
11177 this.fireEvent("load", this, r, options, o);
11178 if(options.callback){
11179 options.callback.call(options.scope || this, r, options, true);
11185 * Loads data from a passed data block. A Reader which understands the format of the data
11186 * must have been configured in the constructor.
11187 * @param {Object} data The data block from which to read the Records. The format of the data expected
11188 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11189 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11191 loadData : function(o, append){
11192 var r = this.reader.readRecords(o);
11193 this.loadRecords(r, {add: append}, true);
11197 * Gets the number of cached records.
11199 * <em>If using paging, this may not be the total size of the dataset. If the data object
11200 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11201 * the data set size</em>
11203 getCount : function(){
11204 return this.data.length || 0;
11208 * Gets the total number of records in the dataset as returned by the server.
11210 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11211 * the dataset size</em>
11213 getTotalCount : function(){
11214 return this.totalLength || 0;
11218 * Returns the sort state of the Store as an object with two properties:
11220 field {String} The name of the field by which the Records are sorted
11221 direction {String} The sort order, "ASC" or "DESC"
11224 getSortState : function(){
11225 return this.sortInfo;
11229 applySort : function(){
11230 if(this.sortInfo && !this.remoteSort){
11231 var s = this.sortInfo, f = s.field;
11232 var st = this.fields.get(f).sortType;
11233 var fn = function(r1, r2){
11234 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11235 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11237 this.data.sort(s.direction, fn);
11238 if(this.snapshot && this.snapshot != this.data){
11239 this.snapshot.sort(s.direction, fn);
11245 * Sets the default sort column and order to be used by the next load operation.
11246 * @param {String} fieldName The name of the field to sort by.
11247 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11249 setDefaultSort : function(field, dir){
11250 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11254 * Sort the Records.
11255 * If remote sorting is used, the sort is performed on the server, and the cache is
11256 * reloaded. If local sorting is used, the cache is sorted internally.
11257 * @param {String} fieldName The name of the field to sort by.
11258 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11260 sort : function(fieldName, dir){
11261 var f = this.fields.get(fieldName);
11263 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11265 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11266 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11271 this.sortToggle[f.name] = dir;
11272 this.sortInfo = {field: f.name, direction: dir};
11273 if(!this.remoteSort){
11275 this.fireEvent("datachanged", this);
11277 this.load(this.lastOptions);
11282 * Calls the specified function for each of the Records in the cache.
11283 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11284 * Returning <em>false</em> aborts and exits the iteration.
11285 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11287 each : function(fn, scope){
11288 this.data.each(fn, scope);
11292 * Gets all records modified since the last commit. Modified records are persisted across load operations
11293 * (e.g., during paging).
11294 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11296 getModifiedRecords : function(){
11297 return this.modified;
11301 createFilterFn : function(property, value, anyMatch){
11302 if(!value.exec){ // not a regex
11303 value = String(value);
11304 if(value.length == 0){
11307 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11309 return function(r){
11310 return value.test(r.data[property]);
11315 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11316 * @param {String} property A field on your records
11317 * @param {Number} start The record index to start at (defaults to 0)
11318 * @param {Number} end The last record index to include (defaults to length - 1)
11319 * @return {Number} The sum
11321 sum : function(property, start, end){
11322 var rs = this.data.items, v = 0;
11323 start = start || 0;
11324 end = (end || end === 0) ? end : rs.length-1;
11326 for(var i = start; i <= end; i++){
11327 v += (rs[i].data[property] || 0);
11333 * Filter the records by a specified property.
11334 * @param {String} field A field on your records
11335 * @param {String/RegExp} value Either a string that the field
11336 * should start with or a RegExp to test against the field
11337 * @param {Boolean} anyMatch True to match any part not just the beginning
11339 filter : function(property, value, anyMatch){
11340 var fn = this.createFilterFn(property, value, anyMatch);
11341 return fn ? this.filterBy(fn) : this.clearFilter();
11345 * Filter by a function. The specified function will be called with each
11346 * record in this data source. If the function returns true the record is included,
11347 * otherwise it is filtered.
11348 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11349 * @param {Object} scope (optional) The scope of the function (defaults to this)
11351 filterBy : function(fn, scope){
11352 this.snapshot = this.snapshot || this.data;
11353 this.data = this.queryBy(fn, scope||this);
11354 this.fireEvent("datachanged", this);
11358 * Query the records by a specified property.
11359 * @param {String} field A field on your records
11360 * @param {String/RegExp} value Either a string that the field
11361 * should start with or a RegExp to test against the field
11362 * @param {Boolean} anyMatch True to match any part not just the beginning
11363 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11365 query : function(property, value, anyMatch){
11366 var fn = this.createFilterFn(property, value, anyMatch);
11367 return fn ? this.queryBy(fn) : this.data.clone();
11371 * Query by a function. The specified function will be called with each
11372 * record in this data source. If the function returns true the record is included
11374 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11375 * @param {Object} scope (optional) The scope of the function (defaults to this)
11376 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11378 queryBy : function(fn, scope){
11379 var data = this.snapshot || this.data;
11380 return data.filterBy(fn, scope||this);
11384 * Collects unique values for a particular dataIndex from this store.
11385 * @param {String} dataIndex The property to collect
11386 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11387 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11388 * @return {Array} An array of the unique values
11390 collect : function(dataIndex, allowNull, bypassFilter){
11391 var d = (bypassFilter === true && this.snapshot) ?
11392 this.snapshot.items : this.data.items;
11393 var v, sv, r = [], l = {};
11394 for(var i = 0, len = d.length; i < len; i++){
11395 v = d[i].data[dataIndex];
11397 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11406 * Revert to a view of the Record cache with no filtering applied.
11407 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11409 clearFilter : function(suppressEvent){
11410 if(this.snapshot && this.snapshot != this.data){
11411 this.data = this.snapshot;
11412 delete this.snapshot;
11413 if(suppressEvent !== true){
11414 this.fireEvent("datachanged", this);
11420 afterEdit : function(record){
11421 if(this.modified.indexOf(record) == -1){
11422 this.modified.push(record);
11424 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11428 afterReject : function(record){
11429 this.modified.remove(record);
11430 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11434 afterCommit : function(record){
11435 this.modified.remove(record);
11436 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11440 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11441 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11443 commitChanges : function(){
11444 var m = this.modified.slice(0);
11445 this.modified = [];
11446 for(var i = 0, len = m.length; i < len; i++){
11452 * Cancel outstanding changes on all changed records.
11454 rejectChanges : function(){
11455 var m = this.modified.slice(0);
11456 this.modified = [];
11457 for(var i = 0, len = m.length; i < len; i++){
11462 onMetaChange : function(meta, rtype, o){
11463 this.recordType = rtype;
11464 this.fields = rtype.prototype.fields;
11465 delete this.snapshot;
11466 this.sortInfo = meta.sortInfo || this.sortInfo;
11467 this.modified = [];
11468 this.fireEvent('metachange', this, this.reader.meta);
11471 moveIndex : function(data, type)
11473 var index = this.indexOf(data);
11475 var newIndex = index + type;
11479 this.insert(newIndex, data);
11484 * Ext JS Library 1.1.1
11485 * Copyright(c) 2006-2007, Ext JS, LLC.
11487 * Originally Released Under LGPL - original licence link has changed is not relivant.
11490 * <script type="text/javascript">
11494 * @class Roo.data.SimpleStore
11495 * @extends Roo.data.Store
11496 * Small helper class to make creating Stores from Array data easier.
11497 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11498 * @cfg {Array} fields An array of field definition objects, or field name strings.
11499 * @cfg {Array} data The multi-dimensional array of data
11501 * @param {Object} config
11503 Roo.data.SimpleStore = function(config){
11504 Roo.data.SimpleStore.superclass.constructor.call(this, {
11506 reader: new Roo.data.ArrayReader({
11509 Roo.data.Record.create(config.fields)
11511 proxy : new Roo.data.MemoryProxy(config.data)
11515 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11517 * Ext JS Library 1.1.1
11518 * Copyright(c) 2006-2007, Ext JS, LLC.
11520 * Originally Released Under LGPL - original licence link has changed is not relivant.
11523 * <script type="text/javascript">
11528 * @extends Roo.data.Store
11529 * @class Roo.data.JsonStore
11530 * Small helper class to make creating Stores for JSON data easier. <br/>
11532 var store = new Roo.data.JsonStore({
11533 url: 'get-images.php',
11535 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11538 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11539 * JsonReader and HttpProxy (unless inline data is provided).</b>
11540 * @cfg {Array} fields An array of field definition objects, or field name strings.
11542 * @param {Object} config
11544 Roo.data.JsonStore = function(c){
11545 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11546 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11547 reader: new Roo.data.JsonReader(c, c.fields)
11550 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11552 * Ext JS Library 1.1.1
11553 * Copyright(c) 2006-2007, Ext JS, LLC.
11555 * Originally Released Under LGPL - original licence link has changed is not relivant.
11558 * <script type="text/javascript">
11562 Roo.data.Field = function(config){
11563 if(typeof config == "string"){
11564 config = {name: config};
11566 Roo.apply(this, config);
11569 this.type = "auto";
11572 var st = Roo.data.SortTypes;
11573 // named sortTypes are supported, here we look them up
11574 if(typeof this.sortType == "string"){
11575 this.sortType = st[this.sortType];
11578 // set default sortType for strings and dates
11579 if(!this.sortType){
11582 this.sortType = st.asUCString;
11585 this.sortType = st.asDate;
11588 this.sortType = st.none;
11593 var stripRe = /[\$,%]/g;
11595 // prebuilt conversion function for this field, instead of
11596 // switching every time we're reading a value
11598 var cv, dateFormat = this.dateFormat;
11603 cv = function(v){ return v; };
11606 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11610 return v !== undefined && v !== null && v !== '' ?
11611 parseInt(String(v).replace(stripRe, ""), 10) : '';
11616 return v !== undefined && v !== null && v !== '' ?
11617 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11622 cv = function(v){ return v === true || v === "true" || v == 1; };
11629 if(v instanceof Date){
11633 if(dateFormat == "timestamp"){
11634 return new Date(v*1000);
11636 return Date.parseDate(v, dateFormat);
11638 var parsed = Date.parse(v);
11639 return parsed ? new Date(parsed) : null;
11648 Roo.data.Field.prototype = {
11656 * Ext JS Library 1.1.1
11657 * Copyright(c) 2006-2007, Ext JS, LLC.
11659 * Originally Released Under LGPL - original licence link has changed is not relivant.
11662 * <script type="text/javascript">
11665 // Base class for reading structured data from a data source. This class is intended to be
11666 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11669 * @class Roo.data.DataReader
11670 * Base class for reading structured data from a data source. This class is intended to be
11671 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11674 Roo.data.DataReader = function(meta, recordType){
11678 this.recordType = recordType instanceof Array ?
11679 Roo.data.Record.create(recordType) : recordType;
11682 Roo.data.DataReader.prototype = {
11684 * Create an empty record
11685 * @param {Object} data (optional) - overlay some values
11686 * @return {Roo.data.Record} record created.
11688 newRow : function(d) {
11690 this.recordType.prototype.fields.each(function(c) {
11692 case 'int' : da[c.name] = 0; break;
11693 case 'date' : da[c.name] = new Date(); break;
11694 case 'float' : da[c.name] = 0.0; break;
11695 case 'boolean' : da[c.name] = false; break;
11696 default : da[c.name] = ""; break;
11700 return new this.recordType(Roo.apply(da, d));
11705 * Ext JS Library 1.1.1
11706 * Copyright(c) 2006-2007, Ext JS, LLC.
11708 * Originally Released Under LGPL - original licence link has changed is not relivant.
11711 * <script type="text/javascript">
11715 * @class Roo.data.DataProxy
11716 * @extends Roo.data.Observable
11717 * This class is an abstract base class for implementations which provide retrieval of
11718 * unformatted data objects.<br>
11720 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11721 * (of the appropriate type which knows how to parse the data object) to provide a block of
11722 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11724 * Custom implementations must implement the load method as described in
11725 * {@link Roo.data.HttpProxy#load}.
11727 Roo.data.DataProxy = function(){
11730 * @event beforeload
11731 * Fires before a network request is made to retrieve a data object.
11732 * @param {Object} This DataProxy object.
11733 * @param {Object} params The params parameter to the load function.
11738 * Fires before the load method's callback is called.
11739 * @param {Object} This DataProxy object.
11740 * @param {Object} o The data object.
11741 * @param {Object} arg The callback argument object passed to the load function.
11745 * @event loadexception
11746 * Fires if an Exception occurs during data retrieval.
11747 * @param {Object} This DataProxy object.
11748 * @param {Object} o The data object.
11749 * @param {Object} arg The callback argument object passed to the load function.
11750 * @param {Object} e The Exception.
11752 loadexception : true
11754 Roo.data.DataProxy.superclass.constructor.call(this);
11757 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11760 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11764 * Ext JS Library 1.1.1
11765 * Copyright(c) 2006-2007, Ext JS, LLC.
11767 * Originally Released Under LGPL - original licence link has changed is not relivant.
11770 * <script type="text/javascript">
11773 * @class Roo.data.MemoryProxy
11774 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11775 * to the Reader when its load method is called.
11777 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11779 Roo.data.MemoryProxy = function(data){
11783 Roo.data.MemoryProxy.superclass.constructor.call(this);
11787 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11790 * Load data from the requested source (in this case an in-memory
11791 * data object passed to the constructor), read the data object into
11792 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11793 * process that block using the passed callback.
11794 * @param {Object} params This parameter is not used by the MemoryProxy class.
11795 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11796 * object into a block of Roo.data.Records.
11797 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11798 * The function must be passed <ul>
11799 * <li>The Record block object</li>
11800 * <li>The "arg" argument from the load function</li>
11801 * <li>A boolean success indicator</li>
11803 * @param {Object} scope The scope in which to call the callback
11804 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11806 load : function(params, reader, callback, scope, arg){
11807 params = params || {};
11810 result = reader.readRecords(this.data);
11812 this.fireEvent("loadexception", this, arg, null, e);
11813 callback.call(scope, null, arg, false);
11816 callback.call(scope, result, arg, true);
11820 update : function(params, records){
11825 * Ext JS Library 1.1.1
11826 * Copyright(c) 2006-2007, Ext JS, LLC.
11828 * Originally Released Under LGPL - original licence link has changed is not relivant.
11831 * <script type="text/javascript">
11834 * @class Roo.data.HttpProxy
11835 * @extends Roo.data.DataProxy
11836 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11837 * configured to reference a certain URL.<br><br>
11839 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11840 * from which the running page was served.<br><br>
11842 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11844 * Be aware that to enable the browser to parse an XML document, the server must set
11845 * the Content-Type header in the HTTP response to "text/xml".
11847 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11848 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11849 * will be used to make the request.
11851 Roo.data.HttpProxy = function(conn){
11852 Roo.data.HttpProxy.superclass.constructor.call(this);
11853 // is conn a conn config or a real conn?
11855 this.useAjax = !conn || !conn.events;
11859 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11860 // thse are take from connection...
11863 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11866 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11867 * extra parameters to each request made by this object. (defaults to undefined)
11870 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11871 * to each request made by this object. (defaults to undefined)
11874 * @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)
11877 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11880 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11886 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11890 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11891 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11892 * a finer-grained basis than the DataProxy events.
11894 getConnection : function(){
11895 return this.useAjax ? Roo.Ajax : this.conn;
11899 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11900 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11901 * process that block using the passed callback.
11902 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11903 * for the request to the remote server.
11904 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11905 * object into a block of Roo.data.Records.
11906 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11907 * The function must be passed <ul>
11908 * <li>The Record block object</li>
11909 * <li>The "arg" argument from the load function</li>
11910 * <li>A boolean success indicator</li>
11912 * @param {Object} scope The scope in which to call the callback
11913 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11915 load : function(params, reader, callback, scope, arg){
11916 if(this.fireEvent("beforeload", this, params) !== false){
11918 params : params || {},
11920 callback : callback,
11925 callback : this.loadResponse,
11929 Roo.applyIf(o, this.conn);
11930 if(this.activeRequest){
11931 Roo.Ajax.abort(this.activeRequest);
11933 this.activeRequest = Roo.Ajax.request(o);
11935 this.conn.request(o);
11938 callback.call(scope||this, null, arg, false);
11943 loadResponse : function(o, success, response){
11944 delete this.activeRequest;
11946 this.fireEvent("loadexception", this, o, response);
11947 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11952 result = o.reader.read(response);
11954 this.fireEvent("loadexception", this, o, response, e);
11955 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11959 this.fireEvent("load", this, o, o.request.arg);
11960 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11964 update : function(dataSet){
11969 updateResponse : function(dataSet){
11974 * Ext JS Library 1.1.1
11975 * Copyright(c) 2006-2007, Ext JS, LLC.
11977 * Originally Released Under LGPL - original licence link has changed is not relivant.
11980 * <script type="text/javascript">
11984 * @class Roo.data.ScriptTagProxy
11985 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11986 * other than the originating domain of the running page.<br><br>
11988 * <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
11989 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11991 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11992 * source code that is used as the source inside a <script> tag.<br><br>
11994 * In order for the browser to process the returned data, the server must wrap the data object
11995 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11996 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11997 * depending on whether the callback name was passed:
12000 boolean scriptTag = false;
12001 String cb = request.getParameter("callback");
12004 response.setContentType("text/javascript");
12006 response.setContentType("application/x-json");
12008 Writer out = response.getWriter();
12010 out.write(cb + "(");
12012 out.print(dataBlock.toJsonString());
12019 * @param {Object} config A configuration object.
12021 Roo.data.ScriptTagProxy = function(config){
12022 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12023 Roo.apply(this, config);
12024 this.head = document.getElementsByTagName("head")[0];
12027 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12029 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12031 * @cfg {String} url The URL from which to request the data object.
12034 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12038 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12039 * the server the name of the callback function set up by the load call to process the returned data object.
12040 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12041 * javascript output which calls this named function passing the data object as its only parameter.
12043 callbackParam : "callback",
12045 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12046 * name to the request.
12051 * Load data from the configured URL, read the data object into
12052 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12053 * process that block using the passed callback.
12054 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12055 * for the request to the remote server.
12056 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12057 * object into a block of Roo.data.Records.
12058 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12059 * The function must be passed <ul>
12060 * <li>The Record block object</li>
12061 * <li>The "arg" argument from the load function</li>
12062 * <li>A boolean success indicator</li>
12064 * @param {Object} scope The scope in which to call the callback
12065 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12067 load : function(params, reader, callback, scope, arg){
12068 if(this.fireEvent("beforeload", this, params) !== false){
12070 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12072 var url = this.url;
12073 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12075 url += "&_dc=" + (new Date().getTime());
12077 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12080 cb : "stcCallback"+transId,
12081 scriptId : "stcScript"+transId,
12085 callback : callback,
12091 window[trans.cb] = function(o){
12092 conn.handleResponse(o, trans);
12095 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12097 if(this.autoAbort !== false){
12101 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12103 var script = document.createElement("script");
12104 script.setAttribute("src", url);
12105 script.setAttribute("type", "text/javascript");
12106 script.setAttribute("id", trans.scriptId);
12107 this.head.appendChild(script);
12109 this.trans = trans;
12111 callback.call(scope||this, null, arg, false);
12116 isLoading : function(){
12117 return this.trans ? true : false;
12121 * Abort the current server request.
12123 abort : function(){
12124 if(this.isLoading()){
12125 this.destroyTrans(this.trans);
12130 destroyTrans : function(trans, isLoaded){
12131 this.head.removeChild(document.getElementById(trans.scriptId));
12132 clearTimeout(trans.timeoutId);
12134 window[trans.cb] = undefined;
12136 delete window[trans.cb];
12139 // if hasn't been loaded, wait for load to remove it to prevent script error
12140 window[trans.cb] = function(){
12141 window[trans.cb] = undefined;
12143 delete window[trans.cb];
12150 handleResponse : function(o, trans){
12151 this.trans = false;
12152 this.destroyTrans(trans, true);
12155 result = trans.reader.readRecords(o);
12157 this.fireEvent("loadexception", this, o, trans.arg, e);
12158 trans.callback.call(trans.scope||window, null, trans.arg, false);
12161 this.fireEvent("load", this, o, trans.arg);
12162 trans.callback.call(trans.scope||window, result, trans.arg, true);
12166 handleFailure : function(trans){
12167 this.trans = false;
12168 this.destroyTrans(trans, false);
12169 this.fireEvent("loadexception", this, null, trans.arg);
12170 trans.callback.call(trans.scope||window, null, trans.arg, false);
12174 * Ext JS Library 1.1.1
12175 * Copyright(c) 2006-2007, Ext JS, LLC.
12177 * Originally Released Under LGPL - original licence link has changed is not relivant.
12180 * <script type="text/javascript">
12184 * @class Roo.data.JsonReader
12185 * @extends Roo.data.DataReader
12186 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12187 * based on mappings in a provided Roo.data.Record constructor.
12189 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12190 * in the reply previously.
12195 var RecordDef = Roo.data.Record.create([
12196 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12197 {name: 'occupation'} // This field will use "occupation" as the mapping.
12199 var myReader = new Roo.data.JsonReader({
12200 totalProperty: "results", // The property which contains the total dataset size (optional)
12201 root: "rows", // The property which contains an Array of row objects
12202 id: "id" // The property within each row object that provides an ID for the record (optional)
12206 * This would consume a JSON file like this:
12208 { 'results': 2, 'rows': [
12209 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12210 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12213 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12214 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12215 * paged from the remote server.
12216 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12217 * @cfg {String} root name of the property which contains the Array of row objects.
12218 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12219 * @cfg {Array} fields Array of field definition objects
12221 * Create a new JsonReader
12222 * @param {Object} meta Metadata configuration options
12223 * @param {Object} recordType Either an Array of field definition objects,
12224 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12226 Roo.data.JsonReader = function(meta, recordType){
12229 // set some defaults:
12230 Roo.applyIf(meta, {
12231 totalProperty: 'total',
12232 successProperty : 'success',
12237 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12239 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12242 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12243 * Used by Store query builder to append _requestMeta to params.
12246 metaFromRemote : false,
12248 * This method is only used by a DataProxy which has retrieved data from a remote server.
12249 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12250 * @return {Object} data A data block which is used by an Roo.data.Store object as
12251 * a cache of Roo.data.Records.
12253 read : function(response){
12254 var json = response.responseText;
12256 var o = /* eval:var:o */ eval("("+json+")");
12258 throw {message: "JsonReader.read: Json object not found"};
12264 this.metaFromRemote = true;
12265 this.meta = o.metaData;
12266 this.recordType = Roo.data.Record.create(o.metaData.fields);
12267 this.onMetaChange(this.meta, this.recordType, o);
12269 return this.readRecords(o);
12272 // private function a store will implement
12273 onMetaChange : function(meta, recordType, o){
12280 simpleAccess: function(obj, subsc) {
12287 getJsonAccessor: function(){
12289 return function(expr) {
12291 return(re.test(expr))
12292 ? new Function("obj", "return obj." + expr)
12297 return Roo.emptyFn;
12302 * Create a data block containing Roo.data.Records from an XML document.
12303 * @param {Object} o An object which contains an Array of row objects in the property specified
12304 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12305 * which contains the total size of the dataset.
12306 * @return {Object} data A data block which is used by an Roo.data.Store object as
12307 * a cache of Roo.data.Records.
12309 readRecords : function(o){
12311 * After any data loads, the raw JSON data is available for further custom processing.
12315 var s = this.meta, Record = this.recordType,
12316 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12318 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12320 if(s.totalProperty) {
12321 this.getTotal = this.getJsonAccessor(s.totalProperty);
12323 if(s.successProperty) {
12324 this.getSuccess = this.getJsonAccessor(s.successProperty);
12326 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12328 var g = this.getJsonAccessor(s.id);
12329 this.getId = function(rec) {
12331 return (r === undefined || r === "") ? null : r;
12334 this.getId = function(){return null;};
12337 for(var jj = 0; jj < fl; jj++){
12339 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12340 this.ef[jj] = this.getJsonAccessor(map);
12344 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12345 if(s.totalProperty){
12346 var vt = parseInt(this.getTotal(o), 10);
12351 if(s.successProperty){
12352 var vs = this.getSuccess(o);
12353 if(vs === false || vs === 'false'){
12358 for(var i = 0; i < c; i++){
12361 var id = this.getId(n);
12362 for(var j = 0; j < fl; j++){
12364 var v = this.ef[j](n);
12366 Roo.log('missing convert for ' + f.name);
12370 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12372 var record = new Record(values, id);
12374 records[i] = record;
12380 totalRecords : totalRecords
12385 * Ext JS Library 1.1.1
12386 * Copyright(c) 2006-2007, Ext JS, LLC.
12388 * Originally Released Under LGPL - original licence link has changed is not relivant.
12391 * <script type="text/javascript">
12395 * @class Roo.data.ArrayReader
12396 * @extends Roo.data.DataReader
12397 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12398 * Each element of that Array represents a row of data fields. The
12399 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12400 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12404 var RecordDef = Roo.data.Record.create([
12405 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12406 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12408 var myReader = new Roo.data.ArrayReader({
12409 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12413 * This would consume an Array like this:
12415 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12417 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12419 * Create a new JsonReader
12420 * @param {Object} meta Metadata configuration options.
12421 * @param {Object} recordType Either an Array of field definition objects
12422 * as specified to {@link Roo.data.Record#create},
12423 * or an {@link Roo.data.Record} object
12424 * created using {@link Roo.data.Record#create}.
12426 Roo.data.ArrayReader = function(meta, recordType){
12427 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12430 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12432 * Create a data block containing Roo.data.Records from an XML document.
12433 * @param {Object} o An Array of row objects which represents the dataset.
12434 * @return {Object} data A data block which is used by an Roo.data.Store object as
12435 * a cache of Roo.data.Records.
12437 readRecords : function(o){
12438 var sid = this.meta ? this.meta.id : null;
12439 var recordType = this.recordType, fields = recordType.prototype.fields;
12442 for(var i = 0; i < root.length; i++){
12445 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12446 for(var j = 0, jlen = fields.length; j < jlen; j++){
12447 var f = fields.items[j];
12448 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12449 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12451 values[f.name] = v;
12453 var record = new recordType(values, id);
12455 records[records.length] = record;
12459 totalRecords : records.length
12468 * @class Roo.bootstrap.ComboBox
12469 * @extends Roo.bootstrap.TriggerField
12470 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12471 * @cfg {Boolean} append (true|false) default false
12472 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12473 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12474 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12475 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12476 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12477 * @cfg {Boolean} animate default true
12478 * @cfg {Boolean} emptyResultText only for touch device
12479 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12480 * @cfg {String} emptyTitle default ''
12482 * Create a new ComboBox.
12483 * @param {Object} config Configuration options
12485 Roo.bootstrap.ComboBox = function(config){
12486 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12490 * Fires when the dropdown list is expanded
12491 * @param {Roo.bootstrap.ComboBox} combo This combo box
12496 * Fires when the dropdown list is collapsed
12497 * @param {Roo.bootstrap.ComboBox} combo This combo box
12501 * @event beforeselect
12502 * Fires before a list item is selected. Return false to cancel the selection.
12503 * @param {Roo.bootstrap.ComboBox} combo This combo box
12504 * @param {Roo.data.Record} record The data record returned from the underlying store
12505 * @param {Number} index The index of the selected item in the dropdown list
12507 'beforeselect' : true,
12510 * Fires when a list item is selected
12511 * @param {Roo.bootstrap.ComboBox} combo This combo box
12512 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12513 * @param {Number} index The index of the selected item in the dropdown list
12517 * @event beforequery
12518 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12519 * The event object passed has these properties:
12520 * @param {Roo.bootstrap.ComboBox} combo This combo box
12521 * @param {String} query The query
12522 * @param {Boolean} forceAll true to force "all" query
12523 * @param {Boolean} cancel true to cancel the query
12524 * @param {Object} e The query event object
12526 'beforequery': true,
12529 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12530 * @param {Roo.bootstrap.ComboBox} combo This combo box
12535 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12536 * @param {Roo.bootstrap.ComboBox} combo This combo box
12537 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12542 * Fires when the remove value from the combobox array
12543 * @param {Roo.bootstrap.ComboBox} combo This combo box
12547 * @event afterremove
12548 * Fires when the remove value from the combobox array
12549 * @param {Roo.bootstrap.ComboBox} combo This combo box
12551 'afterremove' : true,
12553 * @event specialfilter
12554 * Fires when specialfilter
12555 * @param {Roo.bootstrap.ComboBox} combo This combo box
12557 'specialfilter' : true,
12560 * Fires when tick the element
12561 * @param {Roo.bootstrap.ComboBox} combo This combo box
12565 * @event touchviewdisplay
12566 * Fires when touch view require special display (default is using displayField)
12567 * @param {Roo.bootstrap.ComboBox} combo This combo box
12568 * @param {Object} cfg set html .
12570 'touchviewdisplay' : true
12575 this.tickItems = [];
12577 this.selectedIndex = -1;
12578 if(this.mode == 'local'){
12579 if(config.queryDelay === undefined){
12580 this.queryDelay = 10;
12582 if(config.minChars === undefined){
12588 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12591 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12592 * rendering into an Roo.Editor, defaults to false)
12595 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12596 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12599 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12602 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12603 * the dropdown list (defaults to undefined, with no header element)
12607 * @cfg {String/Roo.Template} tpl The template to use to render the output
12611 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12613 listWidth: undefined,
12615 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12616 * mode = 'remote' or 'text' if mode = 'local')
12618 displayField: undefined,
12621 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12622 * mode = 'remote' or 'value' if mode = 'local').
12623 * Note: use of a valueField requires the user make a selection
12624 * in order for a value to be mapped.
12626 valueField: undefined,
12628 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12633 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12634 * field's data value (defaults to the underlying DOM element's name)
12636 hiddenName: undefined,
12638 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12642 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12644 selectedClass: 'active',
12647 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12651 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12652 * anchor positions (defaults to 'tl-bl')
12654 listAlign: 'tl-bl?',
12656 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12660 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12661 * query specified by the allQuery config option (defaults to 'query')
12663 triggerAction: 'query',
12665 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12666 * (defaults to 4, does not apply if editable = false)
12670 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12671 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12675 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12676 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12680 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12681 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12685 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12686 * when editable = true (defaults to false)
12688 selectOnFocus:false,
12690 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12692 queryParam: 'query',
12694 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12695 * when mode = 'remote' (defaults to 'Loading...')
12697 loadingText: 'Loading...',
12699 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12703 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12707 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12708 * traditional select (defaults to true)
12712 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12716 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12720 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12721 * listWidth has a higher value)
12725 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12726 * allow the user to set arbitrary text into the field (defaults to false)
12728 forceSelection:false,
12730 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12731 * if typeAhead = true (defaults to 250)
12733 typeAheadDelay : 250,
12735 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12736 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12738 valueNotFoundText : undefined,
12740 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12742 blockFocus : false,
12745 * @cfg {Boolean} disableClear Disable showing of clear button.
12747 disableClear : false,
12749 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12751 alwaysQuery : false,
12754 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12759 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12761 invalidClass : "has-warning",
12764 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12766 validClass : "has-success",
12769 * @cfg {Boolean} specialFilter (true|false) special filter default false
12771 specialFilter : false,
12774 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12776 mobileTouchView : true,
12779 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12781 useNativeIOS : false,
12783 ios_options : false,
12795 btnPosition : 'right',
12796 triggerList : true,
12797 showToggleBtn : true,
12799 emptyResultText: 'Empty',
12800 triggerText : 'Select',
12803 // element that contains real text value.. (when hidden is used..)
12805 getAutoCreate : function()
12810 * Render classic select for iso
12813 if(Roo.isIOS && this.useNativeIOS){
12814 cfg = this.getAutoCreateNativeIOS();
12822 if(Roo.isTouch && this.mobileTouchView){
12823 cfg = this.getAutoCreateTouchView();
12830 if(!this.tickable){
12831 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12836 * ComboBox with tickable selections
12839 var align = this.labelAlign || this.parentLabelAlign();
12842 cls : 'form-group roo-combobox-tickable' //input-group
12845 var btn_text_select = '';
12846 var btn_text_done = '';
12847 var btn_text_cancel = '';
12849 if (this.btn_text_show) {
12850 btn_text_select = 'Select';
12851 btn_text_done = 'Done';
12852 btn_text_cancel = 'Cancel';
12857 cls : 'tickable-buttons',
12862 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12863 //html : this.triggerText
12864 html: btn_text_select
12870 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12872 html: btn_text_done
12878 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12880 html: btn_text_cancel
12886 buttons.cn.unshift({
12888 cls: 'roo-select2-search-field-input'
12894 Roo.each(buttons.cn, function(c){
12896 c.cls += ' btn-' + _this.size;
12899 if (_this.disabled) {
12910 cls: 'form-hidden-field'
12914 cls: 'roo-select2-choices',
12918 cls: 'roo-select2-search-field',
12929 cls: 'roo-select2-container input-group roo-select2-container-multi',
12934 // cls: 'typeahead typeahead-long dropdown-menu',
12935 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12940 if(this.hasFeedback && !this.allowBlank){
12944 cls: 'glyphicon form-control-feedback'
12947 combobox.cn.push(feedback);
12951 if (align ==='left' && this.fieldLabel.length) {
12953 cfg.cls += ' roo-form-group-label-left';
12958 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12959 tooltip : 'This field is required'
12964 cls : 'control-label',
12965 html : this.fieldLabel
12977 var labelCfg = cfg.cn[1];
12978 var contentCfg = cfg.cn[2];
12981 if(this.indicatorpos == 'right'){
12987 cls : 'control-label',
12991 html : this.fieldLabel
12995 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12996 tooltip : 'This field is required'
13011 labelCfg = cfg.cn[0];
13012 contentCfg = cfg.cn[1];
13016 if(this.labelWidth > 12){
13017 labelCfg.style = "width: " + this.labelWidth + 'px';
13020 if(this.labelWidth < 13 && this.labelmd == 0){
13021 this.labelmd = this.labelWidth;
13024 if(this.labellg > 0){
13025 labelCfg.cls += ' col-lg-' + this.labellg;
13026 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13029 if(this.labelmd > 0){
13030 labelCfg.cls += ' col-md-' + this.labelmd;
13031 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13034 if(this.labelsm > 0){
13035 labelCfg.cls += ' col-sm-' + this.labelsm;
13036 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13039 if(this.labelxs > 0){
13040 labelCfg.cls += ' col-xs-' + this.labelxs;
13041 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13045 } else if ( this.fieldLabel.length) {
13046 // Roo.log(" label");
13050 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13051 tooltip : 'This field is required'
13055 //cls : 'input-group-addon',
13056 html : this.fieldLabel
13061 if(this.indicatorpos == 'right'){
13065 //cls : 'input-group-addon',
13066 html : this.fieldLabel
13070 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13071 tooltip : 'This field is required'
13080 // Roo.log(" no label && no align");
13087 ['xs','sm','md','lg'].map(function(size){
13088 if (settings[size]) {
13089 cfg.cls += ' col-' + size + '-' + settings[size];
13097 _initEventsCalled : false,
13100 initEvents: function()
13102 if (this._initEventsCalled) { // as we call render... prevent looping...
13105 this._initEventsCalled = true;
13108 throw "can not find store for combo";
13111 this.indicator = this.indicatorEl();
13113 this.store = Roo.factory(this.store, Roo.data);
13114 this.store.parent = this;
13116 // if we are building from html. then this element is so complex, that we can not really
13117 // use the rendered HTML.
13118 // so we have to trash and replace the previous code.
13119 if (Roo.XComponent.build_from_html) {
13120 // remove this element....
13121 var e = this.el.dom, k=0;
13122 while (e ) { e = e.previousSibling; ++k;}
13127 this.rendered = false;
13129 this.render(this.parent().getChildContainer(true), k);
13132 if(Roo.isIOS && this.useNativeIOS){
13133 this.initIOSView();
13141 if(Roo.isTouch && this.mobileTouchView){
13142 this.initTouchView();
13147 this.initTickableEvents();
13151 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13153 if(this.hiddenName){
13155 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13157 this.hiddenField.dom.value =
13158 this.hiddenValue !== undefined ? this.hiddenValue :
13159 this.value !== undefined ? this.value : '';
13161 // prevent input submission
13162 this.el.dom.removeAttribute('name');
13163 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13168 // this.el.dom.setAttribute('autocomplete', 'off');
13171 var cls = 'x-combo-list';
13173 //this.list = new Roo.Layer({
13174 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13180 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13181 _this.list.setWidth(lw);
13184 this.list.on('mouseover', this.onViewOver, this);
13185 this.list.on('mousemove', this.onViewMove, this);
13186 this.list.on('scroll', this.onViewScroll, this);
13189 this.list.swallowEvent('mousewheel');
13190 this.assetHeight = 0;
13193 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13194 this.assetHeight += this.header.getHeight();
13197 this.innerList = this.list.createChild({cls:cls+'-inner'});
13198 this.innerList.on('mouseover', this.onViewOver, this);
13199 this.innerList.on('mousemove', this.onViewMove, this);
13200 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13202 if(this.allowBlank && !this.pageSize && !this.disableClear){
13203 this.footer = this.list.createChild({cls:cls+'-ft'});
13204 this.pageTb = new Roo.Toolbar(this.footer);
13208 this.footer = this.list.createChild({cls:cls+'-ft'});
13209 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13210 {pageSize: this.pageSize});
13214 if (this.pageTb && this.allowBlank && !this.disableClear) {
13216 this.pageTb.add(new Roo.Toolbar.Fill(), {
13217 cls: 'x-btn-icon x-btn-clear',
13219 handler: function()
13222 _this.clearValue();
13223 _this.onSelect(false, -1);
13228 this.assetHeight += this.footer.getHeight();
13233 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13236 this.view = new Roo.View(this.list, this.tpl, {
13237 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13239 //this.view.wrapEl.setDisplayed(false);
13240 this.view.on('click', this.onViewClick, this);
13243 this.store.on('beforeload', this.onBeforeLoad, this);
13244 this.store.on('load', this.onLoad, this);
13245 this.store.on('loadexception', this.onLoadException, this);
13247 if(this.resizable){
13248 this.resizer = new Roo.Resizable(this.list, {
13249 pinned:true, handles:'se'
13251 this.resizer.on('resize', function(r, w, h){
13252 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13253 this.listWidth = w;
13254 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13255 this.restrictHeight();
13257 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13260 if(!this.editable){
13261 this.editable = true;
13262 this.setEditable(false);
13267 if (typeof(this.events.add.listeners) != 'undefined') {
13269 this.addicon = this.wrap.createChild(
13270 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13272 this.addicon.on('click', function(e) {
13273 this.fireEvent('add', this);
13276 if (typeof(this.events.edit.listeners) != 'undefined') {
13278 this.editicon = this.wrap.createChild(
13279 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13280 if (this.addicon) {
13281 this.editicon.setStyle('margin-left', '40px');
13283 this.editicon.on('click', function(e) {
13285 // we fire even if inothing is selected..
13286 this.fireEvent('edit', this, this.lastData );
13292 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13293 "up" : function(e){
13294 this.inKeyMode = true;
13298 "down" : function(e){
13299 if(!this.isExpanded()){
13300 this.onTriggerClick();
13302 this.inKeyMode = true;
13307 "enter" : function(e){
13308 // this.onViewClick();
13312 if(this.fireEvent("specialkey", this, e)){
13313 this.onViewClick(false);
13319 "esc" : function(e){
13323 "tab" : function(e){
13326 if(this.fireEvent("specialkey", this, e)){
13327 this.onViewClick(false);
13335 doRelay : function(foo, bar, hname){
13336 if(hname == 'down' || this.scope.isExpanded()){
13337 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13346 this.queryDelay = Math.max(this.queryDelay || 10,
13347 this.mode == 'local' ? 10 : 250);
13350 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13352 if(this.typeAhead){
13353 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13355 if(this.editable !== false){
13356 this.inputEl().on("keyup", this.onKeyUp, this);
13358 if(this.forceSelection){
13359 this.inputEl().on('blur', this.doForce, this);
13363 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13364 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13368 initTickableEvents: function()
13372 if(this.hiddenName){
13374 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13376 this.hiddenField.dom.value =
13377 this.hiddenValue !== undefined ? this.hiddenValue :
13378 this.value !== undefined ? this.value : '';
13380 // prevent input submission
13381 this.el.dom.removeAttribute('name');
13382 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13387 // this.list = this.el.select('ul.dropdown-menu',true).first();
13389 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13390 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13391 if(this.triggerList){
13392 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13395 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13396 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13398 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13399 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13401 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13402 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13404 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13405 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13406 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13409 this.cancelBtn.hide();
13414 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13415 _this.list.setWidth(lw);
13418 this.list.on('mouseover', this.onViewOver, this);
13419 this.list.on('mousemove', this.onViewMove, this);
13421 this.list.on('scroll', this.onViewScroll, this);
13424 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>';
13427 this.view = new Roo.View(this.list, this.tpl, {
13428 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13431 //this.view.wrapEl.setDisplayed(false);
13432 this.view.on('click', this.onViewClick, this);
13436 this.store.on('beforeload', this.onBeforeLoad, this);
13437 this.store.on('load', this.onLoad, this);
13438 this.store.on('loadexception', this.onLoadException, this);
13441 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13442 "up" : function(e){
13443 this.inKeyMode = true;
13447 "down" : function(e){
13448 this.inKeyMode = true;
13452 "enter" : function(e){
13453 if(this.fireEvent("specialkey", this, e)){
13454 this.onViewClick(false);
13460 "esc" : function(e){
13461 this.onTickableFooterButtonClick(e, false, false);
13464 "tab" : function(e){
13465 this.fireEvent("specialkey", this, e);
13467 this.onTickableFooterButtonClick(e, false, false);
13474 doRelay : function(e, fn, key){
13475 if(this.scope.isExpanded()){
13476 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13485 this.queryDelay = Math.max(this.queryDelay || 10,
13486 this.mode == 'local' ? 10 : 250);
13489 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13491 if(this.typeAhead){
13492 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13495 if(this.editable !== false){
13496 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13499 this.indicator = this.indicatorEl();
13501 if(this.indicator){
13502 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13503 this.indicator.hide();
13508 onDestroy : function(){
13510 this.view.setStore(null);
13511 this.view.el.removeAllListeners();
13512 this.view.el.remove();
13513 this.view.purgeListeners();
13516 this.list.dom.innerHTML = '';
13520 this.store.un('beforeload', this.onBeforeLoad, this);
13521 this.store.un('load', this.onLoad, this);
13522 this.store.un('loadexception', this.onLoadException, this);
13524 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13528 fireKey : function(e){
13529 if(e.isNavKeyPress() && !this.list.isVisible()){
13530 this.fireEvent("specialkey", this, e);
13535 onResize: function(w, h){
13536 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13538 // if(typeof w != 'number'){
13539 // // we do not handle it!?!?
13542 // var tw = this.trigger.getWidth();
13543 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13544 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13546 // this.inputEl().setWidth( this.adjustWidth('input', x));
13548 // //this.trigger.setStyle('left', x+'px');
13550 // if(this.list && this.listWidth === undefined){
13551 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13552 // this.list.setWidth(lw);
13553 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13561 * Allow or prevent the user from directly editing the field text. If false is passed,
13562 * the user will only be able to select from the items defined in the dropdown list. This method
13563 * is the runtime equivalent of setting the 'editable' config option at config time.
13564 * @param {Boolean} value True to allow the user to directly edit the field text
13566 setEditable : function(value){
13567 if(value == this.editable){
13570 this.editable = value;
13572 this.inputEl().dom.setAttribute('readOnly', true);
13573 this.inputEl().on('mousedown', this.onTriggerClick, this);
13574 this.inputEl().addClass('x-combo-noedit');
13576 this.inputEl().dom.setAttribute('readOnly', false);
13577 this.inputEl().un('mousedown', this.onTriggerClick, this);
13578 this.inputEl().removeClass('x-combo-noedit');
13584 onBeforeLoad : function(combo,opts){
13585 if(!this.hasFocus){
13589 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13591 this.restrictHeight();
13592 this.selectedIndex = -1;
13596 onLoad : function(){
13598 this.hasQuery = false;
13600 if(!this.hasFocus){
13604 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13605 this.loading.hide();
13608 if(this.store.getCount() > 0){
13611 this.restrictHeight();
13612 if(this.lastQuery == this.allQuery){
13613 if(this.editable && !this.tickable){
13614 this.inputEl().dom.select();
13618 !this.selectByValue(this.value, true) &&
13621 !this.store.lastOptions ||
13622 typeof(this.store.lastOptions.add) == 'undefined' ||
13623 this.store.lastOptions.add != true
13626 this.select(0, true);
13629 if(this.autoFocus){
13632 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13633 this.taTask.delay(this.typeAheadDelay);
13637 this.onEmptyResults();
13643 onLoadException : function()
13645 this.hasQuery = false;
13647 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13648 this.loading.hide();
13651 if(this.tickable && this.editable){
13656 // only causes errors at present
13657 //Roo.log(this.store.reader.jsonData);
13658 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13660 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13666 onTypeAhead : function(){
13667 if(this.store.getCount() > 0){
13668 var r = this.store.getAt(0);
13669 var newValue = r.data[this.displayField];
13670 var len = newValue.length;
13671 var selStart = this.getRawValue().length;
13673 if(selStart != len){
13674 this.setRawValue(newValue);
13675 this.selectText(selStart, newValue.length);
13681 onSelect : function(record, index){
13683 if(this.fireEvent('beforeselect', this, record, index) !== false){
13685 this.setFromData(index > -1 ? record.data : false);
13688 this.fireEvent('select', this, record, index);
13693 * Returns the currently selected field value or empty string if no value is set.
13694 * @return {String} value The selected value
13696 getValue : function()
13698 if(Roo.isIOS && this.useNativeIOS){
13699 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13703 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13706 if(this.valueField){
13707 return typeof this.value != 'undefined' ? this.value : '';
13709 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13713 getRawValue : function()
13715 if(Roo.isIOS && this.useNativeIOS){
13716 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13719 var v = this.inputEl().getValue();
13725 * Clears any text/value currently set in the field
13727 clearValue : function(){
13729 if(this.hiddenField){
13730 this.hiddenField.dom.value = '';
13733 this.setRawValue('');
13734 this.lastSelectionText = '';
13735 this.lastData = false;
13737 var close = this.closeTriggerEl();
13748 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13749 * will be displayed in the field. If the value does not match the data value of an existing item,
13750 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13751 * Otherwise the field will be blank (although the value will still be set).
13752 * @param {String} value The value to match
13754 setValue : function(v)
13756 if(Roo.isIOS && this.useNativeIOS){
13757 this.setIOSValue(v);
13767 if(this.valueField){
13768 var r = this.findRecord(this.valueField, v);
13770 text = r.data[this.displayField];
13771 }else if(this.valueNotFoundText !== undefined){
13772 text = this.valueNotFoundText;
13775 this.lastSelectionText = text;
13776 if(this.hiddenField){
13777 this.hiddenField.dom.value = v;
13779 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13782 var close = this.closeTriggerEl();
13785 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13791 * @property {Object} the last set data for the element
13796 * Sets the value of the field based on a object which is related to the record format for the store.
13797 * @param {Object} value the value to set as. or false on reset?
13799 setFromData : function(o){
13806 var dv = ''; // display value
13807 var vv = ''; // value value..
13809 if (this.displayField) {
13810 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13812 // this is an error condition!!!
13813 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13816 if(this.valueField){
13817 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13820 var close = this.closeTriggerEl();
13823 if(dv.length || vv * 1 > 0){
13825 this.blockFocus=true;
13831 if(this.hiddenField){
13832 this.hiddenField.dom.value = vv;
13834 this.lastSelectionText = dv;
13835 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13839 // no hidden field.. - we store the value in 'value', but still display
13840 // display field!!!!
13841 this.lastSelectionText = dv;
13842 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13849 reset : function(){
13850 // overridden so that last data is reset..
13857 this.setValue(this.originalValue);
13858 //this.clearInvalid();
13859 this.lastData = false;
13861 this.view.clearSelections();
13867 findRecord : function(prop, value){
13869 if(this.store.getCount() > 0){
13870 this.store.each(function(r){
13871 if(r.data[prop] == value){
13881 getName: function()
13883 // returns hidden if it's set..
13884 if (!this.rendered) {return ''};
13885 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13889 onViewMove : function(e, t){
13890 this.inKeyMode = false;
13894 onViewOver : function(e, t){
13895 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13898 var item = this.view.findItemFromChild(t);
13901 var index = this.view.indexOf(item);
13902 this.select(index, false);
13907 onViewClick : function(view, doFocus, el, e)
13909 var index = this.view.getSelectedIndexes()[0];
13911 var r = this.store.getAt(index);
13915 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13922 Roo.each(this.tickItems, function(v,k){
13924 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13926 _this.tickItems.splice(k, 1);
13928 if(typeof(e) == 'undefined' && view == false){
13929 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13941 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13942 this.tickItems.push(r.data);
13945 if(typeof(e) == 'undefined' && view == false){
13946 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13953 this.onSelect(r, index);
13955 if(doFocus !== false && !this.blockFocus){
13956 this.inputEl().focus();
13961 restrictHeight : function(){
13962 //this.innerList.dom.style.height = '';
13963 //var inner = this.innerList.dom;
13964 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13965 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13966 //this.list.beginUpdate();
13967 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13968 this.list.alignTo(this.inputEl(), this.listAlign);
13969 this.list.alignTo(this.inputEl(), this.listAlign);
13970 //this.list.endUpdate();
13974 onEmptyResults : function(){
13976 if(this.tickable && this.editable){
13977 this.restrictHeight();
13985 * Returns true if the dropdown list is expanded, else false.
13987 isExpanded : function(){
13988 return this.list.isVisible();
13992 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13993 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13994 * @param {String} value The data value of the item to select
13995 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13996 * selected item if it is not currently in view (defaults to true)
13997 * @return {Boolean} True if the value matched an item in the list, else false
13999 selectByValue : function(v, scrollIntoView){
14000 if(v !== undefined && v !== null){
14001 var r = this.findRecord(this.valueField || this.displayField, v);
14003 this.select(this.store.indexOf(r), scrollIntoView);
14011 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14012 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14013 * @param {Number} index The zero-based index of the list item to select
14014 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14015 * selected item if it is not currently in view (defaults to true)
14017 select : function(index, scrollIntoView){
14018 this.selectedIndex = index;
14019 this.view.select(index);
14020 if(scrollIntoView !== false){
14021 var el = this.view.getNode(index);
14023 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14026 this.list.scrollChildIntoView(el, false);
14032 selectNext : function(){
14033 var ct = this.store.getCount();
14035 if(this.selectedIndex == -1){
14037 }else if(this.selectedIndex < ct-1){
14038 this.select(this.selectedIndex+1);
14044 selectPrev : function(){
14045 var ct = this.store.getCount();
14047 if(this.selectedIndex == -1){
14049 }else if(this.selectedIndex != 0){
14050 this.select(this.selectedIndex-1);
14056 onKeyUp : function(e){
14057 if(this.editable !== false && !e.isSpecialKey()){
14058 this.lastKey = e.getKey();
14059 this.dqTask.delay(this.queryDelay);
14064 validateBlur : function(){
14065 return !this.list || !this.list.isVisible();
14069 initQuery : function(){
14071 var v = this.getRawValue();
14073 if(this.tickable && this.editable){
14074 v = this.tickableInputEl().getValue();
14081 doForce : function(){
14082 if(this.inputEl().dom.value.length > 0){
14083 this.inputEl().dom.value =
14084 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14090 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14091 * query allowing the query action to be canceled if needed.
14092 * @param {String} query The SQL query to execute
14093 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14094 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14095 * saved in the current store (defaults to false)
14097 doQuery : function(q, forceAll){
14099 if(q === undefined || q === null){
14104 forceAll: forceAll,
14108 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14113 forceAll = qe.forceAll;
14114 if(forceAll === true || (q.length >= this.minChars)){
14116 this.hasQuery = true;
14118 if(this.lastQuery != q || this.alwaysQuery){
14119 this.lastQuery = q;
14120 if(this.mode == 'local'){
14121 this.selectedIndex = -1;
14123 this.store.clearFilter();
14126 if(this.specialFilter){
14127 this.fireEvent('specialfilter', this);
14132 this.store.filter(this.displayField, q);
14135 this.store.fireEvent("datachanged", this.store);
14142 this.store.baseParams[this.queryParam] = q;
14144 var options = {params : this.getParams(q)};
14147 options.add = true;
14148 options.params.start = this.page * this.pageSize;
14151 this.store.load(options);
14154 * this code will make the page width larger, at the beginning, the list not align correctly,
14155 * we should expand the list on onLoad
14156 * so command out it
14161 this.selectedIndex = -1;
14166 this.loadNext = false;
14170 getParams : function(q){
14172 //p[this.queryParam] = q;
14176 p.limit = this.pageSize;
14182 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14184 collapse : function(){
14185 if(!this.isExpanded()){
14191 this.hasFocus = false;
14195 this.cancelBtn.hide();
14196 this.trigger.show();
14199 this.tickableInputEl().dom.value = '';
14200 this.tickableInputEl().blur();
14205 Roo.get(document).un('mousedown', this.collapseIf, this);
14206 Roo.get(document).un('mousewheel', this.collapseIf, this);
14207 if (!this.editable) {
14208 Roo.get(document).un('keydown', this.listKeyPress, this);
14210 this.fireEvent('collapse', this);
14216 collapseIf : function(e){
14217 var in_combo = e.within(this.el);
14218 var in_list = e.within(this.list);
14219 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14221 if (in_combo || in_list || is_list) {
14222 //e.stopPropagation();
14227 this.onTickableFooterButtonClick(e, false, false);
14235 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14237 expand : function(){
14239 if(this.isExpanded() || !this.hasFocus){
14243 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14244 this.list.setWidth(lw);
14250 this.restrictHeight();
14254 this.tickItems = Roo.apply([], this.item);
14257 this.cancelBtn.show();
14258 this.trigger.hide();
14261 this.tickableInputEl().focus();
14266 Roo.get(document).on('mousedown', this.collapseIf, this);
14267 Roo.get(document).on('mousewheel', this.collapseIf, this);
14268 if (!this.editable) {
14269 Roo.get(document).on('keydown', this.listKeyPress, this);
14272 this.fireEvent('expand', this);
14276 // Implements the default empty TriggerField.onTriggerClick function
14277 onTriggerClick : function(e)
14279 Roo.log('trigger click');
14281 if(this.disabled || !this.triggerList){
14286 this.loadNext = false;
14288 if(this.isExpanded()){
14290 if (!this.blockFocus) {
14291 this.inputEl().focus();
14295 this.hasFocus = true;
14296 if(this.triggerAction == 'all') {
14297 this.doQuery(this.allQuery, true);
14299 this.doQuery(this.getRawValue());
14301 if (!this.blockFocus) {
14302 this.inputEl().focus();
14307 onTickableTriggerClick : function(e)
14314 this.loadNext = false;
14315 this.hasFocus = true;
14317 if(this.triggerAction == 'all') {
14318 this.doQuery(this.allQuery, true);
14320 this.doQuery(this.getRawValue());
14324 onSearchFieldClick : function(e)
14326 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14327 this.onTickableFooterButtonClick(e, false, false);
14331 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14336 this.loadNext = false;
14337 this.hasFocus = true;
14339 if(this.triggerAction == 'all') {
14340 this.doQuery(this.allQuery, true);
14342 this.doQuery(this.getRawValue());
14346 listKeyPress : function(e)
14348 //Roo.log('listkeypress');
14349 // scroll to first matching element based on key pres..
14350 if (e.isSpecialKey()) {
14353 var k = String.fromCharCode(e.getKey()).toUpperCase();
14356 var csel = this.view.getSelectedNodes();
14357 var cselitem = false;
14359 var ix = this.view.indexOf(csel[0]);
14360 cselitem = this.store.getAt(ix);
14361 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14367 this.store.each(function(v) {
14369 // start at existing selection.
14370 if (cselitem.id == v.id) {
14376 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14377 match = this.store.indexOf(v);
14383 if (match === false) {
14384 return true; // no more action?
14387 this.view.select(match);
14388 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14389 sn.scrollIntoView(sn.dom.parentNode, false);
14392 onViewScroll : function(e, t){
14394 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){
14398 this.hasQuery = true;
14400 this.loading = this.list.select('.loading', true).first();
14402 if(this.loading === null){
14403 this.list.createChild({
14405 cls: 'loading roo-select2-more-results roo-select2-active',
14406 html: 'Loading more results...'
14409 this.loading = this.list.select('.loading', true).first();
14411 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14413 this.loading.hide();
14416 this.loading.show();
14421 this.loadNext = true;
14423 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14428 addItem : function(o)
14430 var dv = ''; // display value
14432 if (this.displayField) {
14433 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14435 // this is an error condition!!!
14436 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14443 var choice = this.choices.createChild({
14445 cls: 'roo-select2-search-choice',
14454 cls: 'roo-select2-search-choice-close fa fa-times',
14459 }, this.searchField);
14461 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14463 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14471 this.inputEl().dom.value = '';
14476 onRemoveItem : function(e, _self, o)
14478 e.preventDefault();
14480 this.lastItem = Roo.apply([], this.item);
14482 var index = this.item.indexOf(o.data) * 1;
14485 Roo.log('not this item?!');
14489 this.item.splice(index, 1);
14494 this.fireEvent('remove', this, e);
14500 syncValue : function()
14502 if(!this.item.length){
14509 Roo.each(this.item, function(i){
14510 if(_this.valueField){
14511 value.push(i[_this.valueField]);
14518 this.value = value.join(',');
14520 if(this.hiddenField){
14521 this.hiddenField.dom.value = this.value;
14524 this.store.fireEvent("datachanged", this.store);
14529 clearItem : function()
14531 if(!this.multiple){
14537 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14545 if(this.tickable && !Roo.isTouch){
14546 this.view.refresh();
14550 inputEl: function ()
14552 if(Roo.isIOS && this.useNativeIOS){
14553 return this.el.select('select.roo-ios-select', true).first();
14556 if(Roo.isTouch && this.mobileTouchView){
14557 return this.el.select('input.form-control',true).first();
14561 return this.searchField;
14564 return this.el.select('input.form-control',true).first();
14567 onTickableFooterButtonClick : function(e, btn, el)
14569 e.preventDefault();
14571 this.lastItem = Roo.apply([], this.item);
14573 if(btn && btn.name == 'cancel'){
14574 this.tickItems = Roo.apply([], this.item);
14583 Roo.each(this.tickItems, function(o){
14591 validate : function()
14593 var v = this.getRawValue();
14596 v = this.getValue();
14599 if(this.disabled || this.allowBlank || v.length){
14604 this.markInvalid();
14608 tickableInputEl : function()
14610 if(!this.tickable || !this.editable){
14611 return this.inputEl();
14614 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14618 getAutoCreateTouchView : function()
14623 cls: 'form-group' //input-group
14629 type : this.inputType,
14630 cls : 'form-control x-combo-noedit',
14631 autocomplete: 'new-password',
14632 placeholder : this.placeholder || '',
14637 input.name = this.name;
14641 input.cls += ' input-' + this.size;
14644 if (this.disabled) {
14645 input.disabled = true;
14656 inputblock.cls += ' input-group';
14658 inputblock.cn.unshift({
14660 cls : 'input-group-addon',
14665 if(this.removable && !this.multiple){
14666 inputblock.cls += ' roo-removable';
14668 inputblock.cn.push({
14671 cls : 'roo-combo-removable-btn close'
14675 if(this.hasFeedback && !this.allowBlank){
14677 inputblock.cls += ' has-feedback';
14679 inputblock.cn.push({
14681 cls: 'glyphicon form-control-feedback'
14688 inputblock.cls += (this.before) ? '' : ' input-group';
14690 inputblock.cn.push({
14692 cls : 'input-group-addon',
14703 cls: 'form-hidden-field'
14717 cls: 'form-hidden-field'
14721 cls: 'roo-select2-choices',
14725 cls: 'roo-select2-search-field',
14738 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14744 if(!this.multiple && this.showToggleBtn){
14751 if (this.caret != false) {
14754 cls: 'fa fa-' + this.caret
14761 cls : 'input-group-addon btn dropdown-toggle',
14766 cls: 'combobox-clear',
14780 combobox.cls += ' roo-select2-container-multi';
14783 var align = this.labelAlign || this.parentLabelAlign();
14785 if (align ==='left' && this.fieldLabel.length) {
14790 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14791 tooltip : 'This field is required'
14795 cls : 'control-label',
14796 html : this.fieldLabel
14807 var labelCfg = cfg.cn[1];
14808 var contentCfg = cfg.cn[2];
14811 if(this.indicatorpos == 'right'){
14816 cls : 'control-label',
14820 html : this.fieldLabel
14824 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14825 tooltip : 'This field is required'
14838 labelCfg = cfg.cn[0];
14839 contentCfg = cfg.cn[1];
14844 if(this.labelWidth > 12){
14845 labelCfg.style = "width: " + this.labelWidth + 'px';
14848 if(this.labelWidth < 13 && this.labelmd == 0){
14849 this.labelmd = this.labelWidth;
14852 if(this.labellg > 0){
14853 labelCfg.cls += ' col-lg-' + this.labellg;
14854 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14857 if(this.labelmd > 0){
14858 labelCfg.cls += ' col-md-' + this.labelmd;
14859 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14862 if(this.labelsm > 0){
14863 labelCfg.cls += ' col-sm-' + this.labelsm;
14864 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14867 if(this.labelxs > 0){
14868 labelCfg.cls += ' col-xs-' + this.labelxs;
14869 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14873 } else if ( this.fieldLabel.length) {
14877 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14878 tooltip : 'This field is required'
14882 cls : 'control-label',
14883 html : this.fieldLabel
14894 if(this.indicatorpos == 'right'){
14898 cls : 'control-label',
14899 html : this.fieldLabel,
14903 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14904 tooltip : 'This field is required'
14921 var settings = this;
14923 ['xs','sm','md','lg'].map(function(size){
14924 if (settings[size]) {
14925 cfg.cls += ' col-' + size + '-' + settings[size];
14932 initTouchView : function()
14934 this.renderTouchView();
14936 this.touchViewEl.on('scroll', function(){
14937 this.el.dom.scrollTop = 0;
14940 this.originalValue = this.getValue();
14942 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14944 this.inputEl().on("click", this.showTouchView, this);
14945 if (this.triggerEl) {
14946 this.triggerEl.on("click", this.showTouchView, this);
14950 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14951 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14953 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14955 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14956 this.store.on('load', this.onTouchViewLoad, this);
14957 this.store.on('loadexception', this.onTouchViewLoadException, this);
14959 if(this.hiddenName){
14961 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14963 this.hiddenField.dom.value =
14964 this.hiddenValue !== undefined ? this.hiddenValue :
14965 this.value !== undefined ? this.value : '';
14967 this.el.dom.removeAttribute('name');
14968 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14972 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14973 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14976 if(this.removable && !this.multiple){
14977 var close = this.closeTriggerEl();
14979 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14980 close.on('click', this.removeBtnClick, this, close);
14984 * fix the bug in Safari iOS8
14986 this.inputEl().on("focus", function(e){
14987 document.activeElement.blur();
14995 renderTouchView : function()
14997 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14998 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15000 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15001 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15003 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15004 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15005 this.touchViewBodyEl.setStyle('overflow', 'auto');
15007 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15008 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15010 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15011 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15015 showTouchView : function()
15021 this.touchViewHeaderEl.hide();
15023 if(this.modalTitle.length){
15024 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15025 this.touchViewHeaderEl.show();
15028 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15029 this.touchViewEl.show();
15031 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15033 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15034 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15036 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15038 if(this.modalTitle.length){
15039 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15042 this.touchViewBodyEl.setHeight(bodyHeight);
15046 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15048 this.touchViewEl.addClass('in');
15051 this.doTouchViewQuery();
15055 hideTouchView : function()
15057 this.touchViewEl.removeClass('in');
15061 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15063 this.touchViewEl.setStyle('display', 'none');
15068 setTouchViewValue : function()
15075 Roo.each(this.tickItems, function(o){
15080 this.hideTouchView();
15083 doTouchViewQuery : function()
15092 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15096 if(!this.alwaysQuery || this.mode == 'local'){
15097 this.onTouchViewLoad();
15104 onTouchViewBeforeLoad : function(combo,opts)
15110 onTouchViewLoad : function()
15112 if(this.store.getCount() < 1){
15113 this.onTouchViewEmptyResults();
15117 this.clearTouchView();
15119 var rawValue = this.getRawValue();
15121 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15123 this.tickItems = [];
15125 this.store.data.each(function(d, rowIndex){
15126 var row = this.touchViewListGroup.createChild(template);
15128 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15129 row.addClass(d.data.cls);
15132 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15135 html : d.data[this.displayField]
15138 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15139 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15142 row.removeClass('selected');
15143 if(!this.multiple && this.valueField &&
15144 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15147 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15148 row.addClass('selected');
15151 if(this.multiple && this.valueField &&
15152 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15156 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15157 this.tickItems.push(d.data);
15160 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15164 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15166 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15168 if(this.modalTitle.length){
15169 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15172 var listHeight = this.touchViewListGroup.getHeight();
15176 if(firstChecked && listHeight > bodyHeight){
15177 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15182 onTouchViewLoadException : function()
15184 this.hideTouchView();
15187 onTouchViewEmptyResults : function()
15189 this.clearTouchView();
15191 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15193 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15197 clearTouchView : function()
15199 this.touchViewListGroup.dom.innerHTML = '';
15202 onTouchViewClick : function(e, el, o)
15204 e.preventDefault();
15207 var rowIndex = o.rowIndex;
15209 var r = this.store.getAt(rowIndex);
15211 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15213 if(!this.multiple){
15214 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15215 c.dom.removeAttribute('checked');
15218 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15220 this.setFromData(r.data);
15222 var close = this.closeTriggerEl();
15228 this.hideTouchView();
15230 this.fireEvent('select', this, r, rowIndex);
15235 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15236 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15237 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15241 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15242 this.addItem(r.data);
15243 this.tickItems.push(r.data);
15247 getAutoCreateNativeIOS : function()
15250 cls: 'form-group' //input-group,
15255 cls : 'roo-ios-select'
15259 combobox.name = this.name;
15262 if (this.disabled) {
15263 combobox.disabled = true;
15266 var settings = this;
15268 ['xs','sm','md','lg'].map(function(size){
15269 if (settings[size]) {
15270 cfg.cls += ' col-' + size + '-' + settings[size];
15280 initIOSView : function()
15282 this.store.on('load', this.onIOSViewLoad, this);
15287 onIOSViewLoad : function()
15289 if(this.store.getCount() < 1){
15293 this.clearIOSView();
15295 if(this.allowBlank) {
15297 var default_text = '-- SELECT --';
15299 if(this.placeholder.length){
15300 default_text = this.placeholder;
15303 if(this.emptyTitle.length){
15304 default_text += ' - ' + this.emptyTitle + ' -';
15307 var opt = this.inputEl().createChild({
15310 html : default_text
15314 o[this.valueField] = 0;
15315 o[this.displayField] = default_text;
15317 this.ios_options.push({
15324 this.store.data.each(function(d, rowIndex){
15328 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15329 html = d.data[this.displayField];
15334 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15335 value = d.data[this.valueField];
15344 if(this.value == d.data[this.valueField]){
15345 option['selected'] = true;
15348 var opt = this.inputEl().createChild(option);
15350 this.ios_options.push({
15357 this.inputEl().on('change', function(){
15358 this.fireEvent('select', this);
15363 clearIOSView: function()
15365 this.inputEl().dom.innerHTML = '';
15367 this.ios_options = [];
15370 setIOSValue: function(v)
15374 if(!this.ios_options){
15378 Roo.each(this.ios_options, function(opts){
15380 opts.el.dom.removeAttribute('selected');
15382 if(opts.data[this.valueField] != v){
15386 opts.el.dom.setAttribute('selected', true);
15392 * @cfg {Boolean} grow
15396 * @cfg {Number} growMin
15400 * @cfg {Number} growMax
15409 Roo.apply(Roo.bootstrap.ComboBox, {
15413 cls: 'modal-header',
15435 cls: 'list-group-item',
15439 cls: 'roo-combobox-list-group-item-value'
15443 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15457 listItemCheckbox : {
15459 cls: 'list-group-item',
15463 cls: 'roo-combobox-list-group-item-value'
15467 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15483 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15488 cls: 'modal-footer',
15496 cls: 'col-xs-6 text-left',
15499 cls: 'btn btn-danger roo-touch-view-cancel',
15505 cls: 'col-xs-6 text-right',
15508 cls: 'btn btn-success roo-touch-view-ok',
15519 Roo.apply(Roo.bootstrap.ComboBox, {
15521 touchViewTemplate : {
15523 cls: 'modal fade roo-combobox-touch-view',
15527 cls: 'modal-dialog',
15528 style : 'position:fixed', // we have to fix position....
15532 cls: 'modal-content',
15534 Roo.bootstrap.ComboBox.header,
15535 Roo.bootstrap.ComboBox.body,
15536 Roo.bootstrap.ComboBox.footer
15545 * Ext JS Library 1.1.1
15546 * Copyright(c) 2006-2007, Ext JS, LLC.
15548 * Originally Released Under LGPL - original licence link has changed is not relivant.
15551 * <script type="text/javascript">
15556 * @extends Roo.util.Observable
15557 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15558 * This class also supports single and multi selection modes. <br>
15559 * Create a data model bound view:
15561 var store = new Roo.data.Store(...);
15563 var view = new Roo.View({
15565 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15567 singleSelect: true,
15568 selectedClass: "ydataview-selected",
15572 // listen for node click?
15573 view.on("click", function(vw, index, node, e){
15574 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15578 dataModel.load("foobar.xml");
15580 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15582 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15583 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15585 * Note: old style constructor is still suported (container, template, config)
15588 * Create a new View
15589 * @param {Object} config The config object
15592 Roo.View = function(config, depreciated_tpl, depreciated_config){
15594 this.parent = false;
15596 if (typeof(depreciated_tpl) == 'undefined') {
15597 // new way.. - universal constructor.
15598 Roo.apply(this, config);
15599 this.el = Roo.get(this.el);
15602 this.el = Roo.get(config);
15603 this.tpl = depreciated_tpl;
15604 Roo.apply(this, depreciated_config);
15606 this.wrapEl = this.el.wrap().wrap();
15607 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15610 if(typeof(this.tpl) == "string"){
15611 this.tpl = new Roo.Template(this.tpl);
15613 // support xtype ctors..
15614 this.tpl = new Roo.factory(this.tpl, Roo);
15618 this.tpl.compile();
15623 * @event beforeclick
15624 * Fires before a click is processed. Returns false to cancel the default action.
15625 * @param {Roo.View} this
15626 * @param {Number} index The index of the target node
15627 * @param {HTMLElement} node The target node
15628 * @param {Roo.EventObject} e The raw event object
15630 "beforeclick" : true,
15633 * Fires when a template node is clicked.
15634 * @param {Roo.View} this
15635 * @param {Number} index The index of the target node
15636 * @param {HTMLElement} node The target node
15637 * @param {Roo.EventObject} e The raw event object
15642 * Fires when a template node is double clicked.
15643 * @param {Roo.View} this
15644 * @param {Number} index The index of the target node
15645 * @param {HTMLElement} node The target node
15646 * @param {Roo.EventObject} e The raw event object
15650 * @event contextmenu
15651 * Fires when a template node is right clicked.
15652 * @param {Roo.View} this
15653 * @param {Number} index The index of the target node
15654 * @param {HTMLElement} node The target node
15655 * @param {Roo.EventObject} e The raw event object
15657 "contextmenu" : true,
15659 * @event selectionchange
15660 * Fires when the selected nodes change.
15661 * @param {Roo.View} this
15662 * @param {Array} selections Array of the selected nodes
15664 "selectionchange" : true,
15667 * @event beforeselect
15668 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15669 * @param {Roo.View} this
15670 * @param {HTMLElement} node The node to be selected
15671 * @param {Array} selections Array of currently selected nodes
15673 "beforeselect" : true,
15675 * @event preparedata
15676 * Fires on every row to render, to allow you to change the data.
15677 * @param {Roo.View} this
15678 * @param {Object} data to be rendered (change this)
15680 "preparedata" : true
15688 "click": this.onClick,
15689 "dblclick": this.onDblClick,
15690 "contextmenu": this.onContextMenu,
15694 this.selections = [];
15696 this.cmp = new Roo.CompositeElementLite([]);
15698 this.store = Roo.factory(this.store, Roo.data);
15699 this.setStore(this.store, true);
15702 if ( this.footer && this.footer.xtype) {
15704 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15706 this.footer.dataSource = this.store;
15707 this.footer.container = fctr;
15708 this.footer = Roo.factory(this.footer, Roo);
15709 fctr.insertFirst(this.el);
15711 // this is a bit insane - as the paging toolbar seems to detach the el..
15712 // dom.parentNode.parentNode.parentNode
15713 // they get detached?
15717 Roo.View.superclass.constructor.call(this);
15722 Roo.extend(Roo.View, Roo.util.Observable, {
15725 * @cfg {Roo.data.Store} store Data store to load data from.
15730 * @cfg {String|Roo.Element} el The container element.
15735 * @cfg {String|Roo.Template} tpl The template used by this View
15739 * @cfg {String} dataName the named area of the template to use as the data area
15740 * Works with domtemplates roo-name="name"
15744 * @cfg {String} selectedClass The css class to add to selected nodes
15746 selectedClass : "x-view-selected",
15748 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15753 * @cfg {String} text to display on mask (default Loading)
15757 * @cfg {Boolean} multiSelect Allow multiple selection
15759 multiSelect : false,
15761 * @cfg {Boolean} singleSelect Allow single selection
15763 singleSelect: false,
15766 * @cfg {Boolean} toggleSelect - selecting
15768 toggleSelect : false,
15771 * @cfg {Boolean} tickable - selecting
15776 * Returns the element this view is bound to.
15777 * @return {Roo.Element}
15779 getEl : function(){
15780 return this.wrapEl;
15786 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15788 refresh : function(){
15789 //Roo.log('refresh');
15792 // if we are using something like 'domtemplate', then
15793 // the what gets used is:
15794 // t.applySubtemplate(NAME, data, wrapping data..)
15795 // the outer template then get' applied with
15796 // the store 'extra data'
15797 // and the body get's added to the
15798 // roo-name="data" node?
15799 // <span class='roo-tpl-{name}'></span> ?????
15803 this.clearSelections();
15804 this.el.update("");
15806 var records = this.store.getRange();
15807 if(records.length < 1) {
15809 // is this valid?? = should it render a template??
15811 this.el.update(this.emptyText);
15815 if (this.dataName) {
15816 this.el.update(t.apply(this.store.meta)); //????
15817 el = this.el.child('.roo-tpl-' + this.dataName);
15820 for(var i = 0, len = records.length; i < len; i++){
15821 var data = this.prepareData(records[i].data, i, records[i]);
15822 this.fireEvent("preparedata", this, data, i, records[i]);
15824 var d = Roo.apply({}, data);
15827 Roo.apply(d, {'roo-id' : Roo.id()});
15831 Roo.each(this.parent.item, function(item){
15832 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15835 Roo.apply(d, {'roo-data-checked' : 'checked'});
15839 html[html.length] = Roo.util.Format.trim(
15841 t.applySubtemplate(this.dataName, d, this.store.meta) :
15848 el.update(html.join(""));
15849 this.nodes = el.dom.childNodes;
15850 this.updateIndexes(0);
15855 * Function to override to reformat the data that is sent to
15856 * the template for each node.
15857 * DEPRICATED - use the preparedata event handler.
15858 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15859 * a JSON object for an UpdateManager bound view).
15861 prepareData : function(data, index, record)
15863 this.fireEvent("preparedata", this, data, index, record);
15867 onUpdate : function(ds, record){
15868 // Roo.log('on update');
15869 this.clearSelections();
15870 var index = this.store.indexOf(record);
15871 var n = this.nodes[index];
15872 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15873 n.parentNode.removeChild(n);
15874 this.updateIndexes(index, index);
15880 onAdd : function(ds, records, index)
15882 //Roo.log(['on Add', ds, records, index] );
15883 this.clearSelections();
15884 if(this.nodes.length == 0){
15888 var n = this.nodes[index];
15889 for(var i = 0, len = records.length; i < len; i++){
15890 var d = this.prepareData(records[i].data, i, records[i]);
15892 this.tpl.insertBefore(n, d);
15895 this.tpl.append(this.el, d);
15898 this.updateIndexes(index);
15901 onRemove : function(ds, record, index){
15902 // Roo.log('onRemove');
15903 this.clearSelections();
15904 var el = this.dataName ?
15905 this.el.child('.roo-tpl-' + this.dataName) :
15908 el.dom.removeChild(this.nodes[index]);
15909 this.updateIndexes(index);
15913 * Refresh an individual node.
15914 * @param {Number} index
15916 refreshNode : function(index){
15917 this.onUpdate(this.store, this.store.getAt(index));
15920 updateIndexes : function(startIndex, endIndex){
15921 var ns = this.nodes;
15922 startIndex = startIndex || 0;
15923 endIndex = endIndex || ns.length - 1;
15924 for(var i = startIndex; i <= endIndex; i++){
15925 ns[i].nodeIndex = i;
15930 * Changes the data store this view uses and refresh the view.
15931 * @param {Store} store
15933 setStore : function(store, initial){
15934 if(!initial && this.store){
15935 this.store.un("datachanged", this.refresh);
15936 this.store.un("add", this.onAdd);
15937 this.store.un("remove", this.onRemove);
15938 this.store.un("update", this.onUpdate);
15939 this.store.un("clear", this.refresh);
15940 this.store.un("beforeload", this.onBeforeLoad);
15941 this.store.un("load", this.onLoad);
15942 this.store.un("loadexception", this.onLoad);
15946 store.on("datachanged", this.refresh, this);
15947 store.on("add", this.onAdd, this);
15948 store.on("remove", this.onRemove, this);
15949 store.on("update", this.onUpdate, this);
15950 store.on("clear", this.refresh, this);
15951 store.on("beforeload", this.onBeforeLoad, this);
15952 store.on("load", this.onLoad, this);
15953 store.on("loadexception", this.onLoad, this);
15961 * onbeforeLoad - masks the loading area.
15964 onBeforeLoad : function(store,opts)
15966 //Roo.log('onBeforeLoad');
15968 this.el.update("");
15970 this.el.mask(this.mask ? this.mask : "Loading" );
15972 onLoad : function ()
15979 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15980 * @param {HTMLElement} node
15981 * @return {HTMLElement} The template node
15983 findItemFromChild : function(node){
15984 var el = this.dataName ?
15985 this.el.child('.roo-tpl-' + this.dataName,true) :
15988 if(!node || node.parentNode == el){
15991 var p = node.parentNode;
15992 while(p && p != el){
15993 if(p.parentNode == el){
16002 onClick : function(e){
16003 var item = this.findItemFromChild(e.getTarget());
16005 var index = this.indexOf(item);
16006 if(this.onItemClick(item, index, e) !== false){
16007 this.fireEvent("click", this, index, item, e);
16010 this.clearSelections();
16015 onContextMenu : function(e){
16016 var item = this.findItemFromChild(e.getTarget());
16018 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16023 onDblClick : function(e){
16024 var item = this.findItemFromChild(e.getTarget());
16026 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16030 onItemClick : function(item, index, e)
16032 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16035 if (this.toggleSelect) {
16036 var m = this.isSelected(item) ? 'unselect' : 'select';
16039 _t[m](item, true, false);
16042 if(this.multiSelect || this.singleSelect){
16043 if(this.multiSelect && e.shiftKey && this.lastSelection){
16044 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16046 this.select(item, this.multiSelect && e.ctrlKey);
16047 this.lastSelection = item;
16050 if(!this.tickable){
16051 e.preventDefault();
16059 * Get the number of selected nodes.
16062 getSelectionCount : function(){
16063 return this.selections.length;
16067 * Get the currently selected nodes.
16068 * @return {Array} An array of HTMLElements
16070 getSelectedNodes : function(){
16071 return this.selections;
16075 * Get the indexes of the selected nodes.
16078 getSelectedIndexes : function(){
16079 var indexes = [], s = this.selections;
16080 for(var i = 0, len = s.length; i < len; i++){
16081 indexes.push(s[i].nodeIndex);
16087 * Clear all selections
16088 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16090 clearSelections : function(suppressEvent){
16091 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16092 this.cmp.elements = this.selections;
16093 this.cmp.removeClass(this.selectedClass);
16094 this.selections = [];
16095 if(!suppressEvent){
16096 this.fireEvent("selectionchange", this, this.selections);
16102 * Returns true if the passed node is selected
16103 * @param {HTMLElement/Number} node The node or node index
16104 * @return {Boolean}
16106 isSelected : function(node){
16107 var s = this.selections;
16111 node = this.getNode(node);
16112 return s.indexOf(node) !== -1;
16117 * @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
16118 * @param {Boolean} keepExisting (optional) true to keep existing selections
16119 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16121 select : function(nodeInfo, keepExisting, suppressEvent){
16122 if(nodeInfo instanceof Array){
16124 this.clearSelections(true);
16126 for(var i = 0, len = nodeInfo.length; i < len; i++){
16127 this.select(nodeInfo[i], true, true);
16131 var node = this.getNode(nodeInfo);
16132 if(!node || this.isSelected(node)){
16133 return; // already selected.
16136 this.clearSelections(true);
16139 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16140 Roo.fly(node).addClass(this.selectedClass);
16141 this.selections.push(node);
16142 if(!suppressEvent){
16143 this.fireEvent("selectionchange", this, this.selections);
16151 * @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
16152 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16153 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16155 unselect : function(nodeInfo, keepExisting, suppressEvent)
16157 if(nodeInfo instanceof Array){
16158 Roo.each(this.selections, function(s) {
16159 this.unselect(s, nodeInfo);
16163 var node = this.getNode(nodeInfo);
16164 if(!node || !this.isSelected(node)){
16165 //Roo.log("not selected");
16166 return; // not selected.
16170 Roo.each(this.selections, function(s) {
16172 Roo.fly(node).removeClass(this.selectedClass);
16179 this.selections= ns;
16180 this.fireEvent("selectionchange", this, this.selections);
16184 * Gets a template node.
16185 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16186 * @return {HTMLElement} The node or null if it wasn't found
16188 getNode : function(nodeInfo){
16189 if(typeof nodeInfo == "string"){
16190 return document.getElementById(nodeInfo);
16191 }else if(typeof nodeInfo == "number"){
16192 return this.nodes[nodeInfo];
16198 * Gets a range template nodes.
16199 * @param {Number} startIndex
16200 * @param {Number} endIndex
16201 * @return {Array} An array of nodes
16203 getNodes : function(start, end){
16204 var ns = this.nodes;
16205 start = start || 0;
16206 end = typeof end == "undefined" ? ns.length - 1 : end;
16209 for(var i = start; i <= end; i++){
16213 for(var i = start; i >= end; i--){
16221 * Finds the index of the passed node
16222 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16223 * @return {Number} The index of the node or -1
16225 indexOf : function(node){
16226 node = this.getNode(node);
16227 if(typeof node.nodeIndex == "number"){
16228 return node.nodeIndex;
16230 var ns = this.nodes;
16231 for(var i = 0, len = ns.length; i < len; i++){
16242 * based on jquery fullcalendar
16246 Roo.bootstrap = Roo.bootstrap || {};
16248 * @class Roo.bootstrap.Calendar
16249 * @extends Roo.bootstrap.Component
16250 * Bootstrap Calendar class
16251 * @cfg {Boolean} loadMask (true|false) default false
16252 * @cfg {Object} header generate the user specific header of the calendar, default false
16255 * Create a new Container
16256 * @param {Object} config The config object
16261 Roo.bootstrap.Calendar = function(config){
16262 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16266 * Fires when a date is selected
16267 * @param {DatePicker} this
16268 * @param {Date} date The selected date
16272 * @event monthchange
16273 * Fires when the displayed month changes
16274 * @param {DatePicker} this
16275 * @param {Date} date The selected month
16277 'monthchange': true,
16279 * @event evententer
16280 * Fires when mouse over an event
16281 * @param {Calendar} this
16282 * @param {event} Event
16284 'evententer': true,
16286 * @event eventleave
16287 * Fires when the mouse leaves an
16288 * @param {Calendar} this
16291 'eventleave': true,
16293 * @event eventclick
16294 * Fires when the mouse click an
16295 * @param {Calendar} this
16304 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16307 * @cfg {Number} startDay
16308 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16316 getAutoCreate : function(){
16319 var fc_button = function(name, corner, style, content ) {
16320 return Roo.apply({},{
16322 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16324 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16327 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16338 style : 'width:100%',
16345 cls : 'fc-header-left',
16347 fc_button('prev', 'left', 'arrow', '‹' ),
16348 fc_button('next', 'right', 'arrow', '›' ),
16349 { tag: 'span', cls: 'fc-header-space' },
16350 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16358 cls : 'fc-header-center',
16362 cls: 'fc-header-title',
16365 html : 'month / year'
16373 cls : 'fc-header-right',
16375 /* fc_button('month', 'left', '', 'month' ),
16376 fc_button('week', '', '', 'week' ),
16377 fc_button('day', 'right', '', 'day' )
16389 header = this.header;
16392 var cal_heads = function() {
16394 // fixme - handle this.
16396 for (var i =0; i < Date.dayNames.length; i++) {
16397 var d = Date.dayNames[i];
16400 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16401 html : d.substring(0,3)
16405 ret[0].cls += ' fc-first';
16406 ret[6].cls += ' fc-last';
16409 var cal_cell = function(n) {
16412 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16417 cls: 'fc-day-number',
16421 cls: 'fc-day-content',
16425 style: 'position: relative;' // height: 17px;
16437 var cal_rows = function() {
16440 for (var r = 0; r < 6; r++) {
16447 for (var i =0; i < Date.dayNames.length; i++) {
16448 var d = Date.dayNames[i];
16449 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16452 row.cn[0].cls+=' fc-first';
16453 row.cn[0].cn[0].style = 'min-height:90px';
16454 row.cn[6].cls+=' fc-last';
16458 ret[0].cls += ' fc-first';
16459 ret[4].cls += ' fc-prev-last';
16460 ret[5].cls += ' fc-last';
16467 cls: 'fc-border-separate',
16468 style : 'width:100%',
16476 cls : 'fc-first fc-last',
16494 cls : 'fc-content',
16495 style : "position: relative;",
16498 cls : 'fc-view fc-view-month fc-grid',
16499 style : 'position: relative',
16500 unselectable : 'on',
16503 cls : 'fc-event-container',
16504 style : 'position:absolute;z-index:8;top:0;left:0;'
16522 initEvents : function()
16525 throw "can not find store for calendar";
16531 style: "text-align:center",
16535 style: "background-color:white;width:50%;margin:250 auto",
16539 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16550 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16552 var size = this.el.select('.fc-content', true).first().getSize();
16553 this.maskEl.setSize(size.width, size.height);
16554 this.maskEl.enableDisplayMode("block");
16555 if(!this.loadMask){
16556 this.maskEl.hide();
16559 this.store = Roo.factory(this.store, Roo.data);
16560 this.store.on('load', this.onLoad, this);
16561 this.store.on('beforeload', this.onBeforeLoad, this);
16565 this.cells = this.el.select('.fc-day',true);
16566 //Roo.log(this.cells);
16567 this.textNodes = this.el.query('.fc-day-number');
16568 this.cells.addClassOnOver('fc-state-hover');
16570 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16571 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16572 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16573 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16575 this.on('monthchange', this.onMonthChange, this);
16577 this.update(new Date().clearTime());
16580 resize : function() {
16581 var sz = this.el.getSize();
16583 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16584 this.el.select('.fc-day-content div',true).setHeight(34);
16589 showPrevMonth : function(e){
16590 this.update(this.activeDate.add("mo", -1));
16592 showToday : function(e){
16593 this.update(new Date().clearTime());
16596 showNextMonth : function(e){
16597 this.update(this.activeDate.add("mo", 1));
16601 showPrevYear : function(){
16602 this.update(this.activeDate.add("y", -1));
16606 showNextYear : function(){
16607 this.update(this.activeDate.add("y", 1));
16612 update : function(date)
16614 var vd = this.activeDate;
16615 this.activeDate = date;
16616 // if(vd && this.el){
16617 // var t = date.getTime();
16618 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16619 // Roo.log('using add remove');
16621 // this.fireEvent('monthchange', this, date);
16623 // this.cells.removeClass("fc-state-highlight");
16624 // this.cells.each(function(c){
16625 // if(c.dateValue == t){
16626 // c.addClass("fc-state-highlight");
16627 // setTimeout(function(){
16628 // try{c.dom.firstChild.focus();}catch(e){}
16638 var days = date.getDaysInMonth();
16640 var firstOfMonth = date.getFirstDateOfMonth();
16641 var startingPos = firstOfMonth.getDay()-this.startDay;
16643 if(startingPos < this.startDay){
16647 var pm = date.add(Date.MONTH, -1);
16648 var prevStart = pm.getDaysInMonth()-startingPos;
16650 this.cells = this.el.select('.fc-day',true);
16651 this.textNodes = this.el.query('.fc-day-number');
16652 this.cells.addClassOnOver('fc-state-hover');
16654 var cells = this.cells.elements;
16655 var textEls = this.textNodes;
16657 Roo.each(cells, function(cell){
16658 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16661 days += startingPos;
16663 // convert everything to numbers so it's fast
16664 var day = 86400000;
16665 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16668 //Roo.log(prevStart);
16670 var today = new Date().clearTime().getTime();
16671 var sel = date.clearTime().getTime();
16672 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16673 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16674 var ddMatch = this.disabledDatesRE;
16675 var ddText = this.disabledDatesText;
16676 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16677 var ddaysText = this.disabledDaysText;
16678 var format = this.format;
16680 var setCellClass = function(cal, cell){
16684 //Roo.log('set Cell Class');
16686 var t = d.getTime();
16690 cell.dateValue = t;
16692 cell.className += " fc-today";
16693 cell.className += " fc-state-highlight";
16694 cell.title = cal.todayText;
16697 // disable highlight in other month..
16698 //cell.className += " fc-state-highlight";
16703 cell.className = " fc-state-disabled";
16704 cell.title = cal.minText;
16708 cell.className = " fc-state-disabled";
16709 cell.title = cal.maxText;
16713 if(ddays.indexOf(d.getDay()) != -1){
16714 cell.title = ddaysText;
16715 cell.className = " fc-state-disabled";
16718 if(ddMatch && format){
16719 var fvalue = d.dateFormat(format);
16720 if(ddMatch.test(fvalue)){
16721 cell.title = ddText.replace("%0", fvalue);
16722 cell.className = " fc-state-disabled";
16726 if (!cell.initialClassName) {
16727 cell.initialClassName = cell.dom.className;
16730 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16735 for(; i < startingPos; i++) {
16736 textEls[i].innerHTML = (++prevStart);
16737 d.setDate(d.getDate()+1);
16739 cells[i].className = "fc-past fc-other-month";
16740 setCellClass(this, cells[i]);
16745 for(; i < days; i++){
16746 intDay = i - startingPos + 1;
16747 textEls[i].innerHTML = (intDay);
16748 d.setDate(d.getDate()+1);
16750 cells[i].className = ''; // "x-date-active";
16751 setCellClass(this, cells[i]);
16755 for(; i < 42; i++) {
16756 textEls[i].innerHTML = (++extraDays);
16757 d.setDate(d.getDate()+1);
16759 cells[i].className = "fc-future fc-other-month";
16760 setCellClass(this, cells[i]);
16763 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16765 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16767 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16768 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16770 if(totalRows != 6){
16771 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16772 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16775 this.fireEvent('monthchange', this, date);
16779 if(!this.internalRender){
16780 var main = this.el.dom.firstChild;
16781 var w = main.offsetWidth;
16782 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16783 Roo.fly(main).setWidth(w);
16784 this.internalRender = true;
16785 // opera does not respect the auto grow header center column
16786 // then, after it gets a width opera refuses to recalculate
16787 // without a second pass
16788 if(Roo.isOpera && !this.secondPass){
16789 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16790 this.secondPass = true;
16791 this.update.defer(10, this, [date]);
16798 findCell : function(dt) {
16799 dt = dt.clearTime().getTime();
16801 this.cells.each(function(c){
16802 //Roo.log("check " +c.dateValue + '?=' + dt);
16803 if(c.dateValue == dt){
16813 findCells : function(ev) {
16814 var s = ev.start.clone().clearTime().getTime();
16816 var e= ev.end.clone().clearTime().getTime();
16819 this.cells.each(function(c){
16820 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16822 if(c.dateValue > e){
16825 if(c.dateValue < s){
16834 // findBestRow: function(cells)
16838 // for (var i =0 ; i < cells.length;i++) {
16839 // ret = Math.max(cells[i].rows || 0,ret);
16846 addItem : function(ev)
16848 // look for vertical location slot in
16849 var cells = this.findCells(ev);
16851 // ev.row = this.findBestRow(cells);
16853 // work out the location.
16857 for(var i =0; i < cells.length; i++) {
16859 cells[i].row = cells[0].row;
16862 cells[i].row = cells[i].row + 1;
16872 if (crow.start.getY() == cells[i].getY()) {
16874 crow.end = cells[i];
16891 cells[0].events.push(ev);
16893 this.calevents.push(ev);
16896 clearEvents: function() {
16898 if(!this.calevents){
16902 Roo.each(this.cells.elements, function(c){
16908 Roo.each(this.calevents, function(e) {
16909 Roo.each(e.els, function(el) {
16910 el.un('mouseenter' ,this.onEventEnter, this);
16911 el.un('mouseleave' ,this.onEventLeave, this);
16916 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16922 renderEvents: function()
16926 this.cells.each(function(c) {
16935 if(c.row != c.events.length){
16936 r = 4 - (4 - (c.row - c.events.length));
16939 c.events = ev.slice(0, r);
16940 c.more = ev.slice(r);
16942 if(c.more.length && c.more.length == 1){
16943 c.events.push(c.more.pop());
16946 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16950 this.cells.each(function(c) {
16952 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16955 for (var e = 0; e < c.events.length; e++){
16956 var ev = c.events[e];
16957 var rows = ev.rows;
16959 for(var i = 0; i < rows.length; i++) {
16961 // how many rows should it span..
16964 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16965 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16967 unselectable : "on",
16970 cls: 'fc-event-inner',
16974 // cls: 'fc-event-time',
16975 // html : cells.length > 1 ? '' : ev.time
16979 cls: 'fc-event-title',
16980 html : String.format('{0}', ev.title)
16987 cls: 'ui-resizable-handle ui-resizable-e',
16988 html : '  '
16995 cfg.cls += ' fc-event-start';
16997 if ((i+1) == rows.length) {
16998 cfg.cls += ' fc-event-end';
17001 var ctr = _this.el.select('.fc-event-container',true).first();
17002 var cg = ctr.createChild(cfg);
17004 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17005 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17007 var r = (c.more.length) ? 1 : 0;
17008 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17009 cg.setWidth(ebox.right - sbox.x -2);
17011 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17012 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17013 cg.on('click', _this.onEventClick, _this, ev);
17024 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17025 style : 'position: absolute',
17026 unselectable : "on",
17029 cls: 'fc-event-inner',
17033 cls: 'fc-event-title',
17041 cls: 'ui-resizable-handle ui-resizable-e',
17042 html : '  '
17048 var ctr = _this.el.select('.fc-event-container',true).first();
17049 var cg = ctr.createChild(cfg);
17051 var sbox = c.select('.fc-day-content',true).first().getBox();
17052 var ebox = c.select('.fc-day-content',true).first().getBox();
17054 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17055 cg.setWidth(ebox.right - sbox.x -2);
17057 cg.on('click', _this.onMoreEventClick, _this, c.more);
17067 onEventEnter: function (e, el,event,d) {
17068 this.fireEvent('evententer', this, el, event);
17071 onEventLeave: function (e, el,event,d) {
17072 this.fireEvent('eventleave', this, el, event);
17075 onEventClick: function (e, el,event,d) {
17076 this.fireEvent('eventclick', this, el, event);
17079 onMonthChange: function () {
17083 onMoreEventClick: function(e, el, more)
17087 this.calpopover.placement = 'right';
17088 this.calpopover.setTitle('More');
17090 this.calpopover.setContent('');
17092 var ctr = this.calpopover.el.select('.popover-content', true).first();
17094 Roo.each(more, function(m){
17096 cls : 'fc-event-hori fc-event-draggable',
17099 var cg = ctr.createChild(cfg);
17101 cg.on('click', _this.onEventClick, _this, m);
17104 this.calpopover.show(el);
17109 onLoad: function ()
17111 this.calevents = [];
17114 if(this.store.getCount() > 0){
17115 this.store.data.each(function(d){
17118 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17119 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17120 time : d.data.start_time,
17121 title : d.data.title,
17122 description : d.data.description,
17123 venue : d.data.venue
17128 this.renderEvents();
17130 if(this.calevents.length && this.loadMask){
17131 this.maskEl.hide();
17135 onBeforeLoad: function()
17137 this.clearEvents();
17139 this.maskEl.show();
17153 * @class Roo.bootstrap.Popover
17154 * @extends Roo.bootstrap.Component
17155 * Bootstrap Popover class
17156 * @cfg {String} html contents of the popover (or false to use children..)
17157 * @cfg {String} title of popover (or false to hide)
17158 * @cfg {String} placement how it is placed
17159 * @cfg {String} trigger click || hover (or false to trigger manually)
17160 * @cfg {String} over what (parent or false to trigger manually.)
17161 * @cfg {Number} delay - delay before showing
17164 * Create a new Popover
17165 * @param {Object} config The config object
17168 Roo.bootstrap.Popover = function(config){
17169 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17175 * After the popover show
17177 * @param {Roo.bootstrap.Popover} this
17182 * After the popover hide
17184 * @param {Roo.bootstrap.Popover} this
17190 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17192 title: 'Fill in a title',
17195 placement : 'right',
17196 trigger : 'hover', // hover
17202 can_build_overlaid : false,
17204 getChildContainer : function()
17206 return this.el.select('.popover-content',true).first();
17209 getAutoCreate : function(){
17212 cls : 'popover roo-dynamic',
17213 style: 'display:block',
17219 cls : 'popover-inner',
17223 cls: 'popover-title',
17227 cls : 'popover-content',
17238 setTitle: function(str)
17241 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17243 setContent: function(str)
17246 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17248 // as it get's added to the bottom of the page.
17249 onRender : function(ct, position)
17251 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17253 var cfg = Roo.apply({}, this.getAutoCreate());
17257 cfg.cls += ' ' + this.cls;
17260 cfg.style = this.style;
17262 //Roo.log("adding to ");
17263 this.el = Roo.get(document.body).createChild(cfg, position);
17264 // Roo.log(this.el);
17269 initEvents : function()
17271 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17272 this.el.enableDisplayMode('block');
17274 if (this.over === false) {
17277 if (this.triggers === false) {
17280 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17281 var triggers = this.trigger ? this.trigger.split(' ') : [];
17282 Roo.each(triggers, function(trigger) {
17284 if (trigger == 'click') {
17285 on_el.on('click', this.toggle, this);
17286 } else if (trigger != 'manual') {
17287 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17288 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17290 on_el.on(eventIn ,this.enter, this);
17291 on_el.on(eventOut, this.leave, this);
17302 toggle : function () {
17303 this.hoverState == 'in' ? this.leave() : this.enter();
17306 enter : function () {
17308 clearTimeout(this.timeout);
17310 this.hoverState = 'in';
17312 if (!this.delay || !this.delay.show) {
17317 this.timeout = setTimeout(function () {
17318 if (_t.hoverState == 'in') {
17321 }, this.delay.show)
17324 leave : function() {
17325 clearTimeout(this.timeout);
17327 this.hoverState = 'out';
17329 if (!this.delay || !this.delay.hide) {
17334 this.timeout = setTimeout(function () {
17335 if (_t.hoverState == 'out') {
17338 }, this.delay.hide)
17341 show : function (on_el)
17344 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17348 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17349 if (this.html !== false) {
17350 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17352 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17353 if (!this.title.length) {
17354 this.el.select('.popover-title',true).hide();
17357 var placement = typeof this.placement == 'function' ?
17358 this.placement.call(this, this.el, on_el) :
17361 var autoToken = /\s?auto?\s?/i;
17362 var autoPlace = autoToken.test(placement);
17364 placement = placement.replace(autoToken, '') || 'top';
17368 //this.el.setXY([0,0]);
17370 this.el.dom.style.display='block';
17371 this.el.addClass(placement);
17373 //this.el.appendTo(on_el);
17375 var p = this.getPosition();
17376 var box = this.el.getBox();
17381 var align = Roo.bootstrap.Popover.alignment[placement];
17384 this.el.alignTo(on_el, align[0],align[1]);
17385 //var arrow = this.el.select('.arrow',true).first();
17386 //arrow.set(align[2],
17388 this.el.addClass('in');
17391 if (this.el.hasClass('fade')) {
17395 this.hoverState = 'in';
17397 this.fireEvent('show', this);
17402 this.el.setXY([0,0]);
17403 this.el.removeClass('in');
17405 this.hoverState = null;
17407 this.fireEvent('hide', this);
17412 Roo.bootstrap.Popover.alignment = {
17413 'left' : ['r-l', [-10,0], 'right'],
17414 'right' : ['l-r', [10,0], 'left'],
17415 'bottom' : ['t-b', [0,10], 'top'],
17416 'top' : [ 'b-t', [0,-10], 'bottom']
17427 * @class Roo.bootstrap.Progress
17428 * @extends Roo.bootstrap.Component
17429 * Bootstrap Progress class
17430 * @cfg {Boolean} striped striped of the progress bar
17431 * @cfg {Boolean} active animated of the progress bar
17435 * Create a new Progress
17436 * @param {Object} config The config object
17439 Roo.bootstrap.Progress = function(config){
17440 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17443 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17448 getAutoCreate : function(){
17456 cfg.cls += ' progress-striped';
17460 cfg.cls += ' active';
17479 * @class Roo.bootstrap.ProgressBar
17480 * @extends Roo.bootstrap.Component
17481 * Bootstrap ProgressBar class
17482 * @cfg {Number} aria_valuenow aria-value now
17483 * @cfg {Number} aria_valuemin aria-value min
17484 * @cfg {Number} aria_valuemax aria-value max
17485 * @cfg {String} label label for the progress bar
17486 * @cfg {String} panel (success | info | warning | danger )
17487 * @cfg {String} role role of the progress bar
17488 * @cfg {String} sr_only text
17492 * Create a new ProgressBar
17493 * @param {Object} config The config object
17496 Roo.bootstrap.ProgressBar = function(config){
17497 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17500 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17504 aria_valuemax : 100,
17510 getAutoCreate : function()
17515 cls: 'progress-bar',
17516 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17528 cfg.role = this.role;
17531 if(this.aria_valuenow){
17532 cfg['aria-valuenow'] = this.aria_valuenow;
17535 if(this.aria_valuemin){
17536 cfg['aria-valuemin'] = this.aria_valuemin;
17539 if(this.aria_valuemax){
17540 cfg['aria-valuemax'] = this.aria_valuemax;
17543 if(this.label && !this.sr_only){
17544 cfg.html = this.label;
17548 cfg.cls += ' progress-bar-' + this.panel;
17554 update : function(aria_valuenow)
17556 this.aria_valuenow = aria_valuenow;
17558 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17573 * @class Roo.bootstrap.TabGroup
17574 * @extends Roo.bootstrap.Column
17575 * Bootstrap Column class
17576 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17577 * @cfg {Boolean} carousel true to make the group behave like a carousel
17578 * @cfg {Boolean} bullets show bullets for the panels
17579 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17580 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17581 * @cfg {Boolean} showarrow (true|false) show arrow default true
17584 * Create a new TabGroup
17585 * @param {Object} config The config object
17588 Roo.bootstrap.TabGroup = function(config){
17589 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17591 this.navId = Roo.id();
17594 Roo.bootstrap.TabGroup.register(this);
17598 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17601 transition : false,
17606 slideOnTouch : false,
17609 getAutoCreate : function()
17611 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17613 cfg.cls += ' tab-content';
17615 if (this.carousel) {
17616 cfg.cls += ' carousel slide';
17619 cls : 'carousel-inner',
17623 if(this.bullets && !Roo.isTouch){
17626 cls : 'carousel-bullets',
17630 if(this.bullets_cls){
17631 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17638 cfg.cn[0].cn.push(bullets);
17641 if(this.showarrow){
17642 cfg.cn[0].cn.push({
17644 class : 'carousel-arrow',
17648 class : 'carousel-prev',
17652 class : 'fa fa-chevron-left'
17658 class : 'carousel-next',
17662 class : 'fa fa-chevron-right'
17675 initEvents: function()
17677 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17678 // this.el.on("touchstart", this.onTouchStart, this);
17681 if(this.autoslide){
17684 this.slideFn = window.setInterval(function() {
17685 _this.showPanelNext();
17689 if(this.showarrow){
17690 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17691 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17697 // onTouchStart : function(e, el, o)
17699 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17703 // this.showPanelNext();
17707 getChildContainer : function()
17709 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17713 * register a Navigation item
17714 * @param {Roo.bootstrap.NavItem} the navitem to add
17716 register : function(item)
17718 this.tabs.push( item);
17719 item.navId = this.navId; // not really needed..
17724 getActivePanel : function()
17727 Roo.each(this.tabs, function(t) {
17737 getPanelByName : function(n)
17740 Roo.each(this.tabs, function(t) {
17741 if (t.tabId == n) {
17749 indexOfPanel : function(p)
17752 Roo.each(this.tabs, function(t,i) {
17753 if (t.tabId == p.tabId) {
17762 * show a specific panel
17763 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17764 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17766 showPanel : function (pan)
17768 if(this.transition || typeof(pan) == 'undefined'){
17769 Roo.log("waiting for the transitionend");
17773 if (typeof(pan) == 'number') {
17774 pan = this.tabs[pan];
17777 if (typeof(pan) == 'string') {
17778 pan = this.getPanelByName(pan);
17781 var cur = this.getActivePanel();
17784 Roo.log('pan or acitve pan is undefined');
17788 if (pan.tabId == this.getActivePanel().tabId) {
17792 if (false === cur.fireEvent('beforedeactivate')) {
17796 if(this.bullets > 0 && !Roo.isTouch){
17797 this.setActiveBullet(this.indexOfPanel(pan));
17800 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17802 this.transition = true;
17803 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17804 var lr = dir == 'next' ? 'left' : 'right';
17805 pan.el.addClass(dir); // or prev
17806 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17807 cur.el.addClass(lr); // or right
17808 pan.el.addClass(lr);
17811 cur.el.on('transitionend', function() {
17812 Roo.log("trans end?");
17814 pan.el.removeClass([lr,dir]);
17815 pan.setActive(true);
17817 cur.el.removeClass([lr]);
17818 cur.setActive(false);
17820 _this.transition = false;
17822 }, this, { single: true } );
17827 cur.setActive(false);
17828 pan.setActive(true);
17833 showPanelNext : function()
17835 var i = this.indexOfPanel(this.getActivePanel());
17837 if (i >= this.tabs.length - 1 && !this.autoslide) {
17841 if (i >= this.tabs.length - 1 && this.autoslide) {
17845 this.showPanel(this.tabs[i+1]);
17848 showPanelPrev : function()
17850 var i = this.indexOfPanel(this.getActivePanel());
17852 if (i < 1 && !this.autoslide) {
17856 if (i < 1 && this.autoslide) {
17857 i = this.tabs.length;
17860 this.showPanel(this.tabs[i-1]);
17864 addBullet: function()
17866 if(!this.bullets || Roo.isTouch){
17869 var ctr = this.el.select('.carousel-bullets',true).first();
17870 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17871 var bullet = ctr.createChild({
17872 cls : 'bullet bullet-' + i
17873 },ctr.dom.lastChild);
17878 bullet.on('click', (function(e, el, o, ii, t){
17880 e.preventDefault();
17882 this.showPanel(ii);
17884 if(this.autoslide && this.slideFn){
17885 clearInterval(this.slideFn);
17886 this.slideFn = window.setInterval(function() {
17887 _this.showPanelNext();
17891 }).createDelegate(this, [i, bullet], true));
17896 setActiveBullet : function(i)
17902 Roo.each(this.el.select('.bullet', true).elements, function(el){
17903 el.removeClass('selected');
17906 var bullet = this.el.select('.bullet-' + i, true).first();
17912 bullet.addClass('selected');
17923 Roo.apply(Roo.bootstrap.TabGroup, {
17927 * register a Navigation Group
17928 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17930 register : function(navgrp)
17932 this.groups[navgrp.navId] = navgrp;
17936 * fetch a Navigation Group based on the navigation ID
17937 * if one does not exist , it will get created.
17938 * @param {string} the navgroup to add
17939 * @returns {Roo.bootstrap.NavGroup} the navgroup
17941 get: function(navId) {
17942 if (typeof(this.groups[navId]) == 'undefined') {
17943 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17945 return this.groups[navId] ;
17960 * @class Roo.bootstrap.TabPanel
17961 * @extends Roo.bootstrap.Component
17962 * Bootstrap TabPanel class
17963 * @cfg {Boolean} active panel active
17964 * @cfg {String} html panel content
17965 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17966 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17967 * @cfg {String} href click to link..
17971 * Create a new TabPanel
17972 * @param {Object} config The config object
17975 Roo.bootstrap.TabPanel = function(config){
17976 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17980 * Fires when the active status changes
17981 * @param {Roo.bootstrap.TabPanel} this
17982 * @param {Boolean} state the new state
17987 * @event beforedeactivate
17988 * Fires before a tab is de-activated - can be used to do validation on a form.
17989 * @param {Roo.bootstrap.TabPanel} this
17990 * @return {Boolean} false if there is an error
17993 'beforedeactivate': true
17996 this.tabId = this.tabId || Roo.id();
18000 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18008 getAutoCreate : function(){
18011 // item is needed for carousel - not sure if it has any effect otherwise
18012 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18013 html: this.html || ''
18017 cfg.cls += ' active';
18021 cfg.tabId = this.tabId;
18028 initEvents: function()
18030 var p = this.parent();
18032 this.navId = this.navId || p.navId;
18034 if (typeof(this.navId) != 'undefined') {
18035 // not really needed.. but just in case.. parent should be a NavGroup.
18036 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18040 var i = tg.tabs.length - 1;
18042 if(this.active && tg.bullets > 0 && i < tg.bullets){
18043 tg.setActiveBullet(i);
18047 this.el.on('click', this.onClick, this);
18050 this.el.on("touchstart", this.onTouchStart, this);
18051 this.el.on("touchmove", this.onTouchMove, this);
18052 this.el.on("touchend", this.onTouchEnd, this);
18057 onRender : function(ct, position)
18059 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18062 setActive : function(state)
18064 Roo.log("panel - set active " + this.tabId + "=" + state);
18066 this.active = state;
18068 this.el.removeClass('active');
18070 } else if (!this.el.hasClass('active')) {
18071 this.el.addClass('active');
18074 this.fireEvent('changed', this, state);
18077 onClick : function(e)
18079 e.preventDefault();
18081 if(!this.href.length){
18085 window.location.href = this.href;
18094 onTouchStart : function(e)
18096 this.swiping = false;
18098 this.startX = e.browserEvent.touches[0].clientX;
18099 this.startY = e.browserEvent.touches[0].clientY;
18102 onTouchMove : function(e)
18104 this.swiping = true;
18106 this.endX = e.browserEvent.touches[0].clientX;
18107 this.endY = e.browserEvent.touches[0].clientY;
18110 onTouchEnd : function(e)
18117 var tabGroup = this.parent();
18119 if(this.endX > this.startX){ // swiping right
18120 tabGroup.showPanelPrev();
18124 if(this.startX > this.endX){ // swiping left
18125 tabGroup.showPanelNext();
18144 * @class Roo.bootstrap.DateField
18145 * @extends Roo.bootstrap.Input
18146 * Bootstrap DateField class
18147 * @cfg {Number} weekStart default 0
18148 * @cfg {String} viewMode default empty, (months|years)
18149 * @cfg {String} minViewMode default empty, (months|years)
18150 * @cfg {Number} startDate default -Infinity
18151 * @cfg {Number} endDate default Infinity
18152 * @cfg {Boolean} todayHighlight default false
18153 * @cfg {Boolean} todayBtn default false
18154 * @cfg {Boolean} calendarWeeks default false
18155 * @cfg {Object} daysOfWeekDisabled default empty
18156 * @cfg {Boolean} singleMode default false (true | false)
18158 * @cfg {Boolean} keyboardNavigation default true
18159 * @cfg {String} language default en
18162 * Create a new DateField
18163 * @param {Object} config The config object
18166 Roo.bootstrap.DateField = function(config){
18167 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18171 * Fires when this field show.
18172 * @param {Roo.bootstrap.DateField} this
18173 * @param {Mixed} date The date value
18178 * Fires when this field hide.
18179 * @param {Roo.bootstrap.DateField} this
18180 * @param {Mixed} date The date value
18185 * Fires when select a date.
18186 * @param {Roo.bootstrap.DateField} this
18187 * @param {Mixed} date The date value
18191 * @event beforeselect
18192 * Fires when before select a date.
18193 * @param {Roo.bootstrap.DateField} this
18194 * @param {Mixed} date The date value
18196 beforeselect : true
18200 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18203 * @cfg {String} format
18204 * The default date format string which can be overriden for localization support. The format must be
18205 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18209 * @cfg {String} altFormats
18210 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18211 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18213 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18221 todayHighlight : false,
18227 keyboardNavigation: true,
18229 calendarWeeks: false,
18231 startDate: -Infinity,
18235 daysOfWeekDisabled: [],
18239 singleMode : false,
18241 UTCDate: function()
18243 return new Date(Date.UTC.apply(Date, arguments));
18246 UTCToday: function()
18248 var today = new Date();
18249 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18252 getDate: function() {
18253 var d = this.getUTCDate();
18254 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18257 getUTCDate: function() {
18261 setDate: function(d) {
18262 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18265 setUTCDate: function(d) {
18267 this.setValue(this.formatDate(this.date));
18270 onRender: function(ct, position)
18273 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18275 this.language = this.language || 'en';
18276 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18277 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18279 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18280 this.format = this.format || 'm/d/y';
18281 this.isInline = false;
18282 this.isInput = true;
18283 this.component = this.el.select('.add-on', true).first() || false;
18284 this.component = (this.component && this.component.length === 0) ? false : this.component;
18285 this.hasInput = this.component && this.inputEl().length;
18287 if (typeof(this.minViewMode === 'string')) {
18288 switch (this.minViewMode) {
18290 this.minViewMode = 1;
18293 this.minViewMode = 2;
18296 this.minViewMode = 0;
18301 if (typeof(this.viewMode === 'string')) {
18302 switch (this.viewMode) {
18315 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18317 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18319 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18321 this.picker().on('mousedown', this.onMousedown, this);
18322 this.picker().on('click', this.onClick, this);
18324 this.picker().addClass('datepicker-dropdown');
18326 this.startViewMode = this.viewMode;
18328 if(this.singleMode){
18329 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18330 v.setVisibilityMode(Roo.Element.DISPLAY);
18334 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18335 v.setStyle('width', '189px');
18339 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18340 if(!this.calendarWeeks){
18345 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18346 v.attr('colspan', function(i, val){
18347 return parseInt(val) + 1;
18352 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18354 this.setStartDate(this.startDate);
18355 this.setEndDate(this.endDate);
18357 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18364 if(this.isInline) {
18369 picker : function()
18371 return this.pickerEl;
18372 // return this.el.select('.datepicker', true).first();
18375 fillDow: function()
18377 var dowCnt = this.weekStart;
18386 if(this.calendarWeeks){
18394 while (dowCnt < this.weekStart + 7) {
18398 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18402 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18405 fillMonths: function()
18408 var months = this.picker().select('>.datepicker-months td', true).first();
18410 months.dom.innerHTML = '';
18416 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18419 months.createChild(month);
18426 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;
18428 if (this.date < this.startDate) {
18429 this.viewDate = new Date(this.startDate);
18430 } else if (this.date > this.endDate) {
18431 this.viewDate = new Date(this.endDate);
18433 this.viewDate = new Date(this.date);
18441 var d = new Date(this.viewDate),
18442 year = d.getUTCFullYear(),
18443 month = d.getUTCMonth(),
18444 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18445 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18446 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18447 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18448 currentDate = this.date && this.date.valueOf(),
18449 today = this.UTCToday();
18451 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18453 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18455 // this.picker.select('>tfoot th.today').
18456 // .text(dates[this.language].today)
18457 // .toggle(this.todayBtn !== false);
18459 this.updateNavArrows();
18462 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18464 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18466 prevMonth.setUTCDate(day);
18468 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18470 var nextMonth = new Date(prevMonth);
18472 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18474 nextMonth = nextMonth.valueOf();
18476 var fillMonths = false;
18478 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18480 while(prevMonth.valueOf() < nextMonth) {
18483 if (prevMonth.getUTCDay() === this.weekStart) {
18485 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18493 if(this.calendarWeeks){
18494 // ISO 8601: First week contains first thursday.
18495 // ISO also states week starts on Monday, but we can be more abstract here.
18497 // Start of current week: based on weekstart/current date
18498 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18499 // Thursday of this week
18500 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18501 // First Thursday of year, year from thursday
18502 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18503 // Calendar week: ms between thursdays, div ms per day, div 7 days
18504 calWeek = (th - yth) / 864e5 / 7 + 1;
18506 fillMonths.cn.push({
18514 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18516 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18519 if (this.todayHighlight &&
18520 prevMonth.getUTCFullYear() == today.getFullYear() &&
18521 prevMonth.getUTCMonth() == today.getMonth() &&
18522 prevMonth.getUTCDate() == today.getDate()) {
18523 clsName += ' today';
18526 if (currentDate && prevMonth.valueOf() === currentDate) {
18527 clsName += ' active';
18530 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18531 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18532 clsName += ' disabled';
18535 fillMonths.cn.push({
18537 cls: 'day ' + clsName,
18538 html: prevMonth.getDate()
18541 prevMonth.setDate(prevMonth.getDate()+1);
18544 var currentYear = this.date && this.date.getUTCFullYear();
18545 var currentMonth = this.date && this.date.getUTCMonth();
18547 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18549 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18550 v.removeClass('active');
18552 if(currentYear === year && k === currentMonth){
18553 v.addClass('active');
18556 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18557 v.addClass('disabled');
18563 year = parseInt(year/10, 10) * 10;
18565 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18567 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18570 for (var i = -1; i < 11; i++) {
18571 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18573 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18581 showMode: function(dir)
18584 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18587 Roo.each(this.picker().select('>div',true).elements, function(v){
18588 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18591 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18596 if(this.isInline) {
18600 this.picker().removeClass(['bottom', 'top']);
18602 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18604 * place to the top of element!
18608 this.picker().addClass('top');
18609 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18614 this.picker().addClass('bottom');
18616 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18619 parseDate : function(value)
18621 if(!value || value instanceof Date){
18624 var v = Date.parseDate(value, this.format);
18625 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18626 v = Date.parseDate(value, 'Y-m-d');
18628 if(!v && this.altFormats){
18629 if(!this.altFormatsArray){
18630 this.altFormatsArray = this.altFormats.split("|");
18632 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18633 v = Date.parseDate(value, this.altFormatsArray[i]);
18639 formatDate : function(date, fmt)
18641 return (!date || !(date instanceof Date)) ?
18642 date : date.dateFormat(fmt || this.format);
18645 onFocus : function()
18647 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18651 onBlur : function()
18653 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18655 var d = this.inputEl().getValue();
18664 this.picker().show();
18668 this.fireEvent('show', this, this.date);
18673 if(this.isInline) {
18676 this.picker().hide();
18677 this.viewMode = this.startViewMode;
18680 this.fireEvent('hide', this, this.date);
18684 onMousedown: function(e)
18686 e.stopPropagation();
18687 e.preventDefault();
18692 Roo.bootstrap.DateField.superclass.keyup.call(this);
18696 setValue: function(v)
18698 if(this.fireEvent('beforeselect', this, v) !== false){
18699 var d = new Date(this.parseDate(v) ).clearTime();
18701 if(isNaN(d.getTime())){
18702 this.date = this.viewDate = '';
18703 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18707 v = this.formatDate(d);
18709 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18711 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18715 this.fireEvent('select', this, this.date);
18719 getValue: function()
18721 return this.formatDate(this.date);
18724 fireKey: function(e)
18726 if (!this.picker().isVisible()){
18727 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18733 var dateChanged = false,
18735 newDate, newViewDate;
18740 e.preventDefault();
18744 if (!this.keyboardNavigation) {
18747 dir = e.keyCode == 37 ? -1 : 1;
18750 newDate = this.moveYear(this.date, dir);
18751 newViewDate = this.moveYear(this.viewDate, dir);
18752 } else if (e.shiftKey){
18753 newDate = this.moveMonth(this.date, dir);
18754 newViewDate = this.moveMonth(this.viewDate, dir);
18756 newDate = new Date(this.date);
18757 newDate.setUTCDate(this.date.getUTCDate() + dir);
18758 newViewDate = new Date(this.viewDate);
18759 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18761 if (this.dateWithinRange(newDate)){
18762 this.date = newDate;
18763 this.viewDate = newViewDate;
18764 this.setValue(this.formatDate(this.date));
18766 e.preventDefault();
18767 dateChanged = true;
18772 if (!this.keyboardNavigation) {
18775 dir = e.keyCode == 38 ? -1 : 1;
18777 newDate = this.moveYear(this.date, dir);
18778 newViewDate = this.moveYear(this.viewDate, dir);
18779 } else if (e.shiftKey){
18780 newDate = this.moveMonth(this.date, dir);
18781 newViewDate = this.moveMonth(this.viewDate, dir);
18783 newDate = new Date(this.date);
18784 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18785 newViewDate = new Date(this.viewDate);
18786 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18788 if (this.dateWithinRange(newDate)){
18789 this.date = newDate;
18790 this.viewDate = newViewDate;
18791 this.setValue(this.formatDate(this.date));
18793 e.preventDefault();
18794 dateChanged = true;
18798 this.setValue(this.formatDate(this.date));
18800 e.preventDefault();
18803 this.setValue(this.formatDate(this.date));
18817 onClick: function(e)
18819 e.stopPropagation();
18820 e.preventDefault();
18822 var target = e.getTarget();
18824 if(target.nodeName.toLowerCase() === 'i'){
18825 target = Roo.get(target).dom.parentNode;
18828 var nodeName = target.nodeName;
18829 var className = target.className;
18830 var html = target.innerHTML;
18831 //Roo.log(nodeName);
18833 switch(nodeName.toLowerCase()) {
18835 switch(className) {
18841 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18842 switch(this.viewMode){
18844 this.viewDate = this.moveMonth(this.viewDate, dir);
18848 this.viewDate = this.moveYear(this.viewDate, dir);
18854 var date = new Date();
18855 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18857 this.setValue(this.formatDate(this.date));
18864 if (className.indexOf('disabled') < 0) {
18865 this.viewDate.setUTCDate(1);
18866 if (className.indexOf('month') > -1) {
18867 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18869 var year = parseInt(html, 10) || 0;
18870 this.viewDate.setUTCFullYear(year);
18874 if(this.singleMode){
18875 this.setValue(this.formatDate(this.viewDate));
18886 //Roo.log(className);
18887 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18888 var day = parseInt(html, 10) || 1;
18889 var year = this.viewDate.getUTCFullYear(),
18890 month = this.viewDate.getUTCMonth();
18892 if (className.indexOf('old') > -1) {
18899 } else if (className.indexOf('new') > -1) {
18907 //Roo.log([year,month,day]);
18908 this.date = this.UTCDate(year, month, day,0,0,0,0);
18909 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18911 //Roo.log(this.formatDate(this.date));
18912 this.setValue(this.formatDate(this.date));
18919 setStartDate: function(startDate)
18921 this.startDate = startDate || -Infinity;
18922 if (this.startDate !== -Infinity) {
18923 this.startDate = this.parseDate(this.startDate);
18926 this.updateNavArrows();
18929 setEndDate: function(endDate)
18931 this.endDate = endDate || Infinity;
18932 if (this.endDate !== Infinity) {
18933 this.endDate = this.parseDate(this.endDate);
18936 this.updateNavArrows();
18939 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18941 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18942 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18943 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18945 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18946 return parseInt(d, 10);
18949 this.updateNavArrows();
18952 updateNavArrows: function()
18954 if(this.singleMode){
18958 var d = new Date(this.viewDate),
18959 year = d.getUTCFullYear(),
18960 month = d.getUTCMonth();
18962 Roo.each(this.picker().select('.prev', true).elements, function(v){
18964 switch (this.viewMode) {
18967 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18973 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18980 Roo.each(this.picker().select('.next', true).elements, function(v){
18982 switch (this.viewMode) {
18985 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18991 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18999 moveMonth: function(date, dir)
19004 var new_date = new Date(date.valueOf()),
19005 day = new_date.getUTCDate(),
19006 month = new_date.getUTCMonth(),
19007 mag = Math.abs(dir),
19009 dir = dir > 0 ? 1 : -1;
19012 // If going back one month, make sure month is not current month
19013 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19015 return new_date.getUTCMonth() == month;
19017 // If going forward one month, make sure month is as expected
19018 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19020 return new_date.getUTCMonth() != new_month;
19022 new_month = month + dir;
19023 new_date.setUTCMonth(new_month);
19024 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19025 if (new_month < 0 || new_month > 11) {
19026 new_month = (new_month + 12) % 12;
19029 // For magnitudes >1, move one month at a time...
19030 for (var i=0; i<mag; i++) {
19031 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19032 new_date = this.moveMonth(new_date, dir);
19034 // ...then reset the day, keeping it in the new month
19035 new_month = new_date.getUTCMonth();
19036 new_date.setUTCDate(day);
19038 return new_month != new_date.getUTCMonth();
19041 // Common date-resetting loop -- if date is beyond end of month, make it
19044 new_date.setUTCDate(--day);
19045 new_date.setUTCMonth(new_month);
19050 moveYear: function(date, dir)
19052 return this.moveMonth(date, dir*12);
19055 dateWithinRange: function(date)
19057 return date >= this.startDate && date <= this.endDate;
19063 this.picker().remove();
19066 validateValue : function(value)
19068 if(value.length < 1) {
19069 if(this.allowBlank){
19075 if(value.length < this.minLength){
19078 if(value.length > this.maxLength){
19082 var vt = Roo.form.VTypes;
19083 if(!vt[this.vtype](value, this)){
19087 if(typeof this.validator == "function"){
19088 var msg = this.validator(value);
19094 if(this.regex && !this.regex.test(value)){
19098 if(typeof(this.parseDate(value)) == 'undefined'){
19102 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19106 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19116 Roo.apply(Roo.bootstrap.DateField, {
19127 html: '<i class="fa fa-arrow-left"/>'
19137 html: '<i class="fa fa-arrow-right"/>'
19179 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19180 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19181 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19182 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19183 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19196 navFnc: 'FullYear',
19201 navFnc: 'FullYear',
19206 Roo.apply(Roo.bootstrap.DateField, {
19210 cls: 'datepicker dropdown-menu roo-dynamic',
19214 cls: 'datepicker-days',
19218 cls: 'table-condensed',
19220 Roo.bootstrap.DateField.head,
19224 Roo.bootstrap.DateField.footer
19231 cls: 'datepicker-months',
19235 cls: 'table-condensed',
19237 Roo.bootstrap.DateField.head,
19238 Roo.bootstrap.DateField.content,
19239 Roo.bootstrap.DateField.footer
19246 cls: 'datepicker-years',
19250 cls: 'table-condensed',
19252 Roo.bootstrap.DateField.head,
19253 Roo.bootstrap.DateField.content,
19254 Roo.bootstrap.DateField.footer
19273 * @class Roo.bootstrap.TimeField
19274 * @extends Roo.bootstrap.Input
19275 * Bootstrap DateField class
19279 * Create a new TimeField
19280 * @param {Object} config The config object
19283 Roo.bootstrap.TimeField = function(config){
19284 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19288 * Fires when this field show.
19289 * @param {Roo.bootstrap.DateField} thisthis
19290 * @param {Mixed} date The date value
19295 * Fires when this field hide.
19296 * @param {Roo.bootstrap.DateField} this
19297 * @param {Mixed} date The date value
19302 * Fires when select a date.
19303 * @param {Roo.bootstrap.DateField} this
19304 * @param {Mixed} date The date value
19310 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19313 * @cfg {String} format
19314 * The default time format string which can be overriden for localization support. The format must be
19315 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19319 onRender: function(ct, position)
19322 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19324 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19326 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19328 this.pop = this.picker().select('>.datepicker-time',true).first();
19329 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19331 this.picker().on('mousedown', this.onMousedown, this);
19332 this.picker().on('click', this.onClick, this);
19334 this.picker().addClass('datepicker-dropdown');
19339 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19340 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19341 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19342 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19343 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19344 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19348 fireKey: function(e){
19349 if (!this.picker().isVisible()){
19350 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19356 e.preventDefault();
19364 this.onTogglePeriod();
19367 this.onIncrementMinutes();
19370 this.onDecrementMinutes();
19379 onClick: function(e) {
19380 e.stopPropagation();
19381 e.preventDefault();
19384 picker : function()
19386 return this.el.select('.datepicker', true).first();
19389 fillTime: function()
19391 var time = this.pop.select('tbody', true).first();
19393 time.dom.innerHTML = '';
19408 cls: 'hours-up glyphicon glyphicon-chevron-up'
19428 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19449 cls: 'timepicker-hour',
19464 cls: 'timepicker-minute',
19479 cls: 'btn btn-primary period',
19501 cls: 'hours-down glyphicon glyphicon-chevron-down'
19521 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19539 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19546 var hours = this.time.getHours();
19547 var minutes = this.time.getMinutes();
19560 hours = hours - 12;
19564 hours = '0' + hours;
19568 minutes = '0' + minutes;
19571 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19572 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19573 this.pop.select('button', true).first().dom.innerHTML = period;
19579 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19581 var cls = ['bottom'];
19583 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19590 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19595 this.picker().addClass(cls.join('-'));
19599 Roo.each(cls, function(c){
19601 _this.picker().setTop(_this.inputEl().getHeight());
19605 _this.picker().setTop(0 - _this.picker().getHeight());
19610 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19614 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19621 onFocus : function()
19623 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19627 onBlur : function()
19629 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19635 this.picker().show();
19640 this.fireEvent('show', this, this.date);
19645 this.picker().hide();
19648 this.fireEvent('hide', this, this.date);
19651 setTime : function()
19654 this.setValue(this.time.format(this.format));
19656 this.fireEvent('select', this, this.date);
19661 onMousedown: function(e){
19662 e.stopPropagation();
19663 e.preventDefault();
19666 onIncrementHours: function()
19668 Roo.log('onIncrementHours');
19669 this.time = this.time.add(Date.HOUR, 1);
19674 onDecrementHours: function()
19676 Roo.log('onDecrementHours');
19677 this.time = this.time.add(Date.HOUR, -1);
19681 onIncrementMinutes: function()
19683 Roo.log('onIncrementMinutes');
19684 this.time = this.time.add(Date.MINUTE, 1);
19688 onDecrementMinutes: function()
19690 Roo.log('onDecrementMinutes');
19691 this.time = this.time.add(Date.MINUTE, -1);
19695 onTogglePeriod: function()
19697 Roo.log('onTogglePeriod');
19698 this.time = this.time.add(Date.HOUR, 12);
19705 Roo.apply(Roo.bootstrap.TimeField, {
19735 cls: 'btn btn-info ok',
19747 Roo.apply(Roo.bootstrap.TimeField, {
19751 cls: 'datepicker dropdown-menu',
19755 cls: 'datepicker-time',
19759 cls: 'table-condensed',
19761 Roo.bootstrap.TimeField.content,
19762 Roo.bootstrap.TimeField.footer
19781 * @class Roo.bootstrap.MonthField
19782 * @extends Roo.bootstrap.Input
19783 * Bootstrap MonthField class
19785 * @cfg {String} language default en
19788 * Create a new MonthField
19789 * @param {Object} config The config object
19792 Roo.bootstrap.MonthField = function(config){
19793 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19798 * Fires when this field show.
19799 * @param {Roo.bootstrap.MonthField} this
19800 * @param {Mixed} date The date value
19805 * Fires when this field hide.
19806 * @param {Roo.bootstrap.MonthField} this
19807 * @param {Mixed} date The date value
19812 * Fires when select a date.
19813 * @param {Roo.bootstrap.MonthField} this
19814 * @param {String} oldvalue The old value
19815 * @param {String} newvalue The new value
19821 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19823 onRender: function(ct, position)
19826 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19828 this.language = this.language || 'en';
19829 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19830 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19832 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19833 this.isInline = false;
19834 this.isInput = true;
19835 this.component = this.el.select('.add-on', true).first() || false;
19836 this.component = (this.component && this.component.length === 0) ? false : this.component;
19837 this.hasInput = this.component && this.inputEL().length;
19839 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19841 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19843 this.picker().on('mousedown', this.onMousedown, this);
19844 this.picker().on('click', this.onClick, this);
19846 this.picker().addClass('datepicker-dropdown');
19848 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19849 v.setStyle('width', '189px');
19856 if(this.isInline) {
19862 setValue: function(v, suppressEvent)
19864 var o = this.getValue();
19866 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19870 if(suppressEvent !== true){
19871 this.fireEvent('select', this, o, v);
19876 getValue: function()
19881 onClick: function(e)
19883 e.stopPropagation();
19884 e.preventDefault();
19886 var target = e.getTarget();
19888 if(target.nodeName.toLowerCase() === 'i'){
19889 target = Roo.get(target).dom.parentNode;
19892 var nodeName = target.nodeName;
19893 var className = target.className;
19894 var html = target.innerHTML;
19896 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19900 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19902 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19908 picker : function()
19910 return this.pickerEl;
19913 fillMonths: function()
19916 var months = this.picker().select('>.datepicker-months td', true).first();
19918 months.dom.innerHTML = '';
19924 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19927 months.createChild(month);
19936 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19937 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19940 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19941 e.removeClass('active');
19943 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19944 e.addClass('active');
19951 if(this.isInline) {
19955 this.picker().removeClass(['bottom', 'top']);
19957 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19959 * place to the top of element!
19963 this.picker().addClass('top');
19964 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19969 this.picker().addClass('bottom');
19971 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19974 onFocus : function()
19976 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19980 onBlur : function()
19982 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19984 var d = this.inputEl().getValue();
19993 this.picker().show();
19994 this.picker().select('>.datepicker-months', true).first().show();
19998 this.fireEvent('show', this, this.date);
20003 if(this.isInline) {
20006 this.picker().hide();
20007 this.fireEvent('hide', this, this.date);
20011 onMousedown: function(e)
20013 e.stopPropagation();
20014 e.preventDefault();
20019 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20023 fireKey: function(e)
20025 if (!this.picker().isVisible()){
20026 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20037 e.preventDefault();
20041 dir = e.keyCode == 37 ? -1 : 1;
20043 this.vIndex = this.vIndex + dir;
20045 if(this.vIndex < 0){
20049 if(this.vIndex > 11){
20053 if(isNaN(this.vIndex)){
20057 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20063 dir = e.keyCode == 38 ? -1 : 1;
20065 this.vIndex = this.vIndex + dir * 4;
20067 if(this.vIndex < 0){
20071 if(this.vIndex > 11){
20075 if(isNaN(this.vIndex)){
20079 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20084 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20085 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20089 e.preventDefault();
20092 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20093 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20109 this.picker().remove();
20114 Roo.apply(Roo.bootstrap.MonthField, {
20133 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20134 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20139 Roo.apply(Roo.bootstrap.MonthField, {
20143 cls: 'datepicker dropdown-menu roo-dynamic',
20147 cls: 'datepicker-months',
20151 cls: 'table-condensed',
20153 Roo.bootstrap.DateField.content
20173 * @class Roo.bootstrap.CheckBox
20174 * @extends Roo.bootstrap.Input
20175 * Bootstrap CheckBox class
20177 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20178 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20179 * @cfg {String} boxLabel The text that appears beside the checkbox
20180 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20181 * @cfg {Boolean} checked initnal the element
20182 * @cfg {Boolean} inline inline the element (default false)
20183 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20184 * @cfg {String} tooltip label tooltip
20187 * Create a new CheckBox
20188 * @param {Object} config The config object
20191 Roo.bootstrap.CheckBox = function(config){
20192 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20197 * Fires when the element is checked or unchecked.
20198 * @param {Roo.bootstrap.CheckBox} this This input
20199 * @param {Boolean} checked The new checked value
20204 * Fires when the element is click.
20205 * @param {Roo.bootstrap.CheckBox} this This input
20212 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20214 inputType: 'checkbox',
20223 getAutoCreate : function()
20225 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20231 cfg.cls = 'form-group ' + this.inputType; //input-group
20234 cfg.cls += ' ' + this.inputType + '-inline';
20240 type : this.inputType,
20241 value : this.inputValue,
20242 cls : 'roo-' + this.inputType, //'form-box',
20243 placeholder : this.placeholder || ''
20247 if(this.inputType != 'radio'){
20251 cls : 'roo-hidden-value',
20252 value : this.checked ? this.inputValue : this.valueOff
20257 if (this.weight) { // Validity check?
20258 cfg.cls += " " + this.inputType + "-" + this.weight;
20261 if (this.disabled) {
20262 input.disabled=true;
20266 input.checked = this.checked;
20271 input.name = this.name;
20273 if(this.inputType != 'radio'){
20274 hidden.name = this.name;
20275 input.name = '_hidden_' + this.name;
20280 input.cls += ' input-' + this.size;
20285 ['xs','sm','md','lg'].map(function(size){
20286 if (settings[size]) {
20287 cfg.cls += ' col-' + size + '-' + settings[size];
20291 var inputblock = input;
20293 if (this.before || this.after) {
20296 cls : 'input-group',
20301 inputblock.cn.push({
20303 cls : 'input-group-addon',
20308 inputblock.cn.push(input);
20310 if(this.inputType != 'radio'){
20311 inputblock.cn.push(hidden);
20315 inputblock.cn.push({
20317 cls : 'input-group-addon',
20324 if (align ==='left' && this.fieldLabel.length) {
20325 // Roo.log("left and has label");
20330 cls : 'control-label',
20331 html : this.fieldLabel
20341 if(this.labelWidth > 12){
20342 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20345 if(this.labelWidth < 13 && this.labelmd == 0){
20346 this.labelmd = this.labelWidth;
20349 if(this.labellg > 0){
20350 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20351 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20354 if(this.labelmd > 0){
20355 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20356 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20359 if(this.labelsm > 0){
20360 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20361 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20364 if(this.labelxs > 0){
20365 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20366 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20369 } else if ( this.fieldLabel.length) {
20370 // Roo.log(" label");
20374 tag: this.boxLabel ? 'span' : 'label',
20376 cls: 'control-label box-input-label',
20377 //cls : 'input-group-addon',
20378 html : this.fieldLabel
20387 // Roo.log(" no label && no align");
20388 cfg.cn = [ inputblock ] ;
20394 var boxLabelCfg = {
20396 //'for': id, // box label is handled by onclick - so no for...
20398 html: this.boxLabel
20402 boxLabelCfg.tooltip = this.tooltip;
20405 cfg.cn.push(boxLabelCfg);
20408 if(this.inputType != 'radio'){
20409 cfg.cn.push(hidden);
20417 * return the real input element.
20419 inputEl: function ()
20421 return this.el.select('input.roo-' + this.inputType,true).first();
20423 hiddenEl: function ()
20425 return this.el.select('input.roo-hidden-value',true).first();
20428 labelEl: function()
20430 return this.el.select('label.control-label',true).first();
20432 /* depricated... */
20436 return this.labelEl();
20439 boxLabelEl: function()
20441 return this.el.select('label.box-label',true).first();
20444 initEvents : function()
20446 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20448 this.inputEl().on('click', this.onClick, this);
20450 if (this.boxLabel) {
20451 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20454 this.startValue = this.getValue();
20457 Roo.bootstrap.CheckBox.register(this);
20461 onClick : function(e)
20463 if(this.fireEvent('click', this, e) !== false){
20464 this.setChecked(!this.checked);
20469 setChecked : function(state,suppressEvent)
20471 this.startValue = this.getValue();
20473 if(this.inputType == 'radio'){
20475 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20476 e.dom.checked = false;
20479 this.inputEl().dom.checked = true;
20481 this.inputEl().dom.value = this.inputValue;
20483 if(suppressEvent !== true){
20484 this.fireEvent('check', this, true);
20492 this.checked = state;
20494 this.inputEl().dom.checked = state;
20497 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20499 if(suppressEvent !== true){
20500 this.fireEvent('check', this, state);
20506 getValue : function()
20508 if(this.inputType == 'radio'){
20509 return this.getGroupValue();
20512 return this.hiddenEl().dom.value;
20516 getGroupValue : function()
20518 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20522 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20525 setValue : function(v,suppressEvent)
20527 if(this.inputType == 'radio'){
20528 this.setGroupValue(v, suppressEvent);
20532 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20537 setGroupValue : function(v, suppressEvent)
20539 this.startValue = this.getValue();
20541 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20542 e.dom.checked = false;
20544 if(e.dom.value == v){
20545 e.dom.checked = true;
20549 if(suppressEvent !== true){
20550 this.fireEvent('check', this, true);
20558 validate : function()
20562 (this.inputType == 'radio' && this.validateRadio()) ||
20563 (this.inputType == 'checkbox' && this.validateCheckbox())
20569 this.markInvalid();
20573 validateRadio : function()
20575 if(this.allowBlank){
20581 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20582 if(!e.dom.checked){
20594 validateCheckbox : function()
20597 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20598 //return (this.getValue() == this.inputValue) ? true : false;
20601 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20609 for(var i in group){
20610 if(group[i].el.isVisible(true)){
20618 for(var i in group){
20623 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20630 * Mark this field as valid
20632 markValid : function()
20636 this.fireEvent('valid', this);
20638 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20641 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20648 if(this.inputType == 'radio'){
20649 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20650 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20651 e.findParent('.form-group', false, true).addClass(_this.validClass);
20658 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20659 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20663 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20669 for(var i in group){
20670 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20671 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20676 * Mark this field as invalid
20677 * @param {String} msg The validation message
20679 markInvalid : function(msg)
20681 if(this.allowBlank){
20687 this.fireEvent('invalid', this, msg);
20689 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20692 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20696 label.markInvalid();
20699 if(this.inputType == 'radio'){
20700 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20701 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20702 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20709 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20710 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20714 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20720 for(var i in group){
20721 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20722 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20727 clearInvalid : function()
20729 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20731 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20733 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20735 if (label && label.iconEl) {
20736 label.iconEl.removeClass(label.validClass);
20737 label.iconEl.removeClass(label.invalidClass);
20741 disable : function()
20743 if(this.inputType != 'radio'){
20744 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20751 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20752 _this.getActionEl().addClass(this.disabledClass);
20753 e.dom.disabled = true;
20757 this.disabled = true;
20758 this.fireEvent("disable", this);
20762 enable : function()
20764 if(this.inputType != 'radio'){
20765 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20772 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20773 _this.getActionEl().removeClass(this.disabledClass);
20774 e.dom.disabled = false;
20778 this.disabled = false;
20779 this.fireEvent("enable", this);
20783 setBoxLabel : function(v)
20788 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20794 Roo.apply(Roo.bootstrap.CheckBox, {
20799 * register a CheckBox Group
20800 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20802 register : function(checkbox)
20804 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20805 this.groups[checkbox.groupId] = {};
20808 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20812 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20816 * fetch a CheckBox Group based on the group ID
20817 * @param {string} the group ID
20818 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20820 get: function(groupId) {
20821 if (typeof(this.groups[groupId]) == 'undefined') {
20825 return this.groups[groupId] ;
20838 * @class Roo.bootstrap.Radio
20839 * @extends Roo.bootstrap.Component
20840 * Bootstrap Radio class
20841 * @cfg {String} boxLabel - the label associated
20842 * @cfg {String} value - the value of radio
20845 * Create a new Radio
20846 * @param {Object} config The config object
20848 Roo.bootstrap.Radio = function(config){
20849 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20853 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20859 getAutoCreate : function()
20863 cls : 'form-group radio',
20868 html : this.boxLabel
20876 initEvents : function()
20878 this.parent().register(this);
20880 this.el.on('click', this.onClick, this);
20884 onClick : function()
20886 this.setChecked(true);
20889 setChecked : function(state, suppressEvent)
20891 this.parent().setValue(this.value, suppressEvent);
20895 setBoxLabel : function(v)
20900 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20915 * @class Roo.bootstrap.SecurePass
20916 * @extends Roo.bootstrap.Input
20917 * Bootstrap SecurePass class
20921 * Create a new SecurePass
20922 * @param {Object} config The config object
20925 Roo.bootstrap.SecurePass = function (config) {
20926 // these go here, so the translation tool can replace them..
20928 PwdEmpty: "Please type a password, and then retype it to confirm.",
20929 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20930 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20931 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20932 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20933 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20934 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20935 TooWeak: "Your password is Too Weak."
20937 this.meterLabel = "Password strength:";
20938 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20939 this.meterClass = [
20940 "roo-password-meter-tooweak",
20941 "roo-password-meter-weak",
20942 "roo-password-meter-medium",
20943 "roo-password-meter-strong",
20944 "roo-password-meter-grey"
20949 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20952 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20954 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20956 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20957 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20958 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20959 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20960 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20961 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20962 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20972 * @cfg {String/Object} Label for the strength meter (defaults to
20973 * 'Password strength:')
20978 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20979 * ['Weak', 'Medium', 'Strong'])
20982 pwdStrengths: false,
20995 initEvents: function ()
20997 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20999 if (this.el.is('input[type=password]') && Roo.isSafari) {
21000 this.el.on('keydown', this.SafariOnKeyDown, this);
21003 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21006 onRender: function (ct, position)
21008 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21009 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21010 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21012 this.trigger.createChild({
21017 cls: 'roo-password-meter-grey col-xs-12',
21020 //width: this.meterWidth + 'px'
21024 cls: 'roo-password-meter-text'
21030 if (this.hideTrigger) {
21031 this.trigger.setDisplayed(false);
21033 this.setSize(this.width || '', this.height || '');
21036 onDestroy: function ()
21038 if (this.trigger) {
21039 this.trigger.removeAllListeners();
21040 this.trigger.remove();
21043 this.wrap.remove();
21045 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21048 checkStrength: function ()
21050 var pwd = this.inputEl().getValue();
21051 if (pwd == this._lastPwd) {
21056 if (this.ClientSideStrongPassword(pwd)) {
21058 } else if (this.ClientSideMediumPassword(pwd)) {
21060 } else if (this.ClientSideWeakPassword(pwd)) {
21066 Roo.log('strength1: ' + strength);
21068 //var pm = this.trigger.child('div/div/div').dom;
21069 var pm = this.trigger.child('div/div');
21070 pm.removeClass(this.meterClass);
21071 pm.addClass(this.meterClass[strength]);
21074 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21076 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21078 this._lastPwd = pwd;
21082 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21084 this._lastPwd = '';
21086 var pm = this.trigger.child('div/div');
21087 pm.removeClass(this.meterClass);
21088 pm.addClass('roo-password-meter-grey');
21091 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21094 this.inputEl().dom.type='password';
21097 validateValue: function (value)
21100 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21103 if (value.length == 0) {
21104 if (this.allowBlank) {
21105 this.clearInvalid();
21109 this.markInvalid(this.errors.PwdEmpty);
21110 this.errorMsg = this.errors.PwdEmpty;
21118 if ('[\x21-\x7e]*'.match(value)) {
21119 this.markInvalid(this.errors.PwdBadChar);
21120 this.errorMsg = this.errors.PwdBadChar;
21123 if (value.length < 6) {
21124 this.markInvalid(this.errors.PwdShort);
21125 this.errorMsg = this.errors.PwdShort;
21128 if (value.length > 16) {
21129 this.markInvalid(this.errors.PwdLong);
21130 this.errorMsg = this.errors.PwdLong;
21134 if (this.ClientSideStrongPassword(value)) {
21136 } else if (this.ClientSideMediumPassword(value)) {
21138 } else if (this.ClientSideWeakPassword(value)) {
21145 if (strength < 2) {
21146 //this.markInvalid(this.errors.TooWeak);
21147 this.errorMsg = this.errors.TooWeak;
21152 console.log('strength2: ' + strength);
21154 //var pm = this.trigger.child('div/div/div').dom;
21156 var pm = this.trigger.child('div/div');
21157 pm.removeClass(this.meterClass);
21158 pm.addClass(this.meterClass[strength]);
21160 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21162 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21164 this.errorMsg = '';
21168 CharacterSetChecks: function (type)
21171 this.fResult = false;
21174 isctype: function (character, type)
21177 case this.kCapitalLetter:
21178 if (character >= 'A' && character <= 'Z') {
21183 case this.kSmallLetter:
21184 if (character >= 'a' && character <= 'z') {
21190 if (character >= '0' && character <= '9') {
21195 case this.kPunctuation:
21196 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21207 IsLongEnough: function (pwd, size)
21209 return !(pwd == null || isNaN(size) || pwd.length < size);
21212 SpansEnoughCharacterSets: function (word, nb)
21214 if (!this.IsLongEnough(word, nb))
21219 var characterSetChecks = new Array(
21220 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21221 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21224 for (var index = 0; index < word.length; ++index) {
21225 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21226 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21227 characterSetChecks[nCharSet].fResult = true;
21234 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21235 if (characterSetChecks[nCharSet].fResult) {
21240 if (nCharSets < nb) {
21246 ClientSideStrongPassword: function (pwd)
21248 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21251 ClientSideMediumPassword: function (pwd)
21253 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21256 ClientSideWeakPassword: function (pwd)
21258 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21261 })//<script type="text/javascript">
21264 * Based Ext JS Library 1.1.1
21265 * Copyright(c) 2006-2007, Ext JS, LLC.
21271 * @class Roo.HtmlEditorCore
21272 * @extends Roo.Component
21273 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21275 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21278 Roo.HtmlEditorCore = function(config){
21281 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21286 * @event initialize
21287 * Fires when the editor is fully initialized (including the iframe)
21288 * @param {Roo.HtmlEditorCore} this
21293 * Fires when the editor is first receives the focus. Any insertion must wait
21294 * until after this event.
21295 * @param {Roo.HtmlEditorCore} this
21299 * @event beforesync
21300 * Fires before the textarea is updated with content from the editor iframe. Return false
21301 * to cancel the sync.
21302 * @param {Roo.HtmlEditorCore} this
21303 * @param {String} html
21307 * @event beforepush
21308 * Fires before the iframe editor is updated with content from the textarea. Return false
21309 * to cancel the push.
21310 * @param {Roo.HtmlEditorCore} this
21311 * @param {String} html
21316 * Fires when the textarea is updated with content from the editor iframe.
21317 * @param {Roo.HtmlEditorCore} this
21318 * @param {String} html
21323 * Fires when the iframe editor is updated with content from the textarea.
21324 * @param {Roo.HtmlEditorCore} this
21325 * @param {String} html
21330 * @event editorevent
21331 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21332 * @param {Roo.HtmlEditorCore} this
21338 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21340 // defaults : white / black...
21341 this.applyBlacklists();
21348 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21352 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21358 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21363 * @cfg {Number} height (in pixels)
21367 * @cfg {Number} width (in pixels)
21372 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21375 stylesheets: false,
21380 // private properties
21381 validationEvent : false,
21383 initialized : false,
21385 sourceEditMode : false,
21386 onFocus : Roo.emptyFn,
21388 hideMode:'offsets',
21392 // blacklist + whitelisted elements..
21399 * Protected method that will not generally be called directly. It
21400 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21401 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21403 getDocMarkup : function(){
21407 // inherit styels from page...??
21408 if (this.stylesheets === false) {
21410 Roo.get(document.head).select('style').each(function(node) {
21411 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21414 Roo.get(document.head).select('link').each(function(node) {
21415 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21418 } else if (!this.stylesheets.length) {
21420 st = '<style type="text/css">' +
21421 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21424 st = '<style type="text/css">' +
21429 st += '<style type="text/css">' +
21430 'IMG { cursor: pointer } ' +
21433 var cls = 'roo-htmleditor-body';
21435 if(this.bodyCls.length){
21436 cls += ' ' + this.bodyCls;
21439 return '<html><head>' + st +
21440 //<style type="text/css">' +
21441 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21443 ' </head><body class="' + cls + '"></body></html>';
21447 onRender : function(ct, position)
21450 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21451 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21454 this.el.dom.style.border = '0 none';
21455 this.el.dom.setAttribute('tabIndex', -1);
21456 this.el.addClass('x-hidden hide');
21460 if(Roo.isIE){ // fix IE 1px bogus margin
21461 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21465 this.frameId = Roo.id();
21469 var iframe = this.owner.wrap.createChild({
21471 cls: 'form-control', // bootstrap..
21473 name: this.frameId,
21474 frameBorder : 'no',
21475 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21480 this.iframe = iframe.dom;
21482 this.assignDocWin();
21484 this.doc.designMode = 'on';
21487 this.doc.write(this.getDocMarkup());
21491 var task = { // must defer to wait for browser to be ready
21493 //console.log("run task?" + this.doc.readyState);
21494 this.assignDocWin();
21495 if(this.doc.body || this.doc.readyState == 'complete'){
21497 this.doc.designMode="on";
21501 Roo.TaskMgr.stop(task);
21502 this.initEditor.defer(10, this);
21509 Roo.TaskMgr.start(task);
21514 onResize : function(w, h)
21516 Roo.log('resize: ' +w + ',' + h );
21517 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21521 if(typeof w == 'number'){
21523 this.iframe.style.width = w + 'px';
21525 if(typeof h == 'number'){
21527 this.iframe.style.height = h + 'px';
21529 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21536 * Toggles the editor between standard and source edit mode.
21537 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21539 toggleSourceEdit : function(sourceEditMode){
21541 this.sourceEditMode = sourceEditMode === true;
21543 if(this.sourceEditMode){
21545 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21548 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21549 //this.iframe.className = '';
21552 //this.setSize(this.owner.wrap.getSize());
21553 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21560 * Protected method that will not generally be called directly. If you need/want
21561 * custom HTML cleanup, this is the method you should override.
21562 * @param {String} html The HTML to be cleaned
21563 * return {String} The cleaned HTML
21565 cleanHtml : function(html){
21566 html = String(html);
21567 if(html.length > 5){
21568 if(Roo.isSafari){ // strip safari nonsense
21569 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21572 if(html == ' '){
21579 * HTML Editor -> Textarea
21580 * Protected method that will not generally be called directly. Syncs the contents
21581 * of the editor iframe with the textarea.
21583 syncValue : function(){
21584 if(this.initialized){
21585 var bd = (this.doc.body || this.doc.documentElement);
21586 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21587 var html = bd.innerHTML;
21589 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21590 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21592 html = '<div style="'+m[0]+'">' + html + '</div>';
21595 html = this.cleanHtml(html);
21596 // fix up the special chars.. normaly like back quotes in word...
21597 // however we do not want to do this with chinese..
21598 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21599 var cc = b.charCodeAt();
21601 (cc >= 0x4E00 && cc < 0xA000 ) ||
21602 (cc >= 0x3400 && cc < 0x4E00 ) ||
21603 (cc >= 0xf900 && cc < 0xfb00 )
21609 if(this.owner.fireEvent('beforesync', this, html) !== false){
21610 this.el.dom.value = html;
21611 this.owner.fireEvent('sync', this, html);
21617 * Protected method that will not generally be called directly. Pushes the value of the textarea
21618 * into the iframe editor.
21620 pushValue : function(){
21621 if(this.initialized){
21622 var v = this.el.dom.value.trim();
21624 // if(v.length < 1){
21628 if(this.owner.fireEvent('beforepush', this, v) !== false){
21629 var d = (this.doc.body || this.doc.documentElement);
21631 this.cleanUpPaste();
21632 this.el.dom.value = d.innerHTML;
21633 this.owner.fireEvent('push', this, v);
21639 deferFocus : function(){
21640 this.focus.defer(10, this);
21644 focus : function(){
21645 if(this.win && !this.sourceEditMode){
21652 assignDocWin: function()
21654 var iframe = this.iframe;
21657 this.doc = iframe.contentWindow.document;
21658 this.win = iframe.contentWindow;
21660 // if (!Roo.get(this.frameId)) {
21663 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21664 // this.win = Roo.get(this.frameId).dom.contentWindow;
21666 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21670 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21671 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21676 initEditor : function(){
21677 //console.log("INIT EDITOR");
21678 this.assignDocWin();
21682 this.doc.designMode="on";
21684 this.doc.write(this.getDocMarkup());
21687 var dbody = (this.doc.body || this.doc.documentElement);
21688 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21689 // this copies styles from the containing element into thsi one..
21690 // not sure why we need all of this..
21691 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21693 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21694 //ss['background-attachment'] = 'fixed'; // w3c
21695 dbody.bgProperties = 'fixed'; // ie
21696 //Roo.DomHelper.applyStyles(dbody, ss);
21697 Roo.EventManager.on(this.doc, {
21698 //'mousedown': this.onEditorEvent,
21699 'mouseup': this.onEditorEvent,
21700 'dblclick': this.onEditorEvent,
21701 'click': this.onEditorEvent,
21702 'keyup': this.onEditorEvent,
21707 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21709 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21710 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21712 this.initialized = true;
21714 this.owner.fireEvent('initialize', this);
21719 onDestroy : function(){
21725 //for (var i =0; i < this.toolbars.length;i++) {
21726 // // fixme - ask toolbars for heights?
21727 // this.toolbars[i].onDestroy();
21730 //this.wrap.dom.innerHTML = '';
21731 //this.wrap.remove();
21736 onFirstFocus : function(){
21738 this.assignDocWin();
21741 this.activated = true;
21744 if(Roo.isGecko){ // prevent silly gecko errors
21746 var s = this.win.getSelection();
21747 if(!s.focusNode || s.focusNode.nodeType != 3){
21748 var r = s.getRangeAt(0);
21749 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21754 this.execCmd('useCSS', true);
21755 this.execCmd('styleWithCSS', false);
21758 this.owner.fireEvent('activate', this);
21762 adjustFont: function(btn){
21763 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21764 //if(Roo.isSafari){ // safari
21767 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21768 if(Roo.isSafari){ // safari
21769 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21770 v = (v < 10) ? 10 : v;
21771 v = (v > 48) ? 48 : v;
21772 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21777 v = Math.max(1, v+adjust);
21779 this.execCmd('FontSize', v );
21782 onEditorEvent : function(e)
21784 this.owner.fireEvent('editorevent', this, e);
21785 // this.updateToolbar();
21786 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21789 insertTag : function(tg)
21791 // could be a bit smarter... -> wrap the current selected tRoo..
21792 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21794 range = this.createRange(this.getSelection());
21795 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21796 wrappingNode.appendChild(range.extractContents());
21797 range.insertNode(wrappingNode);
21804 this.execCmd("formatblock", tg);
21808 insertText : function(txt)
21812 var range = this.createRange();
21813 range.deleteContents();
21814 //alert(Sender.getAttribute('label'));
21816 range.insertNode(this.doc.createTextNode(txt));
21822 * Executes a Midas editor command on the editor document and performs necessary focus and
21823 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21824 * @param {String} cmd The Midas command
21825 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21827 relayCmd : function(cmd, value){
21829 this.execCmd(cmd, value);
21830 this.owner.fireEvent('editorevent', this);
21831 //this.updateToolbar();
21832 this.owner.deferFocus();
21836 * Executes a Midas editor command directly on the editor document.
21837 * For visual commands, you should use {@link #relayCmd} instead.
21838 * <b>This should only be called after the editor is initialized.</b>
21839 * @param {String} cmd The Midas command
21840 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21842 execCmd : function(cmd, value){
21843 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21850 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21852 * @param {String} text | dom node..
21854 insertAtCursor : function(text)
21857 if(!this.activated){
21863 var r = this.doc.selection.createRange();
21874 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21878 // from jquery ui (MIT licenced)
21880 var win = this.win;
21882 if (win.getSelection && win.getSelection().getRangeAt) {
21883 range = win.getSelection().getRangeAt(0);
21884 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21885 range.insertNode(node);
21886 } else if (win.document.selection && win.document.selection.createRange) {
21887 // no firefox support
21888 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21889 win.document.selection.createRange().pasteHTML(txt);
21891 // no firefox support
21892 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21893 this.execCmd('InsertHTML', txt);
21902 mozKeyPress : function(e){
21904 var c = e.getCharCode(), cmd;
21907 c = String.fromCharCode(c).toLowerCase();
21921 this.cleanUpPaste.defer(100, this);
21929 e.preventDefault();
21937 fixKeys : function(){ // load time branching for fastest keydown performance
21939 return function(e){
21940 var k = e.getKey(), r;
21943 r = this.doc.selection.createRange();
21946 r.pasteHTML('    ');
21953 r = this.doc.selection.createRange();
21955 var target = r.parentElement();
21956 if(!target || target.tagName.toLowerCase() != 'li'){
21958 r.pasteHTML('<br />');
21964 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21965 this.cleanUpPaste.defer(100, this);
21971 }else if(Roo.isOpera){
21972 return function(e){
21973 var k = e.getKey();
21977 this.execCmd('InsertHTML','    ');
21980 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21981 this.cleanUpPaste.defer(100, this);
21986 }else if(Roo.isSafari){
21987 return function(e){
21988 var k = e.getKey();
21992 this.execCmd('InsertText','\t');
21996 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21997 this.cleanUpPaste.defer(100, this);
22005 getAllAncestors: function()
22007 var p = this.getSelectedNode();
22010 a.push(p); // push blank onto stack..
22011 p = this.getParentElement();
22015 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22019 a.push(this.doc.body);
22023 lastSelNode : false,
22026 getSelection : function()
22028 this.assignDocWin();
22029 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22032 getSelectedNode: function()
22034 // this may only work on Gecko!!!
22036 // should we cache this!!!!
22041 var range = this.createRange(this.getSelection()).cloneRange();
22044 var parent = range.parentElement();
22046 var testRange = range.duplicate();
22047 testRange.moveToElementText(parent);
22048 if (testRange.inRange(range)) {
22051 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22054 parent = parent.parentElement;
22059 // is ancestor a text element.
22060 var ac = range.commonAncestorContainer;
22061 if (ac.nodeType == 3) {
22062 ac = ac.parentNode;
22065 var ar = ac.childNodes;
22068 var other_nodes = [];
22069 var has_other_nodes = false;
22070 for (var i=0;i<ar.length;i++) {
22071 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22074 // fullly contained node.
22076 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22081 // probably selected..
22082 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22083 other_nodes.push(ar[i]);
22087 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22092 has_other_nodes = true;
22094 if (!nodes.length && other_nodes.length) {
22095 nodes= other_nodes;
22097 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22103 createRange: function(sel)
22105 // this has strange effects when using with
22106 // top toolbar - not sure if it's a great idea.
22107 //this.editor.contentWindow.focus();
22108 if (typeof sel != "undefined") {
22110 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22112 return this.doc.createRange();
22115 return this.doc.createRange();
22118 getParentElement: function()
22121 this.assignDocWin();
22122 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22124 var range = this.createRange(sel);
22127 var p = range.commonAncestorContainer;
22128 while (p.nodeType == 3) { // text node
22139 * Range intersection.. the hard stuff...
22143 * [ -- selected range --- ]
22147 * if end is before start or hits it. fail.
22148 * if start is after end or hits it fail.
22150 * if either hits (but other is outside. - then it's not
22156 // @see http://www.thismuchiknow.co.uk/?p=64.
22157 rangeIntersectsNode : function(range, node)
22159 var nodeRange = node.ownerDocument.createRange();
22161 nodeRange.selectNode(node);
22163 nodeRange.selectNodeContents(node);
22166 var rangeStartRange = range.cloneRange();
22167 rangeStartRange.collapse(true);
22169 var rangeEndRange = range.cloneRange();
22170 rangeEndRange.collapse(false);
22172 var nodeStartRange = nodeRange.cloneRange();
22173 nodeStartRange.collapse(true);
22175 var nodeEndRange = nodeRange.cloneRange();
22176 nodeEndRange.collapse(false);
22178 return rangeStartRange.compareBoundaryPoints(
22179 Range.START_TO_START, nodeEndRange) == -1 &&
22180 rangeEndRange.compareBoundaryPoints(
22181 Range.START_TO_START, nodeStartRange) == 1;
22185 rangeCompareNode : function(range, node)
22187 var nodeRange = node.ownerDocument.createRange();
22189 nodeRange.selectNode(node);
22191 nodeRange.selectNodeContents(node);
22195 range.collapse(true);
22197 nodeRange.collapse(true);
22199 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22200 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22202 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22204 var nodeIsBefore = ss == 1;
22205 var nodeIsAfter = ee == -1;
22207 if (nodeIsBefore && nodeIsAfter) {
22210 if (!nodeIsBefore && nodeIsAfter) {
22211 return 1; //right trailed.
22214 if (nodeIsBefore && !nodeIsAfter) {
22215 return 2; // left trailed.
22221 // private? - in a new class?
22222 cleanUpPaste : function()
22224 // cleans up the whole document..
22225 Roo.log('cleanuppaste');
22227 this.cleanUpChildren(this.doc.body);
22228 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22229 if (clean != this.doc.body.innerHTML) {
22230 this.doc.body.innerHTML = clean;
22235 cleanWordChars : function(input) {// change the chars to hex code
22236 var he = Roo.HtmlEditorCore;
22238 var output = input;
22239 Roo.each(he.swapCodes, function(sw) {
22240 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22242 output = output.replace(swapper, sw[1]);
22249 cleanUpChildren : function (n)
22251 if (!n.childNodes.length) {
22254 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22255 this.cleanUpChild(n.childNodes[i]);
22262 cleanUpChild : function (node)
22265 //console.log(node);
22266 if (node.nodeName == "#text") {
22267 // clean up silly Windows -- stuff?
22270 if (node.nodeName == "#comment") {
22271 node.parentNode.removeChild(node);
22272 // clean up silly Windows -- stuff?
22275 var lcname = node.tagName.toLowerCase();
22276 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22277 // whitelist of tags..
22279 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22281 node.parentNode.removeChild(node);
22286 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22288 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22289 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22291 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22292 // remove_keep_children = true;
22295 if (remove_keep_children) {
22296 this.cleanUpChildren(node);
22297 // inserts everything just before this node...
22298 while (node.childNodes.length) {
22299 var cn = node.childNodes[0];
22300 node.removeChild(cn);
22301 node.parentNode.insertBefore(cn, node);
22303 node.parentNode.removeChild(node);
22307 if (!node.attributes || !node.attributes.length) {
22308 this.cleanUpChildren(node);
22312 function cleanAttr(n,v)
22315 if (v.match(/^\./) || v.match(/^\//)) {
22318 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22321 if (v.match(/^#/)) {
22324 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22325 node.removeAttribute(n);
22329 var cwhite = this.cwhite;
22330 var cblack = this.cblack;
22332 function cleanStyle(n,v)
22334 if (v.match(/expression/)) { //XSS?? should we even bother..
22335 node.removeAttribute(n);
22339 var parts = v.split(/;/);
22342 Roo.each(parts, function(p) {
22343 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22347 var l = p.split(':').shift().replace(/\s+/g,'');
22348 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22350 if ( cwhite.length && cblack.indexOf(l) > -1) {
22351 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22352 //node.removeAttribute(n);
22356 // only allow 'c whitelisted system attributes'
22357 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22358 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22359 //node.removeAttribute(n);
22369 if (clean.length) {
22370 node.setAttribute(n, clean.join(';'));
22372 node.removeAttribute(n);
22378 for (var i = node.attributes.length-1; i > -1 ; i--) {
22379 var a = node.attributes[i];
22382 if (a.name.toLowerCase().substr(0,2)=='on') {
22383 node.removeAttribute(a.name);
22386 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22387 node.removeAttribute(a.name);
22390 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22391 cleanAttr(a.name,a.value); // fixme..
22394 if (a.name == 'style') {
22395 cleanStyle(a.name,a.value);
22398 /// clean up MS crap..
22399 // tecnically this should be a list of valid class'es..
22402 if (a.name == 'class') {
22403 if (a.value.match(/^Mso/)) {
22404 node.className = '';
22407 if (a.value.match(/^body$/)) {
22408 node.className = '';
22419 this.cleanUpChildren(node);
22425 * Clean up MS wordisms...
22427 cleanWord : function(node)
22432 this.cleanWord(this.doc.body);
22435 if (node.nodeName == "#text") {
22436 // clean up silly Windows -- stuff?
22439 if (node.nodeName == "#comment") {
22440 node.parentNode.removeChild(node);
22441 // clean up silly Windows -- stuff?
22445 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22446 node.parentNode.removeChild(node);
22450 // remove - but keep children..
22451 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22452 while (node.childNodes.length) {
22453 var cn = node.childNodes[0];
22454 node.removeChild(cn);
22455 node.parentNode.insertBefore(cn, node);
22457 node.parentNode.removeChild(node);
22458 this.iterateChildren(node, this.cleanWord);
22462 if (node.className.length) {
22464 var cn = node.className.split(/\W+/);
22466 Roo.each(cn, function(cls) {
22467 if (cls.match(/Mso[a-zA-Z]+/)) {
22472 node.className = cna.length ? cna.join(' ') : '';
22474 node.removeAttribute("class");
22478 if (node.hasAttribute("lang")) {
22479 node.removeAttribute("lang");
22482 if (node.hasAttribute("style")) {
22484 var styles = node.getAttribute("style").split(";");
22486 Roo.each(styles, function(s) {
22487 if (!s.match(/:/)) {
22490 var kv = s.split(":");
22491 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22494 // what ever is left... we allow.
22497 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22498 if (!nstyle.length) {
22499 node.removeAttribute('style');
22502 this.iterateChildren(node, this.cleanWord);
22508 * iterateChildren of a Node, calling fn each time, using this as the scole..
22509 * @param {DomNode} node node to iterate children of.
22510 * @param {Function} fn method of this class to call on each item.
22512 iterateChildren : function(node, fn)
22514 if (!node.childNodes.length) {
22517 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22518 fn.call(this, node.childNodes[i])
22524 * cleanTableWidths.
22526 * Quite often pasting from word etc.. results in tables with column and widths.
22527 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22530 cleanTableWidths : function(node)
22535 this.cleanTableWidths(this.doc.body);
22540 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22543 Roo.log(node.tagName);
22544 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22545 this.iterateChildren(node, this.cleanTableWidths);
22548 if (node.hasAttribute('width')) {
22549 node.removeAttribute('width');
22553 if (node.hasAttribute("style")) {
22556 var styles = node.getAttribute("style").split(";");
22558 Roo.each(styles, function(s) {
22559 if (!s.match(/:/)) {
22562 var kv = s.split(":");
22563 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22566 // what ever is left... we allow.
22569 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22570 if (!nstyle.length) {
22571 node.removeAttribute('style');
22575 this.iterateChildren(node, this.cleanTableWidths);
22583 domToHTML : function(currentElement, depth, nopadtext) {
22585 depth = depth || 0;
22586 nopadtext = nopadtext || false;
22588 if (!currentElement) {
22589 return this.domToHTML(this.doc.body);
22592 //Roo.log(currentElement);
22594 var allText = false;
22595 var nodeName = currentElement.nodeName;
22596 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22598 if (nodeName == '#text') {
22600 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22605 if (nodeName != 'BODY') {
22608 // Prints the node tagName, such as <A>, <IMG>, etc
22611 for(i = 0; i < currentElement.attributes.length;i++) {
22613 var aname = currentElement.attributes.item(i).name;
22614 if (!currentElement.attributes.item(i).value.length) {
22617 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22620 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22629 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22632 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22637 // Traverse the tree
22639 var currentElementChild = currentElement.childNodes.item(i);
22640 var allText = true;
22641 var innerHTML = '';
22643 while (currentElementChild) {
22644 // Formatting code (indent the tree so it looks nice on the screen)
22645 var nopad = nopadtext;
22646 if (lastnode == 'SPAN') {
22650 if (currentElementChild.nodeName == '#text') {
22651 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22652 toadd = nopadtext ? toadd : toadd.trim();
22653 if (!nopad && toadd.length > 80) {
22654 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22656 innerHTML += toadd;
22659 currentElementChild = currentElement.childNodes.item(i);
22665 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22667 // Recursively traverse the tree structure of the child node
22668 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22669 lastnode = currentElementChild.nodeName;
22671 currentElementChild=currentElement.childNodes.item(i);
22677 // The remaining code is mostly for formatting the tree
22678 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22683 ret+= "</"+tagName+">";
22689 applyBlacklists : function()
22691 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22692 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22696 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22697 if (b.indexOf(tag) > -1) {
22700 this.white.push(tag);
22704 Roo.each(w, function(tag) {
22705 if (b.indexOf(tag) > -1) {
22708 if (this.white.indexOf(tag) > -1) {
22711 this.white.push(tag);
22716 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22717 if (w.indexOf(tag) > -1) {
22720 this.black.push(tag);
22724 Roo.each(b, function(tag) {
22725 if (w.indexOf(tag) > -1) {
22728 if (this.black.indexOf(tag) > -1) {
22731 this.black.push(tag);
22736 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22737 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22741 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22742 if (b.indexOf(tag) > -1) {
22745 this.cwhite.push(tag);
22749 Roo.each(w, function(tag) {
22750 if (b.indexOf(tag) > -1) {
22753 if (this.cwhite.indexOf(tag) > -1) {
22756 this.cwhite.push(tag);
22761 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22762 if (w.indexOf(tag) > -1) {
22765 this.cblack.push(tag);
22769 Roo.each(b, function(tag) {
22770 if (w.indexOf(tag) > -1) {
22773 if (this.cblack.indexOf(tag) > -1) {
22776 this.cblack.push(tag);
22781 setStylesheets : function(stylesheets)
22783 if(typeof(stylesheets) == 'string'){
22784 Roo.get(this.iframe.contentDocument.head).createChild({
22786 rel : 'stylesheet',
22795 Roo.each(stylesheets, function(s) {
22800 Roo.get(_this.iframe.contentDocument.head).createChild({
22802 rel : 'stylesheet',
22811 removeStylesheets : function()
22815 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22820 setStyle : function(style)
22822 Roo.get(this.iframe.contentDocument.head).createChild({
22831 // hide stuff that is not compatible
22845 * @event specialkey
22849 * @cfg {String} fieldClass @hide
22852 * @cfg {String} focusClass @hide
22855 * @cfg {String} autoCreate @hide
22858 * @cfg {String} inputType @hide
22861 * @cfg {String} invalidClass @hide
22864 * @cfg {String} invalidText @hide
22867 * @cfg {String} msgFx @hide
22870 * @cfg {String} validateOnBlur @hide
22874 Roo.HtmlEditorCore.white = [
22875 'area', 'br', 'img', 'input', 'hr', 'wbr',
22877 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22878 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22879 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22880 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22881 'table', 'ul', 'xmp',
22883 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22886 'dir', 'menu', 'ol', 'ul', 'dl',
22892 Roo.HtmlEditorCore.black = [
22893 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22895 'base', 'basefont', 'bgsound', 'blink', 'body',
22896 'frame', 'frameset', 'head', 'html', 'ilayer',
22897 'iframe', 'layer', 'link', 'meta', 'object',
22898 'script', 'style' ,'title', 'xml' // clean later..
22900 Roo.HtmlEditorCore.clean = [
22901 'script', 'style', 'title', 'xml'
22903 Roo.HtmlEditorCore.remove = [
22908 Roo.HtmlEditorCore.ablack = [
22912 Roo.HtmlEditorCore.aclean = [
22913 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22917 Roo.HtmlEditorCore.pwhite= [
22918 'http', 'https', 'mailto'
22921 // white listed style attributes.
22922 Roo.HtmlEditorCore.cwhite= [
22923 // 'text-align', /// default is to allow most things..
22929 // black listed style attributes.
22930 Roo.HtmlEditorCore.cblack= [
22931 // 'font-size' -- this can be set by the project
22935 Roo.HtmlEditorCore.swapCodes =[
22954 * @class Roo.bootstrap.HtmlEditor
22955 * @extends Roo.bootstrap.TextArea
22956 * Bootstrap HtmlEditor class
22959 * Create a new HtmlEditor
22960 * @param {Object} config The config object
22963 Roo.bootstrap.HtmlEditor = function(config){
22964 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22965 if (!this.toolbars) {
22966 this.toolbars = [];
22969 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22972 * @event initialize
22973 * Fires when the editor is fully initialized (including the iframe)
22974 * @param {HtmlEditor} this
22979 * Fires when the editor is first receives the focus. Any insertion must wait
22980 * until after this event.
22981 * @param {HtmlEditor} this
22985 * @event beforesync
22986 * Fires before the textarea is updated with content from the editor iframe. Return false
22987 * to cancel the sync.
22988 * @param {HtmlEditor} this
22989 * @param {String} html
22993 * @event beforepush
22994 * Fires before the iframe editor is updated with content from the textarea. Return false
22995 * to cancel the push.
22996 * @param {HtmlEditor} this
22997 * @param {String} html
23002 * Fires when the textarea is updated with content from the editor iframe.
23003 * @param {HtmlEditor} this
23004 * @param {String} html
23009 * Fires when the iframe editor is updated with content from the textarea.
23010 * @param {HtmlEditor} this
23011 * @param {String} html
23015 * @event editmodechange
23016 * Fires when the editor switches edit modes
23017 * @param {HtmlEditor} this
23018 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23020 editmodechange: true,
23022 * @event editorevent
23023 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23024 * @param {HtmlEditor} this
23028 * @event firstfocus
23029 * Fires when on first focus - needed by toolbars..
23030 * @param {HtmlEditor} this
23035 * Auto save the htmlEditor value as a file into Events
23036 * @param {HtmlEditor} this
23040 * @event savedpreview
23041 * preview the saved version of htmlEditor
23042 * @param {HtmlEditor} this
23049 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23053 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23058 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23063 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23068 * @cfg {Number} height (in pixels)
23072 * @cfg {Number} width (in pixels)
23077 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23080 stylesheets: false,
23085 // private properties
23086 validationEvent : false,
23088 initialized : false,
23091 onFocus : Roo.emptyFn,
23093 hideMode:'offsets',
23095 tbContainer : false,
23099 toolbarContainer :function() {
23100 return this.wrap.select('.x-html-editor-tb',true).first();
23104 * Protected method that will not generally be called directly. It
23105 * is called when the editor creates its toolbar. Override this method if you need to
23106 * add custom toolbar buttons.
23107 * @param {HtmlEditor} editor
23109 createToolbar : function(){
23110 Roo.log('renewing');
23111 Roo.log("create toolbars");
23113 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23114 this.toolbars[0].render(this.toolbarContainer());
23118 // if (!editor.toolbars || !editor.toolbars.length) {
23119 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23122 // for (var i =0 ; i < editor.toolbars.length;i++) {
23123 // editor.toolbars[i] = Roo.factory(
23124 // typeof(editor.toolbars[i]) == 'string' ?
23125 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23126 // Roo.bootstrap.HtmlEditor);
23127 // editor.toolbars[i].init(editor);
23133 onRender : function(ct, position)
23135 // Roo.log("Call onRender: " + this.xtype);
23137 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23139 this.wrap = this.inputEl().wrap({
23140 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23143 this.editorcore.onRender(ct, position);
23145 if (this.resizable) {
23146 this.resizeEl = new Roo.Resizable(this.wrap, {
23150 minHeight : this.height,
23151 height: this.height,
23152 handles : this.resizable,
23155 resize : function(r, w, h) {
23156 _t.onResize(w,h); // -something
23162 this.createToolbar(this);
23165 if(!this.width && this.resizable){
23166 this.setSize(this.wrap.getSize());
23168 if (this.resizeEl) {
23169 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23170 // should trigger onReize..
23176 onResize : function(w, h)
23178 Roo.log('resize: ' +w + ',' + h );
23179 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23183 if(this.inputEl() ){
23184 if(typeof w == 'number'){
23185 var aw = w - this.wrap.getFrameWidth('lr');
23186 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23189 if(typeof h == 'number'){
23190 var tbh = -11; // fixme it needs to tool bar size!
23191 for (var i =0; i < this.toolbars.length;i++) {
23192 // fixme - ask toolbars for heights?
23193 tbh += this.toolbars[i].el.getHeight();
23194 //if (this.toolbars[i].footer) {
23195 // tbh += this.toolbars[i].footer.el.getHeight();
23203 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23204 ah -= 5; // knock a few pixes off for look..
23205 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23209 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23210 this.editorcore.onResize(ew,eh);
23215 * Toggles the editor between standard and source edit mode.
23216 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23218 toggleSourceEdit : function(sourceEditMode)
23220 this.editorcore.toggleSourceEdit(sourceEditMode);
23222 if(this.editorcore.sourceEditMode){
23223 Roo.log('editor - showing textarea');
23226 // Roo.log(this.syncValue());
23228 this.inputEl().removeClass(['hide', 'x-hidden']);
23229 this.inputEl().dom.removeAttribute('tabIndex');
23230 this.inputEl().focus();
23232 Roo.log('editor - hiding textarea');
23234 // Roo.log(this.pushValue());
23237 this.inputEl().addClass(['hide', 'x-hidden']);
23238 this.inputEl().dom.setAttribute('tabIndex', -1);
23239 //this.deferFocus();
23242 if(this.resizable){
23243 this.setSize(this.wrap.getSize());
23246 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23249 // private (for BoxComponent)
23250 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23252 // private (for BoxComponent)
23253 getResizeEl : function(){
23257 // private (for BoxComponent)
23258 getPositionEl : function(){
23263 initEvents : function(){
23264 this.originalValue = this.getValue();
23268 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23271 // markInvalid : Roo.emptyFn,
23273 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23276 // clearInvalid : Roo.emptyFn,
23278 setValue : function(v){
23279 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23280 this.editorcore.pushValue();
23285 deferFocus : function(){
23286 this.focus.defer(10, this);
23290 focus : function(){
23291 this.editorcore.focus();
23297 onDestroy : function(){
23303 for (var i =0; i < this.toolbars.length;i++) {
23304 // fixme - ask toolbars for heights?
23305 this.toolbars[i].onDestroy();
23308 this.wrap.dom.innerHTML = '';
23309 this.wrap.remove();
23314 onFirstFocus : function(){
23315 //Roo.log("onFirstFocus");
23316 this.editorcore.onFirstFocus();
23317 for (var i =0; i < this.toolbars.length;i++) {
23318 this.toolbars[i].onFirstFocus();
23324 syncValue : function()
23326 this.editorcore.syncValue();
23329 pushValue : function()
23331 this.editorcore.pushValue();
23335 // hide stuff that is not compatible
23349 * @event specialkey
23353 * @cfg {String} fieldClass @hide
23356 * @cfg {String} focusClass @hide
23359 * @cfg {String} autoCreate @hide
23362 * @cfg {String} inputType @hide
23365 * @cfg {String} invalidClass @hide
23368 * @cfg {String} invalidText @hide
23371 * @cfg {String} msgFx @hide
23374 * @cfg {String} validateOnBlur @hide
23383 Roo.namespace('Roo.bootstrap.htmleditor');
23385 * @class Roo.bootstrap.HtmlEditorToolbar1
23390 new Roo.bootstrap.HtmlEditor({
23393 new Roo.bootstrap.HtmlEditorToolbar1({
23394 disable : { fonts: 1 , format: 1, ..., ... , ...],
23400 * @cfg {Object} disable List of elements to disable..
23401 * @cfg {Array} btns List of additional buttons.
23405 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23408 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23411 Roo.apply(this, config);
23413 // default disabled, based on 'good practice'..
23414 this.disable = this.disable || {};
23415 Roo.applyIf(this.disable, {
23418 specialElements : true
23420 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23422 this.editor = config.editor;
23423 this.editorcore = config.editor.editorcore;
23425 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23427 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23428 // dont call parent... till later.
23430 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23435 editorcore : false,
23440 "h1","h2","h3","h4","h5","h6",
23442 "abbr", "acronym", "address", "cite", "samp", "var",
23446 onRender : function(ct, position)
23448 // Roo.log("Call onRender: " + this.xtype);
23450 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23452 this.el.dom.style.marginBottom = '0';
23454 var editorcore = this.editorcore;
23455 var editor= this.editor;
23458 var btn = function(id,cmd , toggle, handler, html){
23460 var event = toggle ? 'toggle' : 'click';
23465 xns: Roo.bootstrap,
23468 enableToggle:toggle !== false,
23470 pressed : toggle ? false : null,
23473 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23474 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23480 // var cb_box = function...
23485 xns: Roo.bootstrap,
23486 glyphicon : 'font',
23490 xns: Roo.bootstrap,
23494 Roo.each(this.formats, function(f) {
23495 style.menu.items.push({
23497 xns: Roo.bootstrap,
23498 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23503 editorcore.insertTag(this.tagname);
23510 children.push(style);
23512 btn('bold',false,true);
23513 btn('italic',false,true);
23514 btn('align-left', 'justifyleft',true);
23515 btn('align-center', 'justifycenter',true);
23516 btn('align-right' , 'justifyright',true);
23517 btn('link', false, false, function(btn) {
23518 //Roo.log("create link?");
23519 var url = prompt(this.createLinkText, this.defaultLinkValue);
23520 if(url && url != 'http:/'+'/'){
23521 this.editorcore.relayCmd('createlink', url);
23524 btn('list','insertunorderedlist',true);
23525 btn('pencil', false,true, function(btn){
23527 this.toggleSourceEdit(btn.pressed);
23530 if (this.editor.btns.length > 0) {
23531 for (var i = 0; i<this.editor.btns.length; i++) {
23532 children.push(this.editor.btns[i]);
23540 xns: Roo.bootstrap,
23545 xns: Roo.bootstrap,
23550 cog.menu.items.push({
23552 xns: Roo.bootstrap,
23553 html : Clean styles,
23558 editorcore.insertTag(this.tagname);
23567 this.xtype = 'NavSimplebar';
23569 for(var i=0;i< children.length;i++) {
23571 this.buttons.add(this.addxtypeChild(children[i]));
23575 editor.on('editorevent', this.updateToolbar, this);
23577 onBtnClick : function(id)
23579 this.editorcore.relayCmd(id);
23580 this.editorcore.focus();
23584 * Protected method that will not generally be called directly. It triggers
23585 * a toolbar update by reading the markup state of the current selection in the editor.
23587 updateToolbar: function(){
23589 if(!this.editorcore.activated){
23590 this.editor.onFirstFocus(); // is this neeed?
23594 var btns = this.buttons;
23595 var doc = this.editorcore.doc;
23596 btns.get('bold').setActive(doc.queryCommandState('bold'));
23597 btns.get('italic').setActive(doc.queryCommandState('italic'));
23598 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23600 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23601 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23602 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23604 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23605 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23608 var ans = this.editorcore.getAllAncestors();
23609 if (this.formatCombo) {
23612 var store = this.formatCombo.store;
23613 this.formatCombo.setValue("");
23614 for (var i =0; i < ans.length;i++) {
23615 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23617 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23625 // hides menus... - so this cant be on a menu...
23626 Roo.bootstrap.MenuMgr.hideAll();
23628 Roo.bootstrap.MenuMgr.hideAll();
23629 //this.editorsyncValue();
23631 onFirstFocus: function() {
23632 this.buttons.each(function(item){
23636 toggleSourceEdit : function(sourceEditMode){
23639 if(sourceEditMode){
23640 Roo.log("disabling buttons");
23641 this.buttons.each( function(item){
23642 if(item.cmd != 'pencil'){
23648 Roo.log("enabling buttons");
23649 if(this.editorcore.initialized){
23650 this.buttons.each( function(item){
23656 Roo.log("calling toggole on editor");
23657 // tell the editor that it's been pressed..
23658 this.editor.toggleSourceEdit(sourceEditMode);
23668 * @class Roo.bootstrap.Table.AbstractSelectionModel
23669 * @extends Roo.util.Observable
23670 * Abstract base class for grid SelectionModels. It provides the interface that should be
23671 * implemented by descendant classes. This class should not be directly instantiated.
23674 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23675 this.locked = false;
23676 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23680 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23681 /** @ignore Called by the grid automatically. Do not call directly. */
23682 init : function(grid){
23688 * Locks the selections.
23691 this.locked = true;
23695 * Unlocks the selections.
23697 unlock : function(){
23698 this.locked = false;
23702 * Returns true if the selections are locked.
23703 * @return {Boolean}
23705 isLocked : function(){
23706 return this.locked;
23710 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23711 * @class Roo.bootstrap.Table.RowSelectionModel
23712 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23713 * It supports multiple selections and keyboard selection/navigation.
23715 * @param {Object} config
23718 Roo.bootstrap.Table.RowSelectionModel = function(config){
23719 Roo.apply(this, config);
23720 this.selections = new Roo.util.MixedCollection(false, function(o){
23725 this.lastActive = false;
23729 * @event selectionchange
23730 * Fires when the selection changes
23731 * @param {SelectionModel} this
23733 "selectionchange" : true,
23735 * @event afterselectionchange
23736 * Fires after the selection changes (eg. by key press or clicking)
23737 * @param {SelectionModel} this
23739 "afterselectionchange" : true,
23741 * @event beforerowselect
23742 * Fires when a row is selected being selected, return false to cancel.
23743 * @param {SelectionModel} this
23744 * @param {Number} rowIndex The selected index
23745 * @param {Boolean} keepExisting False if other selections will be cleared
23747 "beforerowselect" : true,
23750 * Fires when a row is selected.
23751 * @param {SelectionModel} this
23752 * @param {Number} rowIndex The selected index
23753 * @param {Roo.data.Record} r The record
23755 "rowselect" : true,
23757 * @event rowdeselect
23758 * Fires when a row is deselected.
23759 * @param {SelectionModel} this
23760 * @param {Number} rowIndex The selected index
23762 "rowdeselect" : true
23764 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23765 this.locked = false;
23768 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23770 * @cfg {Boolean} singleSelect
23771 * True to allow selection of only one row at a time (defaults to false)
23773 singleSelect : false,
23776 initEvents : function()
23779 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23780 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23781 //}else{ // allow click to work like normal
23782 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23784 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23785 this.grid.on("rowclick", this.handleMouseDown, this);
23787 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23788 "up" : function(e){
23790 this.selectPrevious(e.shiftKey);
23791 }else if(this.last !== false && this.lastActive !== false){
23792 var last = this.last;
23793 this.selectRange(this.last, this.lastActive-1);
23794 this.grid.getView().focusRow(this.lastActive);
23795 if(last !== false){
23799 this.selectFirstRow();
23801 this.fireEvent("afterselectionchange", this);
23803 "down" : function(e){
23805 this.selectNext(e.shiftKey);
23806 }else if(this.last !== false && this.lastActive !== false){
23807 var last = this.last;
23808 this.selectRange(this.last, this.lastActive+1);
23809 this.grid.getView().focusRow(this.lastActive);
23810 if(last !== false){
23814 this.selectFirstRow();
23816 this.fireEvent("afterselectionchange", this);
23820 this.grid.store.on('load', function(){
23821 this.selections.clear();
23824 var view = this.grid.view;
23825 view.on("refresh", this.onRefresh, this);
23826 view.on("rowupdated", this.onRowUpdated, this);
23827 view.on("rowremoved", this.onRemove, this);
23832 onRefresh : function()
23834 var ds = this.grid.store, i, v = this.grid.view;
23835 var s = this.selections;
23836 s.each(function(r){
23837 if((i = ds.indexOfId(r.id)) != -1){
23846 onRemove : function(v, index, r){
23847 this.selections.remove(r);
23851 onRowUpdated : function(v, index, r){
23852 if(this.isSelected(r)){
23853 v.onRowSelect(index);
23859 * @param {Array} records The records to select
23860 * @param {Boolean} keepExisting (optional) True to keep existing selections
23862 selectRecords : function(records, keepExisting)
23865 this.clearSelections();
23867 var ds = this.grid.store;
23868 for(var i = 0, len = records.length; i < len; i++){
23869 this.selectRow(ds.indexOf(records[i]), true);
23874 * Gets the number of selected rows.
23877 getCount : function(){
23878 return this.selections.length;
23882 * Selects the first row in the grid.
23884 selectFirstRow : function(){
23889 * Select the last row.
23890 * @param {Boolean} keepExisting (optional) True to keep existing selections
23892 selectLastRow : function(keepExisting){
23893 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23894 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23898 * Selects the row immediately following the last selected row.
23899 * @param {Boolean} keepExisting (optional) True to keep existing selections
23901 selectNext : function(keepExisting)
23903 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23904 this.selectRow(this.last+1, keepExisting);
23905 this.grid.getView().focusRow(this.last);
23910 * Selects the row that precedes the last selected row.
23911 * @param {Boolean} keepExisting (optional) True to keep existing selections
23913 selectPrevious : function(keepExisting){
23915 this.selectRow(this.last-1, keepExisting);
23916 this.grid.getView().focusRow(this.last);
23921 * Returns the selected records
23922 * @return {Array} Array of selected records
23924 getSelections : function(){
23925 return [].concat(this.selections.items);
23929 * Returns the first selected record.
23932 getSelected : function(){
23933 return this.selections.itemAt(0);
23938 * Clears all selections.
23940 clearSelections : function(fast)
23946 var ds = this.grid.store;
23947 var s = this.selections;
23948 s.each(function(r){
23949 this.deselectRow(ds.indexOfId(r.id));
23953 this.selections.clear();
23960 * Selects all rows.
23962 selectAll : function(){
23966 this.selections.clear();
23967 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23968 this.selectRow(i, true);
23973 * Returns True if there is a selection.
23974 * @return {Boolean}
23976 hasSelection : function(){
23977 return this.selections.length > 0;
23981 * Returns True if the specified row is selected.
23982 * @param {Number/Record} record The record or index of the record to check
23983 * @return {Boolean}
23985 isSelected : function(index){
23986 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23987 return (r && this.selections.key(r.id) ? true : false);
23991 * Returns True if the specified record id is selected.
23992 * @param {String} id The id of record to check
23993 * @return {Boolean}
23995 isIdSelected : function(id){
23996 return (this.selections.key(id) ? true : false);
24001 handleMouseDBClick : function(e, t){
24005 handleMouseDown : function(e, t)
24007 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24008 if(this.isLocked() || rowIndex < 0 ){
24011 if(e.shiftKey && this.last !== false){
24012 var last = this.last;
24013 this.selectRange(last, rowIndex, e.ctrlKey);
24014 this.last = last; // reset the last
24018 var isSelected = this.isSelected(rowIndex);
24019 //Roo.log("select row:" + rowIndex);
24021 this.deselectRow(rowIndex);
24023 this.selectRow(rowIndex, true);
24027 if(e.button !== 0 && isSelected){
24028 alert('rowIndex 2: ' + rowIndex);
24029 view.focusRow(rowIndex);
24030 }else if(e.ctrlKey && isSelected){
24031 this.deselectRow(rowIndex);
24032 }else if(!isSelected){
24033 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24034 view.focusRow(rowIndex);
24038 this.fireEvent("afterselectionchange", this);
24041 handleDragableRowClick : function(grid, rowIndex, e)
24043 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24044 this.selectRow(rowIndex, false);
24045 grid.view.focusRow(rowIndex);
24046 this.fireEvent("afterselectionchange", this);
24051 * Selects multiple rows.
24052 * @param {Array} rows Array of the indexes of the row to select
24053 * @param {Boolean} keepExisting (optional) True to keep existing selections
24055 selectRows : function(rows, keepExisting){
24057 this.clearSelections();
24059 for(var i = 0, len = rows.length; i < len; i++){
24060 this.selectRow(rows[i], true);
24065 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24066 * @param {Number} startRow The index of the first row in the range
24067 * @param {Number} endRow The index of the last row in the range
24068 * @param {Boolean} keepExisting (optional) True to retain existing selections
24070 selectRange : function(startRow, endRow, keepExisting){
24075 this.clearSelections();
24077 if(startRow <= endRow){
24078 for(var i = startRow; i <= endRow; i++){
24079 this.selectRow(i, true);
24082 for(var i = startRow; i >= endRow; i--){
24083 this.selectRow(i, true);
24089 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24090 * @param {Number} startRow The index of the first row in the range
24091 * @param {Number} endRow The index of the last row in the range
24093 deselectRange : function(startRow, endRow, preventViewNotify){
24097 for(var i = startRow; i <= endRow; i++){
24098 this.deselectRow(i, preventViewNotify);
24104 * @param {Number} row The index of the row to select
24105 * @param {Boolean} keepExisting (optional) True to keep existing selections
24107 selectRow : function(index, keepExisting, preventViewNotify)
24109 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24112 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24113 if(!keepExisting || this.singleSelect){
24114 this.clearSelections();
24117 var r = this.grid.store.getAt(index);
24118 //console.log('selectRow - record id :' + r.id);
24120 this.selections.add(r);
24121 this.last = this.lastActive = index;
24122 if(!preventViewNotify){
24123 var proxy = new Roo.Element(
24124 this.grid.getRowDom(index)
24126 proxy.addClass('bg-info info');
24128 this.fireEvent("rowselect", this, index, r);
24129 this.fireEvent("selectionchange", this);
24135 * @param {Number} row The index of the row to deselect
24137 deselectRow : function(index, preventViewNotify)
24142 if(this.last == index){
24145 if(this.lastActive == index){
24146 this.lastActive = false;
24149 var r = this.grid.store.getAt(index);
24154 this.selections.remove(r);
24155 //.console.log('deselectRow - record id :' + r.id);
24156 if(!preventViewNotify){
24158 var proxy = new Roo.Element(
24159 this.grid.getRowDom(index)
24161 proxy.removeClass('bg-info info');
24163 this.fireEvent("rowdeselect", this, index);
24164 this.fireEvent("selectionchange", this);
24168 restoreLast : function(){
24170 this.last = this._last;
24175 acceptsNav : function(row, col, cm){
24176 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24180 onEditorKey : function(field, e){
24181 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24186 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24188 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24190 }else if(k == e.ENTER && !e.ctrlKey){
24194 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24196 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24198 }else if(k == e.ESC){
24202 g.startEditing(newCell[0], newCell[1]);
24208 * Ext JS Library 1.1.1
24209 * Copyright(c) 2006-2007, Ext JS, LLC.
24211 * Originally Released Under LGPL - original licence link has changed is not relivant.
24214 * <script type="text/javascript">
24218 * @class Roo.bootstrap.PagingToolbar
24219 * @extends Roo.bootstrap.NavSimplebar
24220 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24222 * Create a new PagingToolbar
24223 * @param {Object} config The config object
24224 * @param {Roo.data.Store} store
24226 Roo.bootstrap.PagingToolbar = function(config)
24228 // old args format still supported... - xtype is prefered..
24229 // created from xtype...
24231 this.ds = config.dataSource;
24233 if (config.store && !this.ds) {
24234 this.store= Roo.factory(config.store, Roo.data);
24235 this.ds = this.store;
24236 this.ds.xmodule = this.xmodule || false;
24239 this.toolbarItems = [];
24240 if (config.items) {
24241 this.toolbarItems = config.items;
24244 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24249 this.bind(this.ds);
24252 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24256 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24258 * @cfg {Roo.data.Store} dataSource
24259 * The underlying data store providing the paged data
24262 * @cfg {String/HTMLElement/Element} container
24263 * container The id or element that will contain the toolbar
24266 * @cfg {Boolean} displayInfo
24267 * True to display the displayMsg (defaults to false)
24270 * @cfg {Number} pageSize
24271 * The number of records to display per page (defaults to 20)
24275 * @cfg {String} displayMsg
24276 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24278 displayMsg : 'Displaying {0} - {1} of {2}',
24280 * @cfg {String} emptyMsg
24281 * The message to display when no records are found (defaults to "No data to display")
24283 emptyMsg : 'No data to display',
24285 * Customizable piece of the default paging text (defaults to "Page")
24288 beforePageText : "Page",
24290 * Customizable piece of the default paging text (defaults to "of %0")
24293 afterPageText : "of {0}",
24295 * Customizable piece of the default paging text (defaults to "First Page")
24298 firstText : "First Page",
24300 * Customizable piece of the default paging text (defaults to "Previous Page")
24303 prevText : "Previous Page",
24305 * Customizable piece of the default paging text (defaults to "Next Page")
24308 nextText : "Next Page",
24310 * Customizable piece of the default paging text (defaults to "Last Page")
24313 lastText : "Last Page",
24315 * Customizable piece of the default paging text (defaults to "Refresh")
24318 refreshText : "Refresh",
24322 onRender : function(ct, position)
24324 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24325 this.navgroup.parentId = this.id;
24326 this.navgroup.onRender(this.el, null);
24327 // add the buttons to the navgroup
24329 if(this.displayInfo){
24330 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24331 this.displayEl = this.el.select('.x-paging-info', true).first();
24332 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24333 // this.displayEl = navel.el.select('span',true).first();
24339 Roo.each(_this.buttons, function(e){ // this might need to use render????
24340 Roo.factory(e).onRender(_this.el, null);
24344 Roo.each(_this.toolbarItems, function(e) {
24345 _this.navgroup.addItem(e);
24349 this.first = this.navgroup.addItem({
24350 tooltip: this.firstText,
24352 icon : 'fa fa-backward',
24354 preventDefault: true,
24355 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24358 this.prev = this.navgroup.addItem({
24359 tooltip: this.prevText,
24361 icon : 'fa fa-step-backward',
24363 preventDefault: true,
24364 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24366 //this.addSeparator();
24369 var field = this.navgroup.addItem( {
24371 cls : 'x-paging-position',
24373 html : this.beforePageText +
24374 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24375 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24378 this.field = field.el.select('input', true).first();
24379 this.field.on("keydown", this.onPagingKeydown, this);
24380 this.field.on("focus", function(){this.dom.select();});
24383 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24384 //this.field.setHeight(18);
24385 //this.addSeparator();
24386 this.next = this.navgroup.addItem({
24387 tooltip: this.nextText,
24389 html : ' <i class="fa fa-step-forward">',
24391 preventDefault: true,
24392 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24394 this.last = this.navgroup.addItem({
24395 tooltip: this.lastText,
24396 icon : 'fa fa-forward',
24399 preventDefault: true,
24400 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24402 //this.addSeparator();
24403 this.loading = this.navgroup.addItem({
24404 tooltip: this.refreshText,
24405 icon: 'fa fa-refresh',
24406 preventDefault: true,
24407 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24413 updateInfo : function(){
24414 if(this.displayEl){
24415 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24416 var msg = count == 0 ?
24420 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24422 this.displayEl.update(msg);
24427 onLoad : function(ds, r, o)
24429 this.cursor = o.params ? o.params.start : 0;
24430 var d = this.getPageData(),
24435 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24436 this.field.dom.value = ap;
24437 this.first.setDisabled(ap == 1);
24438 this.prev.setDisabled(ap == 1);
24439 this.next.setDisabled(ap == ps);
24440 this.last.setDisabled(ap == ps);
24441 this.loading.enable();
24446 getPageData : function(){
24447 var total = this.ds.getTotalCount();
24450 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24451 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24456 onLoadError : function(){
24457 this.loading.enable();
24461 onPagingKeydown : function(e){
24462 var k = e.getKey();
24463 var d = this.getPageData();
24465 var v = this.field.dom.value, pageNum;
24466 if(!v || isNaN(pageNum = parseInt(v, 10))){
24467 this.field.dom.value = d.activePage;
24470 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24471 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24474 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))
24476 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24477 this.field.dom.value = pageNum;
24478 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24481 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24483 var v = this.field.dom.value, pageNum;
24484 var increment = (e.shiftKey) ? 10 : 1;
24485 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24488 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24489 this.field.dom.value = d.activePage;
24492 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24494 this.field.dom.value = parseInt(v, 10) + increment;
24495 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24496 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24503 beforeLoad : function(){
24505 this.loading.disable();
24510 onClick : function(which){
24519 ds.load({params:{start: 0, limit: this.pageSize}});
24522 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24525 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24528 var total = ds.getTotalCount();
24529 var extra = total % this.pageSize;
24530 var lastStart = extra ? (total - extra) : total-this.pageSize;
24531 ds.load({params:{start: lastStart, limit: this.pageSize}});
24534 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24540 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24541 * @param {Roo.data.Store} store The data store to unbind
24543 unbind : function(ds){
24544 ds.un("beforeload", this.beforeLoad, this);
24545 ds.un("load", this.onLoad, this);
24546 ds.un("loadexception", this.onLoadError, this);
24547 ds.un("remove", this.updateInfo, this);
24548 ds.un("add", this.updateInfo, this);
24549 this.ds = undefined;
24553 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24554 * @param {Roo.data.Store} store The data store to bind
24556 bind : function(ds){
24557 ds.on("beforeload", this.beforeLoad, this);
24558 ds.on("load", this.onLoad, this);
24559 ds.on("loadexception", this.onLoadError, this);
24560 ds.on("remove", this.updateInfo, this);
24561 ds.on("add", this.updateInfo, this);
24572 * @class Roo.bootstrap.MessageBar
24573 * @extends Roo.bootstrap.Component
24574 * Bootstrap MessageBar class
24575 * @cfg {String} html contents of the MessageBar
24576 * @cfg {String} weight (info | success | warning | danger) default info
24577 * @cfg {String} beforeClass insert the bar before the given class
24578 * @cfg {Boolean} closable (true | false) default false
24579 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24582 * Create a new Element
24583 * @param {Object} config The config object
24586 Roo.bootstrap.MessageBar = function(config){
24587 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24590 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24596 beforeClass: 'bootstrap-sticky-wrap',
24598 getAutoCreate : function(){
24602 cls: 'alert alert-dismissable alert-' + this.weight,
24607 html: this.html || ''
24613 cfg.cls += ' alert-messages-fixed';
24627 onRender : function(ct, position)
24629 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24632 var cfg = Roo.apply({}, this.getAutoCreate());
24636 cfg.cls += ' ' + this.cls;
24639 cfg.style = this.style;
24641 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24643 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24646 this.el.select('>button.close').on('click', this.hide, this);
24652 if (!this.rendered) {
24658 this.fireEvent('show', this);
24664 if (!this.rendered) {
24670 this.fireEvent('hide', this);
24673 update : function()
24675 // var e = this.el.dom.firstChild;
24677 // if(this.closable){
24678 // e = e.nextSibling;
24681 // e.data = this.html || '';
24683 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24699 * @class Roo.bootstrap.Graph
24700 * @extends Roo.bootstrap.Component
24701 * Bootstrap Graph class
24705 @cfg {String} graphtype bar | vbar | pie
24706 @cfg {number} g_x coodinator | centre x (pie)
24707 @cfg {number} g_y coodinator | centre y (pie)
24708 @cfg {number} g_r radius (pie)
24709 @cfg {number} g_height height of the chart (respected by all elements in the set)
24710 @cfg {number} g_width width of the chart (respected by all elements in the set)
24711 @cfg {Object} title The title of the chart
24714 -opts (object) options for the chart
24716 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24717 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24719 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.
24720 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24722 o stretch (boolean)
24724 -opts (object) options for the pie
24727 o startAngle (number)
24728 o endAngle (number)
24732 * Create a new Input
24733 * @param {Object} config The config object
24736 Roo.bootstrap.Graph = function(config){
24737 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24743 * The img click event for the img.
24744 * @param {Roo.EventObject} e
24750 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24761 //g_colors: this.colors,
24768 getAutoCreate : function(){
24779 onRender : function(ct,position){
24782 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24784 if (typeof(Raphael) == 'undefined') {
24785 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24789 this.raphael = Raphael(this.el.dom);
24791 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24792 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24793 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24794 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24796 r.text(160, 10, "Single Series Chart").attr(txtattr);
24797 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24798 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24799 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24801 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24802 r.barchart(330, 10, 300, 220, data1);
24803 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24804 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24807 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24808 // r.barchart(30, 30, 560, 250, xdata, {
24809 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24810 // axis : "0 0 1 1",
24811 // axisxlabels : xdata
24812 // //yvalues : cols,
24815 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24817 // this.load(null,xdata,{
24818 // axis : "0 0 1 1",
24819 // axisxlabels : xdata
24824 load : function(graphtype,xdata,opts)
24826 this.raphael.clear();
24828 graphtype = this.graphtype;
24833 var r = this.raphael,
24834 fin = function () {
24835 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24837 fout = function () {
24838 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24840 pfin = function() {
24841 this.sector.stop();
24842 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24845 this.label[0].stop();
24846 this.label[0].attr({ r: 7.5 });
24847 this.label[1].attr({ "font-weight": 800 });
24850 pfout = function() {
24851 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24854 this.label[0].animate({ r: 5 }, 500, "bounce");
24855 this.label[1].attr({ "font-weight": 400 });
24861 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24864 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24867 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24868 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24870 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24877 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24882 setTitle: function(o)
24887 initEvents: function() {
24890 this.el.on('click', this.onClick, this);
24894 onClick : function(e)
24896 Roo.log('img onclick');
24897 this.fireEvent('click', this, e);
24909 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24912 * @class Roo.bootstrap.dash.NumberBox
24913 * @extends Roo.bootstrap.Component
24914 * Bootstrap NumberBox class
24915 * @cfg {String} headline Box headline
24916 * @cfg {String} content Box content
24917 * @cfg {String} icon Box icon
24918 * @cfg {String} footer Footer text
24919 * @cfg {String} fhref Footer href
24922 * Create a new NumberBox
24923 * @param {Object} config The config object
24927 Roo.bootstrap.dash.NumberBox = function(config){
24928 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24932 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24941 getAutoCreate : function(){
24945 cls : 'small-box ',
24953 cls : 'roo-headline',
24954 html : this.headline
24958 cls : 'roo-content',
24959 html : this.content
24973 cls : 'ion ' + this.icon
24982 cls : 'small-box-footer',
24983 href : this.fhref || '#',
24987 cfg.cn.push(footer);
24994 onRender : function(ct,position){
24995 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25002 setHeadline: function (value)
25004 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25007 setFooter: function (value, href)
25009 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25012 this.el.select('a.small-box-footer',true).first().attr('href', href);
25017 setContent: function (value)
25019 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25022 initEvents: function()
25036 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25039 * @class Roo.bootstrap.dash.TabBox
25040 * @extends Roo.bootstrap.Component
25041 * Bootstrap TabBox class
25042 * @cfg {String} title Title of the TabBox
25043 * @cfg {String} icon Icon of the TabBox
25044 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25045 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25048 * Create a new TabBox
25049 * @param {Object} config The config object
25053 Roo.bootstrap.dash.TabBox = function(config){
25054 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25059 * When a pane is added
25060 * @param {Roo.bootstrap.dash.TabPane} pane
25064 * @event activatepane
25065 * When a pane is activated
25066 * @param {Roo.bootstrap.dash.TabPane} pane
25068 "activatepane" : true
25076 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25081 tabScrollable : false,
25083 getChildContainer : function()
25085 return this.el.select('.tab-content', true).first();
25088 getAutoCreate : function(){
25092 cls: 'pull-left header',
25100 cls: 'fa ' + this.icon
25106 cls: 'nav nav-tabs pull-right',
25112 if(this.tabScrollable){
25119 cls: 'nav nav-tabs pull-right',
25130 cls: 'nav-tabs-custom',
25135 cls: 'tab-content no-padding',
25143 initEvents : function()
25145 //Roo.log('add add pane handler');
25146 this.on('addpane', this.onAddPane, this);
25149 * Updates the box title
25150 * @param {String} html to set the title to.
25152 setTitle : function(value)
25154 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25156 onAddPane : function(pane)
25158 this.panes.push(pane);
25159 //Roo.log('addpane');
25161 // tabs are rendere left to right..
25162 if(!this.showtabs){
25166 var ctr = this.el.select('.nav-tabs', true).first();
25169 var existing = ctr.select('.nav-tab',true);
25170 var qty = existing.getCount();;
25173 var tab = ctr.createChild({
25175 cls : 'nav-tab' + (qty ? '' : ' active'),
25183 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25186 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25188 pane.el.addClass('active');
25193 onTabClick : function(ev,un,ob,pane)
25195 //Roo.log('tab - prev default');
25196 ev.preventDefault();
25199 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25200 pane.tab.addClass('active');
25201 //Roo.log(pane.title);
25202 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25203 // technically we should have a deactivate event.. but maybe add later.
25204 // and it should not de-activate the selected tab...
25205 this.fireEvent('activatepane', pane);
25206 pane.el.addClass('active');
25207 pane.fireEvent('activate');
25212 getActivePane : function()
25215 Roo.each(this.panes, function(p) {
25216 if(p.el.hasClass('active')){
25237 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25239 * @class Roo.bootstrap.TabPane
25240 * @extends Roo.bootstrap.Component
25241 * Bootstrap TabPane class
25242 * @cfg {Boolean} active (false | true) Default false
25243 * @cfg {String} title title of panel
25247 * Create a new TabPane
25248 * @param {Object} config The config object
25251 Roo.bootstrap.dash.TabPane = function(config){
25252 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25258 * When a pane is activated
25259 * @param {Roo.bootstrap.dash.TabPane} pane
25266 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25271 // the tabBox that this is attached to.
25274 getAutoCreate : function()
25282 cfg.cls += ' active';
25287 initEvents : function()
25289 //Roo.log('trigger add pane handler');
25290 this.parent().fireEvent('addpane', this)
25294 * Updates the tab title
25295 * @param {String} html to set the title to.
25297 setTitle: function(str)
25303 this.tab.select('a', true).first().dom.innerHTML = str;
25320 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25323 * @class Roo.bootstrap.menu.Menu
25324 * @extends Roo.bootstrap.Component
25325 * Bootstrap Menu class - container for Menu
25326 * @cfg {String} html Text of the menu
25327 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25328 * @cfg {String} icon Font awesome icon
25329 * @cfg {String} pos Menu align to (top | bottom) default bottom
25333 * Create a new Menu
25334 * @param {Object} config The config object
25338 Roo.bootstrap.menu.Menu = function(config){
25339 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25343 * @event beforeshow
25344 * Fires before this menu is displayed
25345 * @param {Roo.bootstrap.menu.Menu} this
25349 * @event beforehide
25350 * Fires before this menu is hidden
25351 * @param {Roo.bootstrap.menu.Menu} this
25356 * Fires after this menu is displayed
25357 * @param {Roo.bootstrap.menu.Menu} this
25362 * Fires after this menu is hidden
25363 * @param {Roo.bootstrap.menu.Menu} this
25368 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25369 * @param {Roo.bootstrap.menu.Menu} this
25370 * @param {Roo.EventObject} e
25377 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25381 weight : 'default',
25386 getChildContainer : function() {
25387 if(this.isSubMenu){
25391 return this.el.select('ul.dropdown-menu', true).first();
25394 getAutoCreate : function()
25399 cls : 'roo-menu-text',
25407 cls : 'fa ' + this.icon
25418 cls : 'dropdown-button btn btn-' + this.weight,
25423 cls : 'dropdown-toggle btn btn-' + this.weight,
25433 cls : 'dropdown-menu'
25439 if(this.pos == 'top'){
25440 cfg.cls += ' dropup';
25443 if(this.isSubMenu){
25446 cls : 'dropdown-menu'
25453 onRender : function(ct, position)
25455 this.isSubMenu = ct.hasClass('dropdown-submenu');
25457 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25460 initEvents : function()
25462 if(this.isSubMenu){
25466 this.hidden = true;
25468 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25469 this.triggerEl.on('click', this.onTriggerPress, this);
25471 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25472 this.buttonEl.on('click', this.onClick, this);
25478 if(this.isSubMenu){
25482 return this.el.select('ul.dropdown-menu', true).first();
25485 onClick : function(e)
25487 this.fireEvent("click", this, e);
25490 onTriggerPress : function(e)
25492 if (this.isVisible()) {
25499 isVisible : function(){
25500 return !this.hidden;
25505 this.fireEvent("beforeshow", this);
25507 this.hidden = false;
25508 this.el.addClass('open');
25510 Roo.get(document).on("mouseup", this.onMouseUp, this);
25512 this.fireEvent("show", this);
25519 this.fireEvent("beforehide", this);
25521 this.hidden = true;
25522 this.el.removeClass('open');
25524 Roo.get(document).un("mouseup", this.onMouseUp);
25526 this.fireEvent("hide", this);
25529 onMouseUp : function()
25543 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25546 * @class Roo.bootstrap.menu.Item
25547 * @extends Roo.bootstrap.Component
25548 * Bootstrap MenuItem class
25549 * @cfg {Boolean} submenu (true | false) default false
25550 * @cfg {String} html text of the item
25551 * @cfg {String} href the link
25552 * @cfg {Boolean} disable (true | false) default false
25553 * @cfg {Boolean} preventDefault (true | false) default true
25554 * @cfg {String} icon Font awesome icon
25555 * @cfg {String} pos Submenu align to (left | right) default right
25559 * Create a new Item
25560 * @param {Object} config The config object
25564 Roo.bootstrap.menu.Item = function(config){
25565 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25569 * Fires when the mouse is hovering over this menu
25570 * @param {Roo.bootstrap.menu.Item} this
25571 * @param {Roo.EventObject} e
25576 * Fires when the mouse exits this menu
25577 * @param {Roo.bootstrap.menu.Item} this
25578 * @param {Roo.EventObject} e
25584 * The raw click event for the entire grid.
25585 * @param {Roo.EventObject} e
25591 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25596 preventDefault: true,
25601 getAutoCreate : function()
25606 cls : 'roo-menu-item-text',
25614 cls : 'fa ' + this.icon
25623 href : this.href || '#',
25630 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25634 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25636 if(this.pos == 'left'){
25637 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25644 initEvents : function()
25646 this.el.on('mouseover', this.onMouseOver, this);
25647 this.el.on('mouseout', this.onMouseOut, this);
25649 this.el.select('a', true).first().on('click', this.onClick, this);
25653 onClick : function(e)
25655 if(this.preventDefault){
25656 e.preventDefault();
25659 this.fireEvent("click", this, e);
25662 onMouseOver : function(e)
25664 if(this.submenu && this.pos == 'left'){
25665 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25668 this.fireEvent("mouseover", this, e);
25671 onMouseOut : function(e)
25673 this.fireEvent("mouseout", this, e);
25685 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25688 * @class Roo.bootstrap.menu.Separator
25689 * @extends Roo.bootstrap.Component
25690 * Bootstrap Separator class
25693 * Create a new Separator
25694 * @param {Object} config The config object
25698 Roo.bootstrap.menu.Separator = function(config){
25699 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25702 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25704 getAutoCreate : function(){
25725 * @class Roo.bootstrap.Tooltip
25726 * Bootstrap Tooltip class
25727 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25728 * to determine which dom element triggers the tooltip.
25730 * It needs to add support for additional attributes like tooltip-position
25733 * Create a new Toolti
25734 * @param {Object} config The config object
25737 Roo.bootstrap.Tooltip = function(config){
25738 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25740 this.alignment = Roo.bootstrap.Tooltip.alignment;
25742 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25743 this.alignment = config.alignment;
25748 Roo.apply(Roo.bootstrap.Tooltip, {
25750 * @function init initialize tooltip monitoring.
25754 currentTip : false,
25755 currentRegion : false,
25761 Roo.get(document).on('mouseover', this.enter ,this);
25762 Roo.get(document).on('mouseout', this.leave, this);
25765 this.currentTip = new Roo.bootstrap.Tooltip();
25768 enter : function(ev)
25770 var dom = ev.getTarget();
25772 //Roo.log(['enter',dom]);
25773 var el = Roo.fly(dom);
25774 if (this.currentEl) {
25776 //Roo.log(this.currentEl);
25777 //Roo.log(this.currentEl.contains(dom));
25778 if (this.currentEl == el) {
25781 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25787 if (this.currentTip.el) {
25788 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25792 if(!el || el.dom == document){
25798 // you can not look for children, as if el is the body.. then everythign is the child..
25799 if (!el.attr('tooltip')) { //
25800 if (!el.select("[tooltip]").elements.length) {
25803 // is the mouse over this child...?
25804 bindEl = el.select("[tooltip]").first();
25805 var xy = ev.getXY();
25806 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25807 //Roo.log("not in region.");
25810 //Roo.log("child element over..");
25813 this.currentEl = bindEl;
25814 this.currentTip.bind(bindEl);
25815 this.currentRegion = Roo.lib.Region.getRegion(dom);
25816 this.currentTip.enter();
25819 leave : function(ev)
25821 var dom = ev.getTarget();
25822 //Roo.log(['leave',dom]);
25823 if (!this.currentEl) {
25828 if (dom != this.currentEl.dom) {
25831 var xy = ev.getXY();
25832 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25835 // only activate leave if mouse cursor is outside... bounding box..
25840 if (this.currentTip) {
25841 this.currentTip.leave();
25843 //Roo.log('clear currentEl');
25844 this.currentEl = false;
25849 'left' : ['r-l', [-2,0], 'right'],
25850 'right' : ['l-r', [2,0], 'left'],
25851 'bottom' : ['t-b', [0,2], 'top'],
25852 'top' : [ 'b-t', [0,-2], 'bottom']
25858 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25863 delay : null, // can be { show : 300 , hide: 500}
25867 hoverState : null, //???
25869 placement : 'bottom',
25873 getAutoCreate : function(){
25880 cls : 'tooltip-arrow'
25883 cls : 'tooltip-inner'
25890 bind : function(el)
25896 enter : function () {
25898 if (this.timeout != null) {
25899 clearTimeout(this.timeout);
25902 this.hoverState = 'in';
25903 //Roo.log("enter - show");
25904 if (!this.delay || !this.delay.show) {
25909 this.timeout = setTimeout(function () {
25910 if (_t.hoverState == 'in') {
25913 }, this.delay.show);
25917 clearTimeout(this.timeout);
25919 this.hoverState = 'out';
25920 if (!this.delay || !this.delay.hide) {
25926 this.timeout = setTimeout(function () {
25927 //Roo.log("leave - timeout");
25929 if (_t.hoverState == 'out') {
25931 Roo.bootstrap.Tooltip.currentEl = false;
25936 show : function (msg)
25939 this.render(document.body);
25942 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25944 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25946 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25948 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25950 var placement = typeof this.placement == 'function' ?
25951 this.placement.call(this, this.el, on_el) :
25954 var autoToken = /\s?auto?\s?/i;
25955 var autoPlace = autoToken.test(placement);
25957 placement = placement.replace(autoToken, '') || 'top';
25961 //this.el.setXY([0,0]);
25963 //this.el.dom.style.display='block';
25965 //this.el.appendTo(on_el);
25967 var p = this.getPosition();
25968 var box = this.el.getBox();
25974 var align = this.alignment[placement];
25976 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25978 if(placement == 'top' || placement == 'bottom'){
25980 placement = 'right';
25983 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25984 placement = 'left';
25987 var scroll = Roo.select('body', true).first().getScroll();
25989 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25995 this.el.alignTo(this.bindEl, align[0],align[1]);
25996 //var arrow = this.el.select('.arrow',true).first();
25997 //arrow.set(align[2],
25999 this.el.addClass(placement);
26001 this.el.addClass('in fade');
26003 this.hoverState = null;
26005 if (this.el.hasClass('fade')) {
26016 //this.el.setXY([0,0]);
26017 this.el.removeClass('in');
26033 * @class Roo.bootstrap.LocationPicker
26034 * @extends Roo.bootstrap.Component
26035 * Bootstrap LocationPicker class
26036 * @cfg {Number} latitude Position when init default 0
26037 * @cfg {Number} longitude Position when init default 0
26038 * @cfg {Number} zoom default 15
26039 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26040 * @cfg {Boolean} mapTypeControl default false
26041 * @cfg {Boolean} disableDoubleClickZoom default false
26042 * @cfg {Boolean} scrollwheel default true
26043 * @cfg {Boolean} streetViewControl default false
26044 * @cfg {Number} radius default 0
26045 * @cfg {String} locationName
26046 * @cfg {Boolean} draggable default true
26047 * @cfg {Boolean} enableAutocomplete default false
26048 * @cfg {Boolean} enableReverseGeocode default true
26049 * @cfg {String} markerTitle
26052 * Create a new LocationPicker
26053 * @param {Object} config The config object
26057 Roo.bootstrap.LocationPicker = function(config){
26059 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26064 * Fires when the picker initialized.
26065 * @param {Roo.bootstrap.LocationPicker} this
26066 * @param {Google Location} location
26070 * @event positionchanged
26071 * Fires when the picker position changed.
26072 * @param {Roo.bootstrap.LocationPicker} this
26073 * @param {Google Location} location
26075 positionchanged : true,
26078 * Fires when the map resize.
26079 * @param {Roo.bootstrap.LocationPicker} this
26084 * Fires when the map show.
26085 * @param {Roo.bootstrap.LocationPicker} this
26090 * Fires when the map hide.
26091 * @param {Roo.bootstrap.LocationPicker} this
26096 * Fires when click the map.
26097 * @param {Roo.bootstrap.LocationPicker} this
26098 * @param {Map event} e
26102 * @event mapRightClick
26103 * Fires when right click the map.
26104 * @param {Roo.bootstrap.LocationPicker} this
26105 * @param {Map event} e
26107 mapRightClick : true,
26109 * @event markerClick
26110 * Fires when click the marker.
26111 * @param {Roo.bootstrap.LocationPicker} this
26112 * @param {Map event} e
26114 markerClick : true,
26116 * @event markerRightClick
26117 * Fires when right click the marker.
26118 * @param {Roo.bootstrap.LocationPicker} this
26119 * @param {Map event} e
26121 markerRightClick : true,
26123 * @event OverlayViewDraw
26124 * Fires when OverlayView Draw
26125 * @param {Roo.bootstrap.LocationPicker} this
26127 OverlayViewDraw : true,
26129 * @event OverlayViewOnAdd
26130 * Fires when OverlayView Draw
26131 * @param {Roo.bootstrap.LocationPicker} this
26133 OverlayViewOnAdd : true,
26135 * @event OverlayViewOnRemove
26136 * Fires when OverlayView Draw
26137 * @param {Roo.bootstrap.LocationPicker} this
26139 OverlayViewOnRemove : true,
26141 * @event OverlayViewShow
26142 * Fires when OverlayView Draw
26143 * @param {Roo.bootstrap.LocationPicker} this
26144 * @param {Pixel} cpx
26146 OverlayViewShow : true,
26148 * @event OverlayViewHide
26149 * Fires when OverlayView Draw
26150 * @param {Roo.bootstrap.LocationPicker} this
26152 OverlayViewHide : true,
26154 * @event loadexception
26155 * Fires when load google lib failed.
26156 * @param {Roo.bootstrap.LocationPicker} this
26158 loadexception : true
26163 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26165 gMapContext: false,
26171 mapTypeControl: false,
26172 disableDoubleClickZoom: false,
26174 streetViewControl: false,
26178 enableAutocomplete: false,
26179 enableReverseGeocode: true,
26182 getAutoCreate: function()
26187 cls: 'roo-location-picker'
26193 initEvents: function(ct, position)
26195 if(!this.el.getWidth() || this.isApplied()){
26199 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26204 initial: function()
26206 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26207 this.fireEvent('loadexception', this);
26211 if(!this.mapTypeId){
26212 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26215 this.gMapContext = this.GMapContext();
26217 this.initOverlayView();
26219 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26223 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26224 _this.setPosition(_this.gMapContext.marker.position);
26227 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26228 _this.fireEvent('mapClick', this, event);
26232 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26233 _this.fireEvent('mapRightClick', this, event);
26237 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26238 _this.fireEvent('markerClick', this, event);
26242 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26243 _this.fireEvent('markerRightClick', this, event);
26247 this.setPosition(this.gMapContext.location);
26249 this.fireEvent('initial', this, this.gMapContext.location);
26252 initOverlayView: function()
26256 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26260 _this.fireEvent('OverlayViewDraw', _this);
26265 _this.fireEvent('OverlayViewOnAdd', _this);
26268 onRemove: function()
26270 _this.fireEvent('OverlayViewOnRemove', _this);
26273 show: function(cpx)
26275 _this.fireEvent('OverlayViewShow', _this, cpx);
26280 _this.fireEvent('OverlayViewHide', _this);
26286 fromLatLngToContainerPixel: function(event)
26288 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26291 isApplied: function()
26293 return this.getGmapContext() == false ? false : true;
26296 getGmapContext: function()
26298 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26301 GMapContext: function()
26303 var position = new google.maps.LatLng(this.latitude, this.longitude);
26305 var _map = new google.maps.Map(this.el.dom, {
26308 mapTypeId: this.mapTypeId,
26309 mapTypeControl: this.mapTypeControl,
26310 disableDoubleClickZoom: this.disableDoubleClickZoom,
26311 scrollwheel: this.scrollwheel,
26312 streetViewControl: this.streetViewControl,
26313 locationName: this.locationName,
26314 draggable: this.draggable,
26315 enableAutocomplete: this.enableAutocomplete,
26316 enableReverseGeocode: this.enableReverseGeocode
26319 var _marker = new google.maps.Marker({
26320 position: position,
26322 title: this.markerTitle,
26323 draggable: this.draggable
26330 location: position,
26331 radius: this.radius,
26332 locationName: this.locationName,
26333 addressComponents: {
26334 formatted_address: null,
26335 addressLine1: null,
26336 addressLine2: null,
26338 streetNumber: null,
26342 stateOrProvince: null
26345 domContainer: this.el.dom,
26346 geodecoder: new google.maps.Geocoder()
26350 drawCircle: function(center, radius, options)
26352 if (this.gMapContext.circle != null) {
26353 this.gMapContext.circle.setMap(null);
26357 options = Roo.apply({}, options, {
26358 strokeColor: "#0000FF",
26359 strokeOpacity: .35,
26361 fillColor: "#0000FF",
26365 options.map = this.gMapContext.map;
26366 options.radius = radius;
26367 options.center = center;
26368 this.gMapContext.circle = new google.maps.Circle(options);
26369 return this.gMapContext.circle;
26375 setPosition: function(location)
26377 this.gMapContext.location = location;
26378 this.gMapContext.marker.setPosition(location);
26379 this.gMapContext.map.panTo(location);
26380 this.drawCircle(location, this.gMapContext.radius, {});
26384 if (this.gMapContext.settings.enableReverseGeocode) {
26385 this.gMapContext.geodecoder.geocode({
26386 latLng: this.gMapContext.location
26387 }, function(results, status) {
26389 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26390 _this.gMapContext.locationName = results[0].formatted_address;
26391 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26393 _this.fireEvent('positionchanged', this, location);
26400 this.fireEvent('positionchanged', this, location);
26405 google.maps.event.trigger(this.gMapContext.map, "resize");
26407 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26409 this.fireEvent('resize', this);
26412 setPositionByLatLng: function(latitude, longitude)
26414 this.setPosition(new google.maps.LatLng(latitude, longitude));
26417 getCurrentPosition: function()
26420 latitude: this.gMapContext.location.lat(),
26421 longitude: this.gMapContext.location.lng()
26425 getAddressName: function()
26427 return this.gMapContext.locationName;
26430 getAddressComponents: function()
26432 return this.gMapContext.addressComponents;
26435 address_component_from_google_geocode: function(address_components)
26439 for (var i = 0; i < address_components.length; i++) {
26440 var component = address_components[i];
26441 if (component.types.indexOf("postal_code") >= 0) {
26442 result.postalCode = component.short_name;
26443 } else if (component.types.indexOf("street_number") >= 0) {
26444 result.streetNumber = component.short_name;
26445 } else if (component.types.indexOf("route") >= 0) {
26446 result.streetName = component.short_name;
26447 } else if (component.types.indexOf("neighborhood") >= 0) {
26448 result.city = component.short_name;
26449 } else if (component.types.indexOf("locality") >= 0) {
26450 result.city = component.short_name;
26451 } else if (component.types.indexOf("sublocality") >= 0) {
26452 result.district = component.short_name;
26453 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26454 result.stateOrProvince = component.short_name;
26455 } else if (component.types.indexOf("country") >= 0) {
26456 result.country = component.short_name;
26460 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26461 result.addressLine2 = "";
26465 setZoomLevel: function(zoom)
26467 this.gMapContext.map.setZoom(zoom);
26480 this.fireEvent('show', this);
26491 this.fireEvent('hide', this);
26496 Roo.apply(Roo.bootstrap.LocationPicker, {
26498 OverlayView : function(map, options)
26500 options = options || {};
26514 * @class Roo.bootstrap.Alert
26515 * @extends Roo.bootstrap.Component
26516 * Bootstrap Alert class
26517 * @cfg {String} title The title of alert
26518 * @cfg {String} html The content of alert
26519 * @cfg {String} weight ( success | info | warning | danger )
26520 * @cfg {String} faicon font-awesomeicon
26523 * Create a new alert
26524 * @param {Object} config The config object
26528 Roo.bootstrap.Alert = function(config){
26529 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26533 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26540 getAutoCreate : function()
26549 cls : 'roo-alert-icon'
26554 cls : 'roo-alert-title',
26559 cls : 'roo-alert-text',
26566 cfg.cn[0].cls += ' fa ' + this.faicon;
26570 cfg.cls += ' alert-' + this.weight;
26576 initEvents: function()
26578 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26581 setTitle : function(str)
26583 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26586 setText : function(str)
26588 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26591 setWeight : function(weight)
26594 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26597 this.weight = weight;
26599 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26602 setIcon : function(icon)
26605 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26608 this.faicon = icon;
26610 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26631 * @class Roo.bootstrap.UploadCropbox
26632 * @extends Roo.bootstrap.Component
26633 * Bootstrap UploadCropbox class
26634 * @cfg {String} emptyText show when image has been loaded
26635 * @cfg {String} rotateNotify show when image too small to rotate
26636 * @cfg {Number} errorTimeout default 3000
26637 * @cfg {Number} minWidth default 300
26638 * @cfg {Number} minHeight default 300
26639 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26640 * @cfg {Boolean} isDocument (true|false) default false
26641 * @cfg {String} url action url
26642 * @cfg {String} paramName default 'imageUpload'
26643 * @cfg {String} method default POST
26644 * @cfg {Boolean} loadMask (true|false) default true
26645 * @cfg {Boolean} loadingText default 'Loading...'
26648 * Create a new UploadCropbox
26649 * @param {Object} config The config object
26652 Roo.bootstrap.UploadCropbox = function(config){
26653 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26657 * @event beforeselectfile
26658 * Fire before select file
26659 * @param {Roo.bootstrap.UploadCropbox} this
26661 "beforeselectfile" : true,
26664 * Fire after initEvent
26665 * @param {Roo.bootstrap.UploadCropbox} this
26670 * Fire after initEvent
26671 * @param {Roo.bootstrap.UploadCropbox} this
26672 * @param {String} data
26677 * Fire when preparing the file data
26678 * @param {Roo.bootstrap.UploadCropbox} this
26679 * @param {Object} file
26684 * Fire when get exception
26685 * @param {Roo.bootstrap.UploadCropbox} this
26686 * @param {XMLHttpRequest} xhr
26688 "exception" : true,
26690 * @event beforeloadcanvas
26691 * Fire before load the canvas
26692 * @param {Roo.bootstrap.UploadCropbox} this
26693 * @param {String} src
26695 "beforeloadcanvas" : true,
26698 * Fire when trash image
26699 * @param {Roo.bootstrap.UploadCropbox} this
26704 * Fire when download the image
26705 * @param {Roo.bootstrap.UploadCropbox} this
26709 * @event footerbuttonclick
26710 * Fire when footerbuttonclick
26711 * @param {Roo.bootstrap.UploadCropbox} this
26712 * @param {String} type
26714 "footerbuttonclick" : true,
26718 * @param {Roo.bootstrap.UploadCropbox} this
26723 * Fire when rotate the image
26724 * @param {Roo.bootstrap.UploadCropbox} this
26725 * @param {String} pos
26730 * Fire when inspect the file
26731 * @param {Roo.bootstrap.UploadCropbox} this
26732 * @param {Object} file
26737 * Fire when xhr upload the file
26738 * @param {Roo.bootstrap.UploadCropbox} this
26739 * @param {Object} data
26744 * Fire when arrange the file data
26745 * @param {Roo.bootstrap.UploadCropbox} this
26746 * @param {Object} formData
26751 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26754 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26756 emptyText : 'Click to upload image',
26757 rotateNotify : 'Image is too small to rotate',
26758 errorTimeout : 3000,
26772 cropType : 'image/jpeg',
26774 canvasLoaded : false,
26775 isDocument : false,
26777 paramName : 'imageUpload',
26779 loadingText : 'Loading...',
26782 getAutoCreate : function()
26786 cls : 'roo-upload-cropbox',
26790 cls : 'roo-upload-cropbox-selector',
26795 cls : 'roo-upload-cropbox-body',
26796 style : 'cursor:pointer',
26800 cls : 'roo-upload-cropbox-preview'
26804 cls : 'roo-upload-cropbox-thumb'
26808 cls : 'roo-upload-cropbox-empty-notify',
26809 html : this.emptyText
26813 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26814 html : this.rotateNotify
26820 cls : 'roo-upload-cropbox-footer',
26823 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26833 onRender : function(ct, position)
26835 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26837 if (this.buttons.length) {
26839 Roo.each(this.buttons, function(bb) {
26841 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26843 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26849 this.maskEl = this.el;
26853 initEvents : function()
26855 this.urlAPI = (window.createObjectURL && window) ||
26856 (window.URL && URL.revokeObjectURL && URL) ||
26857 (window.webkitURL && webkitURL);
26859 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26860 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26862 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26863 this.selectorEl.hide();
26865 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26866 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26868 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26869 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26870 this.thumbEl.hide();
26872 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26873 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26875 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26876 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26877 this.errorEl.hide();
26879 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26880 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26881 this.footerEl.hide();
26883 this.setThumbBoxSize();
26889 this.fireEvent('initial', this);
26896 window.addEventListener("resize", function() { _this.resize(); } );
26898 this.bodyEl.on('click', this.beforeSelectFile, this);
26901 this.bodyEl.on('touchstart', this.onTouchStart, this);
26902 this.bodyEl.on('touchmove', this.onTouchMove, this);
26903 this.bodyEl.on('touchend', this.onTouchEnd, this);
26907 this.bodyEl.on('mousedown', this.onMouseDown, this);
26908 this.bodyEl.on('mousemove', this.onMouseMove, this);
26909 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26910 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26911 Roo.get(document).on('mouseup', this.onMouseUp, this);
26914 this.selectorEl.on('change', this.onFileSelected, this);
26920 this.baseScale = 1;
26922 this.baseRotate = 1;
26923 this.dragable = false;
26924 this.pinching = false;
26927 this.cropData = false;
26928 this.notifyEl.dom.innerHTML = this.emptyText;
26930 this.selectorEl.dom.value = '';
26934 resize : function()
26936 if(this.fireEvent('resize', this) != false){
26937 this.setThumbBoxPosition();
26938 this.setCanvasPosition();
26942 onFooterButtonClick : function(e, el, o, type)
26945 case 'rotate-left' :
26946 this.onRotateLeft(e);
26948 case 'rotate-right' :
26949 this.onRotateRight(e);
26952 this.beforeSelectFile(e);
26967 this.fireEvent('footerbuttonclick', this, type);
26970 beforeSelectFile : function(e)
26972 e.preventDefault();
26974 if(this.fireEvent('beforeselectfile', this) != false){
26975 this.selectorEl.dom.click();
26979 onFileSelected : function(e)
26981 e.preventDefault();
26983 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26987 var file = this.selectorEl.dom.files[0];
26989 if(this.fireEvent('inspect', this, file) != false){
26990 this.prepare(file);
26995 trash : function(e)
26997 this.fireEvent('trash', this);
27000 download : function(e)
27002 this.fireEvent('download', this);
27005 loadCanvas : function(src)
27007 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27011 this.imageEl = document.createElement('img');
27015 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27017 this.imageEl.src = src;
27021 onLoadCanvas : function()
27023 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27024 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27026 this.bodyEl.un('click', this.beforeSelectFile, this);
27028 this.notifyEl.hide();
27029 this.thumbEl.show();
27030 this.footerEl.show();
27032 this.baseRotateLevel();
27034 if(this.isDocument){
27035 this.setThumbBoxSize();
27038 this.setThumbBoxPosition();
27040 this.baseScaleLevel();
27046 this.canvasLoaded = true;
27049 this.maskEl.unmask();
27054 setCanvasPosition : function()
27056 if(!this.canvasEl){
27060 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27061 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27063 this.previewEl.setLeft(pw);
27064 this.previewEl.setTop(ph);
27068 onMouseDown : function(e)
27072 this.dragable = true;
27073 this.pinching = false;
27075 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27076 this.dragable = false;
27080 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27081 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27085 onMouseMove : function(e)
27089 if(!this.canvasLoaded){
27093 if (!this.dragable){
27097 var minX = Math.ceil(this.thumbEl.getLeft(true));
27098 var minY = Math.ceil(this.thumbEl.getTop(true));
27100 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27101 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27103 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27104 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27106 x = x - this.mouseX;
27107 y = y - this.mouseY;
27109 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27110 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27112 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27113 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27115 this.previewEl.setLeft(bgX);
27116 this.previewEl.setTop(bgY);
27118 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27119 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27122 onMouseUp : function(e)
27126 this.dragable = false;
27129 onMouseWheel : function(e)
27133 this.startScale = this.scale;
27135 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27137 if(!this.zoomable()){
27138 this.scale = this.startScale;
27147 zoomable : function()
27149 var minScale = this.thumbEl.getWidth() / this.minWidth;
27151 if(this.minWidth < this.minHeight){
27152 minScale = this.thumbEl.getHeight() / this.minHeight;
27155 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27156 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27160 (this.rotate == 0 || this.rotate == 180) &&
27162 width > this.imageEl.OriginWidth ||
27163 height > this.imageEl.OriginHeight ||
27164 (width < this.minWidth && height < this.minHeight)
27172 (this.rotate == 90 || this.rotate == 270) &&
27174 width > this.imageEl.OriginWidth ||
27175 height > this.imageEl.OriginHeight ||
27176 (width < this.minHeight && height < this.minWidth)
27183 !this.isDocument &&
27184 (this.rotate == 0 || this.rotate == 180) &&
27186 width < this.minWidth ||
27187 width > this.imageEl.OriginWidth ||
27188 height < this.minHeight ||
27189 height > this.imageEl.OriginHeight
27196 !this.isDocument &&
27197 (this.rotate == 90 || this.rotate == 270) &&
27199 width < this.minHeight ||
27200 width > this.imageEl.OriginWidth ||
27201 height < this.minWidth ||
27202 height > this.imageEl.OriginHeight
27212 onRotateLeft : function(e)
27214 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27216 var minScale = this.thumbEl.getWidth() / this.minWidth;
27218 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27219 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27221 this.startScale = this.scale;
27223 while (this.getScaleLevel() < minScale){
27225 this.scale = this.scale + 1;
27227 if(!this.zoomable()){
27232 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27233 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27238 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27245 this.scale = this.startScale;
27247 this.onRotateFail();
27252 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27254 if(this.isDocument){
27255 this.setThumbBoxSize();
27256 this.setThumbBoxPosition();
27257 this.setCanvasPosition();
27262 this.fireEvent('rotate', this, 'left');
27266 onRotateRight : function(e)
27268 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27270 var minScale = this.thumbEl.getWidth() / this.minWidth;
27272 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27273 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27275 this.startScale = this.scale;
27277 while (this.getScaleLevel() < minScale){
27279 this.scale = this.scale + 1;
27281 if(!this.zoomable()){
27286 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27287 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27292 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27299 this.scale = this.startScale;
27301 this.onRotateFail();
27306 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27308 if(this.isDocument){
27309 this.setThumbBoxSize();
27310 this.setThumbBoxPosition();
27311 this.setCanvasPosition();
27316 this.fireEvent('rotate', this, 'right');
27319 onRotateFail : function()
27321 this.errorEl.show(true);
27325 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27330 this.previewEl.dom.innerHTML = '';
27332 var canvasEl = document.createElement("canvas");
27334 var contextEl = canvasEl.getContext("2d");
27336 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27337 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27338 var center = this.imageEl.OriginWidth / 2;
27340 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27341 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27342 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27343 center = this.imageEl.OriginHeight / 2;
27346 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27348 contextEl.translate(center, center);
27349 contextEl.rotate(this.rotate * Math.PI / 180);
27351 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27353 this.canvasEl = document.createElement("canvas");
27355 this.contextEl = this.canvasEl.getContext("2d");
27357 switch (this.rotate) {
27360 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27361 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27363 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27368 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27369 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27371 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27372 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);
27376 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27381 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27382 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27384 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27385 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);
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);
27394 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27395 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27397 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27398 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
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);
27409 this.previewEl.appendChild(this.canvasEl);
27411 this.setCanvasPosition();
27416 if(!this.canvasLoaded){
27420 var imageCanvas = document.createElement("canvas");
27422 var imageContext = imageCanvas.getContext("2d");
27424 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27425 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27427 var center = imageCanvas.width / 2;
27429 imageContext.translate(center, center);
27431 imageContext.rotate(this.rotate * Math.PI / 180);
27433 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27435 var canvas = document.createElement("canvas");
27437 var context = canvas.getContext("2d");
27439 canvas.width = this.minWidth;
27440 canvas.height = this.minHeight;
27442 switch (this.rotate) {
27445 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27446 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27448 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27449 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27451 var targetWidth = this.minWidth - 2 * x;
27452 var targetHeight = this.minHeight - 2 * y;
27456 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27457 scale = targetWidth / width;
27460 if(x > 0 && y == 0){
27461 scale = targetHeight / height;
27464 if(x > 0 && y > 0){
27465 scale = targetWidth / width;
27467 if(width < height){
27468 scale = targetHeight / height;
27472 context.scale(scale, scale);
27474 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27475 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27477 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27478 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27480 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27485 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27486 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27488 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27489 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27491 var targetWidth = this.minWidth - 2 * x;
27492 var targetHeight = this.minHeight - 2 * y;
27496 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27497 scale = targetWidth / width;
27500 if(x > 0 && y == 0){
27501 scale = targetHeight / height;
27504 if(x > 0 && y > 0){
27505 scale = targetWidth / width;
27507 if(width < height){
27508 scale = targetHeight / height;
27512 context.scale(scale, scale);
27514 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27515 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27517 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27518 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27520 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27522 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27527 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27528 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27530 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27531 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27533 var targetWidth = this.minWidth - 2 * x;
27534 var targetHeight = this.minHeight - 2 * y;
27538 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27539 scale = targetWidth / width;
27542 if(x > 0 && y == 0){
27543 scale = targetHeight / height;
27546 if(x > 0 && y > 0){
27547 scale = targetWidth / width;
27549 if(width < height){
27550 scale = targetHeight / height;
27554 context.scale(scale, scale);
27556 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27557 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27559 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27560 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27562 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27563 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27565 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27570 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27571 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27573 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27574 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27576 var targetWidth = this.minWidth - 2 * x;
27577 var targetHeight = this.minHeight - 2 * y;
27581 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27582 scale = targetWidth / width;
27585 if(x > 0 && y == 0){
27586 scale = targetHeight / height;
27589 if(x > 0 && y > 0){
27590 scale = targetWidth / width;
27592 if(width < height){
27593 scale = targetHeight / height;
27597 context.scale(scale, scale);
27599 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27600 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27602 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27603 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27605 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27607 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27614 this.cropData = canvas.toDataURL(this.cropType);
27616 if(this.fireEvent('crop', this, this.cropData) !== false){
27617 this.process(this.file, this.cropData);
27624 setThumbBoxSize : function()
27628 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27629 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27630 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27632 this.minWidth = width;
27633 this.minHeight = height;
27635 if(this.rotate == 90 || this.rotate == 270){
27636 this.minWidth = height;
27637 this.minHeight = width;
27642 width = Math.ceil(this.minWidth * height / this.minHeight);
27644 if(this.minWidth > this.minHeight){
27646 height = Math.ceil(this.minHeight * width / this.minWidth);
27649 this.thumbEl.setStyle({
27650 width : width + 'px',
27651 height : height + 'px'
27658 setThumbBoxPosition : function()
27660 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27661 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27663 this.thumbEl.setLeft(x);
27664 this.thumbEl.setTop(y);
27668 baseRotateLevel : function()
27670 this.baseRotate = 1;
27673 typeof(this.exif) != 'undefined' &&
27674 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27675 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27677 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27680 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27684 baseScaleLevel : function()
27688 if(this.isDocument){
27690 if(this.baseRotate == 6 || this.baseRotate == 8){
27692 height = this.thumbEl.getHeight();
27693 this.baseScale = height / this.imageEl.OriginWidth;
27695 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27696 width = this.thumbEl.getWidth();
27697 this.baseScale = width / this.imageEl.OriginHeight;
27703 height = this.thumbEl.getHeight();
27704 this.baseScale = height / this.imageEl.OriginHeight;
27706 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27707 width = this.thumbEl.getWidth();
27708 this.baseScale = width / this.imageEl.OriginWidth;
27714 if(this.baseRotate == 6 || this.baseRotate == 8){
27716 width = this.thumbEl.getHeight();
27717 this.baseScale = width / this.imageEl.OriginHeight;
27719 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27720 height = this.thumbEl.getWidth();
27721 this.baseScale = height / this.imageEl.OriginHeight;
27724 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27725 height = this.thumbEl.getWidth();
27726 this.baseScale = height / this.imageEl.OriginHeight;
27728 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27729 width = this.thumbEl.getHeight();
27730 this.baseScale = width / this.imageEl.OriginWidth;
27737 width = this.thumbEl.getWidth();
27738 this.baseScale = width / this.imageEl.OriginWidth;
27740 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27741 height = this.thumbEl.getHeight();
27742 this.baseScale = height / this.imageEl.OriginHeight;
27745 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27747 height = this.thumbEl.getHeight();
27748 this.baseScale = height / this.imageEl.OriginHeight;
27750 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27751 width = this.thumbEl.getWidth();
27752 this.baseScale = width / this.imageEl.OriginWidth;
27760 getScaleLevel : function()
27762 return this.baseScale * Math.pow(1.1, this.scale);
27765 onTouchStart : function(e)
27767 if(!this.canvasLoaded){
27768 this.beforeSelectFile(e);
27772 var touches = e.browserEvent.touches;
27778 if(touches.length == 1){
27779 this.onMouseDown(e);
27783 if(touches.length != 2){
27789 for(var i = 0, finger; finger = touches[i]; i++){
27790 coords.push(finger.pageX, finger.pageY);
27793 var x = Math.pow(coords[0] - coords[2], 2);
27794 var y = Math.pow(coords[1] - coords[3], 2);
27796 this.startDistance = Math.sqrt(x + y);
27798 this.startScale = this.scale;
27800 this.pinching = true;
27801 this.dragable = false;
27805 onTouchMove : function(e)
27807 if(!this.pinching && !this.dragable){
27811 var touches = e.browserEvent.touches;
27818 this.onMouseMove(e);
27824 for(var i = 0, finger; finger = touches[i]; i++){
27825 coords.push(finger.pageX, finger.pageY);
27828 var x = Math.pow(coords[0] - coords[2], 2);
27829 var y = Math.pow(coords[1] - coords[3], 2);
27831 this.endDistance = Math.sqrt(x + y);
27833 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27835 if(!this.zoomable()){
27836 this.scale = this.startScale;
27844 onTouchEnd : function(e)
27846 this.pinching = false;
27847 this.dragable = false;
27851 process : function(file, crop)
27854 this.maskEl.mask(this.loadingText);
27857 this.xhr = new XMLHttpRequest();
27859 file.xhr = this.xhr;
27861 this.xhr.open(this.method, this.url, true);
27864 "Accept": "application/json",
27865 "Cache-Control": "no-cache",
27866 "X-Requested-With": "XMLHttpRequest"
27869 for (var headerName in headers) {
27870 var headerValue = headers[headerName];
27872 this.xhr.setRequestHeader(headerName, headerValue);
27878 this.xhr.onload = function()
27880 _this.xhrOnLoad(_this.xhr);
27883 this.xhr.onerror = function()
27885 _this.xhrOnError(_this.xhr);
27888 var formData = new FormData();
27890 formData.append('returnHTML', 'NO');
27893 formData.append('crop', crop);
27896 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27897 formData.append(this.paramName, file, file.name);
27900 if(typeof(file.filename) != 'undefined'){
27901 formData.append('filename', file.filename);
27904 if(typeof(file.mimetype) != 'undefined'){
27905 formData.append('mimetype', file.mimetype);
27908 if(this.fireEvent('arrange', this, formData) != false){
27909 this.xhr.send(formData);
27913 xhrOnLoad : function(xhr)
27916 this.maskEl.unmask();
27919 if (xhr.readyState !== 4) {
27920 this.fireEvent('exception', this, xhr);
27924 var response = Roo.decode(xhr.responseText);
27926 if(!response.success){
27927 this.fireEvent('exception', this, xhr);
27931 var response = Roo.decode(xhr.responseText);
27933 this.fireEvent('upload', this, response);
27937 xhrOnError : function()
27940 this.maskEl.unmask();
27943 Roo.log('xhr on error');
27945 var response = Roo.decode(xhr.responseText);
27951 prepare : function(file)
27954 this.maskEl.mask(this.loadingText);
27960 if(typeof(file) === 'string'){
27961 this.loadCanvas(file);
27965 if(!file || !this.urlAPI){
27970 this.cropType = file.type;
27974 if(this.fireEvent('prepare', this, this.file) != false){
27976 var reader = new FileReader();
27978 reader.onload = function (e) {
27979 if (e.target.error) {
27980 Roo.log(e.target.error);
27984 var buffer = e.target.result,
27985 dataView = new DataView(buffer),
27987 maxOffset = dataView.byteLength - 4,
27991 if (dataView.getUint16(0) === 0xffd8) {
27992 while (offset < maxOffset) {
27993 markerBytes = dataView.getUint16(offset);
27995 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27996 markerLength = dataView.getUint16(offset + 2) + 2;
27997 if (offset + markerLength > dataView.byteLength) {
27998 Roo.log('Invalid meta data: Invalid segment size.');
28002 if(markerBytes == 0xffe1){
28003 _this.parseExifData(
28010 offset += markerLength;
28020 var url = _this.urlAPI.createObjectURL(_this.file);
28022 _this.loadCanvas(url);
28027 reader.readAsArrayBuffer(this.file);
28033 parseExifData : function(dataView, offset, length)
28035 var tiffOffset = offset + 10,
28039 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28040 // No Exif data, might be XMP data instead
28044 // Check for the ASCII code for "Exif" (0x45786966):
28045 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28046 // No Exif data, might be XMP data instead
28049 if (tiffOffset + 8 > dataView.byteLength) {
28050 Roo.log('Invalid Exif data: Invalid segment size.');
28053 // Check for the two null bytes:
28054 if (dataView.getUint16(offset + 8) !== 0x0000) {
28055 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28058 // Check the byte alignment:
28059 switch (dataView.getUint16(tiffOffset)) {
28061 littleEndian = true;
28064 littleEndian = false;
28067 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28070 // Check for the TIFF tag marker (0x002A):
28071 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28072 Roo.log('Invalid Exif data: Missing TIFF marker.');
28075 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28076 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28078 this.parseExifTags(
28081 tiffOffset + dirOffset,
28086 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28091 if (dirOffset + 6 > dataView.byteLength) {
28092 Roo.log('Invalid Exif data: Invalid directory offset.');
28095 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28096 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28097 if (dirEndOffset + 4 > dataView.byteLength) {
28098 Roo.log('Invalid Exif data: Invalid directory size.');
28101 for (i = 0; i < tagsNumber; i += 1) {
28105 dirOffset + 2 + 12 * i, // tag offset
28109 // Return the offset to the next directory:
28110 return dataView.getUint32(dirEndOffset, littleEndian);
28113 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28115 var tag = dataView.getUint16(offset, littleEndian);
28117 this.exif[tag] = this.getExifValue(
28121 dataView.getUint16(offset + 2, littleEndian), // tag type
28122 dataView.getUint32(offset + 4, littleEndian), // tag length
28127 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28129 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28138 Roo.log('Invalid Exif data: Invalid tag type.');
28142 tagSize = tagType.size * length;
28143 // Determine if the value is contained in the dataOffset bytes,
28144 // or if the value at the dataOffset is a pointer to the actual data:
28145 dataOffset = tagSize > 4 ?
28146 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28147 if (dataOffset + tagSize > dataView.byteLength) {
28148 Roo.log('Invalid Exif data: Invalid data offset.');
28151 if (length === 1) {
28152 return tagType.getValue(dataView, dataOffset, littleEndian);
28155 for (i = 0; i < length; i += 1) {
28156 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28159 if (tagType.ascii) {
28161 // Concatenate the chars:
28162 for (i = 0; i < values.length; i += 1) {
28164 // Ignore the terminating NULL byte(s):
28165 if (c === '\u0000') {
28177 Roo.apply(Roo.bootstrap.UploadCropbox, {
28179 'Orientation': 0x0112
28183 1: 0, //'top-left',
28185 3: 180, //'bottom-right',
28186 // 4: 'bottom-left',
28188 6: 90, //'right-top',
28189 // 7: 'right-bottom',
28190 8: 270 //'left-bottom'
28194 // byte, 8-bit unsigned int:
28196 getValue: function (dataView, dataOffset) {
28197 return dataView.getUint8(dataOffset);
28201 // ascii, 8-bit byte:
28203 getValue: function (dataView, dataOffset) {
28204 return String.fromCharCode(dataView.getUint8(dataOffset));
28209 // short, 16 bit int:
28211 getValue: function (dataView, dataOffset, littleEndian) {
28212 return dataView.getUint16(dataOffset, littleEndian);
28216 // long, 32 bit int:
28218 getValue: function (dataView, dataOffset, littleEndian) {
28219 return dataView.getUint32(dataOffset, littleEndian);
28223 // rational = two long values, first is numerator, second is denominator:
28225 getValue: function (dataView, dataOffset, littleEndian) {
28226 return dataView.getUint32(dataOffset, littleEndian) /
28227 dataView.getUint32(dataOffset + 4, littleEndian);
28231 // slong, 32 bit signed int:
28233 getValue: function (dataView, dataOffset, littleEndian) {
28234 return dataView.getInt32(dataOffset, littleEndian);
28238 // srational, two slongs, first is numerator, second is denominator:
28240 getValue: function (dataView, dataOffset, littleEndian) {
28241 return dataView.getInt32(dataOffset, littleEndian) /
28242 dataView.getInt32(dataOffset + 4, littleEndian);
28252 cls : 'btn-group roo-upload-cropbox-rotate-left',
28253 action : 'rotate-left',
28257 cls : 'btn btn-default',
28258 html : '<i class="fa fa-undo"></i>'
28264 cls : 'btn-group roo-upload-cropbox-picture',
28265 action : 'picture',
28269 cls : 'btn btn-default',
28270 html : '<i class="fa fa-picture-o"></i>'
28276 cls : 'btn-group roo-upload-cropbox-rotate-right',
28277 action : 'rotate-right',
28281 cls : 'btn btn-default',
28282 html : '<i class="fa fa-repeat"></i>'
28290 cls : 'btn-group roo-upload-cropbox-rotate-left',
28291 action : 'rotate-left',
28295 cls : 'btn btn-default',
28296 html : '<i class="fa fa-undo"></i>'
28302 cls : 'btn-group roo-upload-cropbox-download',
28303 action : 'download',
28307 cls : 'btn btn-default',
28308 html : '<i class="fa fa-download"></i>'
28314 cls : 'btn-group roo-upload-cropbox-crop',
28319 cls : 'btn btn-default',
28320 html : '<i class="fa fa-crop"></i>'
28326 cls : 'btn-group roo-upload-cropbox-trash',
28331 cls : 'btn btn-default',
28332 html : '<i class="fa fa-trash"></i>'
28338 cls : 'btn-group roo-upload-cropbox-rotate-right',
28339 action : 'rotate-right',
28343 cls : 'btn btn-default',
28344 html : '<i class="fa fa-repeat"></i>'
28352 cls : 'btn-group roo-upload-cropbox-rotate-left',
28353 action : 'rotate-left',
28357 cls : 'btn btn-default',
28358 html : '<i class="fa fa-undo"></i>'
28364 cls : 'btn-group roo-upload-cropbox-rotate-right',
28365 action : 'rotate-right',
28369 cls : 'btn btn-default',
28370 html : '<i class="fa fa-repeat"></i>'
28383 * @class Roo.bootstrap.DocumentManager
28384 * @extends Roo.bootstrap.Component
28385 * Bootstrap DocumentManager class
28386 * @cfg {String} paramName default 'imageUpload'
28387 * @cfg {String} toolTipName default 'filename'
28388 * @cfg {String} method default POST
28389 * @cfg {String} url action url
28390 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28391 * @cfg {Boolean} multiple multiple upload default true
28392 * @cfg {Number} thumbSize default 300
28393 * @cfg {String} fieldLabel
28394 * @cfg {Number} labelWidth default 4
28395 * @cfg {String} labelAlign (left|top) default left
28396 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28397 * @cfg {Number} labellg set the width of label (1-12)
28398 * @cfg {Number} labelmd set the width of label (1-12)
28399 * @cfg {Number} labelsm set the width of label (1-12)
28400 * @cfg {Number} labelxs set the width of label (1-12)
28403 * Create a new DocumentManager
28404 * @param {Object} config The config object
28407 Roo.bootstrap.DocumentManager = function(config){
28408 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28411 this.delegates = [];
28416 * Fire when initial the DocumentManager
28417 * @param {Roo.bootstrap.DocumentManager} this
28422 * inspect selected file
28423 * @param {Roo.bootstrap.DocumentManager} this
28424 * @param {File} file
28429 * Fire when xhr load exception
28430 * @param {Roo.bootstrap.DocumentManager} this
28431 * @param {XMLHttpRequest} xhr
28433 "exception" : true,
28435 * @event afterupload
28436 * Fire when xhr load exception
28437 * @param {Roo.bootstrap.DocumentManager} this
28438 * @param {XMLHttpRequest} xhr
28440 "afterupload" : true,
28443 * prepare the form data
28444 * @param {Roo.bootstrap.DocumentManager} this
28445 * @param {Object} formData
28450 * Fire when remove the file
28451 * @param {Roo.bootstrap.DocumentManager} this
28452 * @param {Object} file
28457 * Fire after refresh the file
28458 * @param {Roo.bootstrap.DocumentManager} this
28463 * Fire after click the image
28464 * @param {Roo.bootstrap.DocumentManager} this
28465 * @param {Object} file
28470 * Fire when upload a image and editable set to true
28471 * @param {Roo.bootstrap.DocumentManager} this
28472 * @param {Object} file
28476 * @event beforeselectfile
28477 * Fire before select file
28478 * @param {Roo.bootstrap.DocumentManager} this
28480 "beforeselectfile" : true,
28483 * Fire before process file
28484 * @param {Roo.bootstrap.DocumentManager} this
28485 * @param {Object} file
28489 * @event previewrendered
28490 * Fire when preview rendered
28491 * @param {Roo.bootstrap.DocumentManager} this
28492 * @param {Object} file
28494 "previewrendered" : true
28499 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28508 paramName : 'imageUpload',
28509 toolTipName : 'filename',
28512 labelAlign : 'left',
28522 getAutoCreate : function()
28524 var managerWidget = {
28526 cls : 'roo-document-manager',
28530 cls : 'roo-document-manager-selector',
28535 cls : 'roo-document-manager-uploader',
28539 cls : 'roo-document-manager-upload-btn',
28540 html : '<i class="fa fa-plus"></i>'
28551 cls : 'column col-md-12',
28556 if(this.fieldLabel.length){
28561 cls : 'column col-md-12',
28562 html : this.fieldLabel
28566 cls : 'column col-md-12',
28571 if(this.labelAlign == 'left'){
28576 html : this.fieldLabel
28585 if(this.labelWidth > 12){
28586 content[0].style = "width: " + this.labelWidth + 'px';
28589 if(this.labelWidth < 13 && this.labelmd == 0){
28590 this.labelmd = this.labelWidth;
28593 if(this.labellg > 0){
28594 content[0].cls += ' col-lg-' + this.labellg;
28595 content[1].cls += ' col-lg-' + (12 - this.labellg);
28598 if(this.labelmd > 0){
28599 content[0].cls += ' col-md-' + this.labelmd;
28600 content[1].cls += ' col-md-' + (12 - this.labelmd);
28603 if(this.labelsm > 0){
28604 content[0].cls += ' col-sm-' + this.labelsm;
28605 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28608 if(this.labelxs > 0){
28609 content[0].cls += ' col-xs-' + this.labelxs;
28610 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28618 cls : 'row clearfix',
28626 initEvents : function()
28628 this.managerEl = this.el.select('.roo-document-manager', true).first();
28629 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28631 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28632 this.selectorEl.hide();
28635 this.selectorEl.attr('multiple', 'multiple');
28638 this.selectorEl.on('change', this.onFileSelected, this);
28640 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28641 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28643 this.uploader.on('click', this.onUploaderClick, this);
28645 this.renderProgressDialog();
28649 window.addEventListener("resize", function() { _this.refresh(); } );
28651 this.fireEvent('initial', this);
28654 renderProgressDialog : function()
28658 this.progressDialog = new Roo.bootstrap.Modal({
28659 cls : 'roo-document-manager-progress-dialog',
28660 allow_close : false,
28670 btnclick : function() {
28671 _this.uploadCancel();
28677 this.progressDialog.render(Roo.get(document.body));
28679 this.progress = new Roo.bootstrap.Progress({
28680 cls : 'roo-document-manager-progress',
28685 this.progress.render(this.progressDialog.getChildContainer());
28687 this.progressBar = new Roo.bootstrap.ProgressBar({
28688 cls : 'roo-document-manager-progress-bar',
28691 aria_valuemax : 12,
28695 this.progressBar.render(this.progress.getChildContainer());
28698 onUploaderClick : function(e)
28700 e.preventDefault();
28702 if(this.fireEvent('beforeselectfile', this) != false){
28703 this.selectorEl.dom.click();
28708 onFileSelected : function(e)
28710 e.preventDefault();
28712 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28716 Roo.each(this.selectorEl.dom.files, function(file){
28717 if(this.fireEvent('inspect', this, file) != false){
28718 this.files.push(file);
28728 this.selectorEl.dom.value = '';
28730 if(!this.files || !this.files.length){
28734 if(this.boxes > 0 && this.files.length > this.boxes){
28735 this.files = this.files.slice(0, this.boxes);
28738 this.uploader.show();
28740 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28741 this.uploader.hide();
28750 Roo.each(this.files, function(file){
28752 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28753 var f = this.renderPreview(file);
28758 if(file.type.indexOf('image') != -1){
28759 this.delegates.push(
28761 _this.process(file);
28762 }).createDelegate(this)
28770 _this.process(file);
28771 }).createDelegate(this)
28776 this.files = files;
28778 this.delegates = this.delegates.concat(docs);
28780 if(!this.delegates.length){
28785 this.progressBar.aria_valuemax = this.delegates.length;
28792 arrange : function()
28794 if(!this.delegates.length){
28795 this.progressDialog.hide();
28800 var delegate = this.delegates.shift();
28802 this.progressDialog.show();
28804 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28806 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28811 refresh : function()
28813 this.uploader.show();
28815 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28816 this.uploader.hide();
28819 Roo.isTouch ? this.closable(false) : this.closable(true);
28821 this.fireEvent('refresh', this);
28824 onRemove : function(e, el, o)
28826 e.preventDefault();
28828 this.fireEvent('remove', this, o);
28832 remove : function(o)
28836 Roo.each(this.files, function(file){
28837 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28846 this.files = files;
28853 Roo.each(this.files, function(file){
28858 file.target.remove();
28867 onClick : function(e, el, o)
28869 e.preventDefault();
28871 this.fireEvent('click', this, o);
28875 closable : function(closable)
28877 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28879 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28891 xhrOnLoad : function(xhr)
28893 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28897 if (xhr.readyState !== 4) {
28899 this.fireEvent('exception', this, xhr);
28903 var response = Roo.decode(xhr.responseText);
28905 if(!response.success){
28907 this.fireEvent('exception', this, xhr);
28911 var file = this.renderPreview(response.data);
28913 this.files.push(file);
28917 this.fireEvent('afterupload', this, xhr);
28921 xhrOnError : function(xhr)
28923 Roo.log('xhr on error');
28925 var response = Roo.decode(xhr.responseText);
28932 process : function(file)
28934 if(this.fireEvent('process', this, file) !== false){
28935 if(this.editable && file.type.indexOf('image') != -1){
28936 this.fireEvent('edit', this, file);
28940 this.uploadStart(file, false);
28947 uploadStart : function(file, crop)
28949 this.xhr = new XMLHttpRequest();
28951 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28956 file.xhr = this.xhr;
28958 this.managerEl.createChild({
28960 cls : 'roo-document-manager-loading',
28964 tooltip : file.name,
28965 cls : 'roo-document-manager-thumb',
28966 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28972 this.xhr.open(this.method, this.url, true);
28975 "Accept": "application/json",
28976 "Cache-Control": "no-cache",
28977 "X-Requested-With": "XMLHttpRequest"
28980 for (var headerName in headers) {
28981 var headerValue = headers[headerName];
28983 this.xhr.setRequestHeader(headerName, headerValue);
28989 this.xhr.onload = function()
28991 _this.xhrOnLoad(_this.xhr);
28994 this.xhr.onerror = function()
28996 _this.xhrOnError(_this.xhr);
28999 var formData = new FormData();
29001 formData.append('returnHTML', 'NO');
29004 formData.append('crop', crop);
29007 formData.append(this.paramName, file, file.name);
29014 if(this.fireEvent('prepare', this, formData, options) != false){
29016 if(options.manually){
29020 this.xhr.send(formData);
29024 this.uploadCancel();
29027 uploadCancel : function()
29033 this.delegates = [];
29035 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29042 renderPreview : function(file)
29044 if(typeof(file.target) != 'undefined' && file.target){
29048 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29050 var previewEl = this.managerEl.createChild({
29052 cls : 'roo-document-manager-preview',
29056 tooltip : file[this.toolTipName],
29057 cls : 'roo-document-manager-thumb',
29058 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29063 html : '<i class="fa fa-times-circle"></i>'
29068 var close = previewEl.select('button.close', true).first();
29070 close.on('click', this.onRemove, this, file);
29072 file.target = previewEl;
29074 var image = previewEl.select('img', true).first();
29078 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29080 image.on('click', this.onClick, this, file);
29082 this.fireEvent('previewrendered', this, file);
29088 onPreviewLoad : function(file, image)
29090 if(typeof(file.target) == 'undefined' || !file.target){
29094 var width = image.dom.naturalWidth || image.dom.width;
29095 var height = image.dom.naturalHeight || image.dom.height;
29097 if(width > height){
29098 file.target.addClass('wide');
29102 file.target.addClass('tall');
29107 uploadFromSource : function(file, crop)
29109 this.xhr = new XMLHttpRequest();
29111 this.managerEl.createChild({
29113 cls : 'roo-document-manager-loading',
29117 tooltip : file.name,
29118 cls : 'roo-document-manager-thumb',
29119 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29125 this.xhr.open(this.method, this.url, true);
29128 "Accept": "application/json",
29129 "Cache-Control": "no-cache",
29130 "X-Requested-With": "XMLHttpRequest"
29133 for (var headerName in headers) {
29134 var headerValue = headers[headerName];
29136 this.xhr.setRequestHeader(headerName, headerValue);
29142 this.xhr.onload = function()
29144 _this.xhrOnLoad(_this.xhr);
29147 this.xhr.onerror = function()
29149 _this.xhrOnError(_this.xhr);
29152 var formData = new FormData();
29154 formData.append('returnHTML', 'NO');
29156 formData.append('crop', crop);
29158 if(typeof(file.filename) != 'undefined'){
29159 formData.append('filename', file.filename);
29162 if(typeof(file.mimetype) != 'undefined'){
29163 formData.append('mimetype', file.mimetype);
29168 if(this.fireEvent('prepare', this, formData) != false){
29169 this.xhr.send(formData);
29179 * @class Roo.bootstrap.DocumentViewer
29180 * @extends Roo.bootstrap.Component
29181 * Bootstrap DocumentViewer class
29182 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29183 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29186 * Create a new DocumentViewer
29187 * @param {Object} config The config object
29190 Roo.bootstrap.DocumentViewer = function(config){
29191 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29196 * Fire after initEvent
29197 * @param {Roo.bootstrap.DocumentViewer} this
29203 * @param {Roo.bootstrap.DocumentViewer} this
29208 * Fire after download button
29209 * @param {Roo.bootstrap.DocumentViewer} this
29214 * Fire after trash button
29215 * @param {Roo.bootstrap.DocumentViewer} this
29222 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29224 showDownload : true,
29228 getAutoCreate : function()
29232 cls : 'roo-document-viewer',
29236 cls : 'roo-document-viewer-body',
29240 cls : 'roo-document-viewer-thumb',
29244 cls : 'roo-document-viewer-image'
29252 cls : 'roo-document-viewer-footer',
29255 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29259 cls : 'btn-group roo-document-viewer-download',
29263 cls : 'btn btn-default',
29264 html : '<i class="fa fa-download"></i>'
29270 cls : 'btn-group roo-document-viewer-trash',
29274 cls : 'btn btn-default',
29275 html : '<i class="fa fa-trash"></i>'
29288 initEvents : function()
29290 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29291 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29293 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29294 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29296 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29297 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29299 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29300 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29302 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29303 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29305 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29306 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29308 this.bodyEl.on('click', this.onClick, this);
29309 this.downloadBtn.on('click', this.onDownload, this);
29310 this.trashBtn.on('click', this.onTrash, this);
29312 this.downloadBtn.hide();
29313 this.trashBtn.hide();
29315 if(this.showDownload){
29316 this.downloadBtn.show();
29319 if(this.showTrash){
29320 this.trashBtn.show();
29323 if(!this.showDownload && !this.showTrash) {
29324 this.footerEl.hide();
29329 initial : function()
29331 this.fireEvent('initial', this);
29335 onClick : function(e)
29337 e.preventDefault();
29339 this.fireEvent('click', this);
29342 onDownload : function(e)
29344 e.preventDefault();
29346 this.fireEvent('download', this);
29349 onTrash : function(e)
29351 e.preventDefault();
29353 this.fireEvent('trash', this);
29365 * @class Roo.bootstrap.NavProgressBar
29366 * @extends Roo.bootstrap.Component
29367 * Bootstrap NavProgressBar class
29370 * Create a new nav progress bar
29371 * @param {Object} config The config object
29374 Roo.bootstrap.NavProgressBar = function(config){
29375 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29377 this.bullets = this.bullets || [];
29379 // Roo.bootstrap.NavProgressBar.register(this);
29383 * Fires when the active item changes
29384 * @param {Roo.bootstrap.NavProgressBar} this
29385 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29386 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29393 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29398 getAutoCreate : function()
29400 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29404 cls : 'roo-navigation-bar-group',
29408 cls : 'roo-navigation-top-bar'
29412 cls : 'roo-navigation-bullets-bar',
29416 cls : 'roo-navigation-bar'
29423 cls : 'roo-navigation-bottom-bar'
29433 initEvents: function()
29438 onRender : function(ct, position)
29440 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29442 if(this.bullets.length){
29443 Roo.each(this.bullets, function(b){
29452 addItem : function(cfg)
29454 var item = new Roo.bootstrap.NavProgressItem(cfg);
29456 item.parentId = this.id;
29457 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29460 var top = new Roo.bootstrap.Element({
29462 cls : 'roo-navigation-bar-text'
29465 var bottom = new Roo.bootstrap.Element({
29467 cls : 'roo-navigation-bar-text'
29470 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29471 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29473 var topText = new Roo.bootstrap.Element({
29475 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29478 var bottomText = new Roo.bootstrap.Element({
29480 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29483 topText.onRender(top.el, null);
29484 bottomText.onRender(bottom.el, null);
29487 item.bottomEl = bottom;
29490 this.barItems.push(item);
29495 getActive : function()
29497 var active = false;
29499 Roo.each(this.barItems, function(v){
29501 if (!v.isActive()) {
29513 setActiveItem : function(item)
29517 Roo.each(this.barItems, function(v){
29518 if (v.rid == item.rid) {
29522 if (v.isActive()) {
29523 v.setActive(false);
29528 item.setActive(true);
29530 this.fireEvent('changed', this, item, prev);
29533 getBarItem: function(rid)
29537 Roo.each(this.barItems, function(e) {
29538 if (e.rid != rid) {
29549 indexOfItem : function(item)
29553 Roo.each(this.barItems, function(v, i){
29555 if (v.rid != item.rid) {
29566 setActiveNext : function()
29568 var i = this.indexOfItem(this.getActive());
29570 if (i > this.barItems.length) {
29574 this.setActiveItem(this.barItems[i+1]);
29577 setActivePrev : function()
29579 var i = this.indexOfItem(this.getActive());
29585 this.setActiveItem(this.barItems[i-1]);
29588 format : function()
29590 if(!this.barItems.length){
29594 var width = 100 / this.barItems.length;
29596 Roo.each(this.barItems, function(i){
29597 i.el.setStyle('width', width + '%');
29598 i.topEl.el.setStyle('width', width + '%');
29599 i.bottomEl.el.setStyle('width', width + '%');
29608 * Nav Progress Item
29613 * @class Roo.bootstrap.NavProgressItem
29614 * @extends Roo.bootstrap.Component
29615 * Bootstrap NavProgressItem class
29616 * @cfg {String} rid the reference id
29617 * @cfg {Boolean} active (true|false) Is item active default false
29618 * @cfg {Boolean} disabled (true|false) Is item active default false
29619 * @cfg {String} html
29620 * @cfg {String} position (top|bottom) text position default bottom
29621 * @cfg {String} icon show icon instead of number
29624 * Create a new NavProgressItem
29625 * @param {Object} config The config object
29627 Roo.bootstrap.NavProgressItem = function(config){
29628 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29633 * The raw click event for the entire grid.
29634 * @param {Roo.bootstrap.NavProgressItem} this
29635 * @param {Roo.EventObject} e
29642 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29648 position : 'bottom',
29651 getAutoCreate : function()
29653 var iconCls = 'roo-navigation-bar-item-icon';
29655 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29659 cls: 'roo-navigation-bar-item',
29669 cfg.cls += ' active';
29672 cfg.cls += ' disabled';
29678 disable : function()
29680 this.setDisabled(true);
29683 enable : function()
29685 this.setDisabled(false);
29688 initEvents: function()
29690 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29692 this.iconEl.on('click', this.onClick, this);
29695 onClick : function(e)
29697 e.preventDefault();
29703 if(this.fireEvent('click', this, e) === false){
29707 this.parent().setActiveItem(this);
29710 isActive: function ()
29712 return this.active;
29715 setActive : function(state)
29717 if(this.active == state){
29721 this.active = state;
29724 this.el.addClass('active');
29728 this.el.removeClass('active');
29733 setDisabled : function(state)
29735 if(this.disabled == state){
29739 this.disabled = state;
29742 this.el.addClass('disabled');
29746 this.el.removeClass('disabled');
29749 tooltipEl : function()
29751 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29764 * @class Roo.bootstrap.FieldLabel
29765 * @extends Roo.bootstrap.Component
29766 * Bootstrap FieldLabel class
29767 * @cfg {String} html contents of the element
29768 * @cfg {String} tag tag of the element default label
29769 * @cfg {String} cls class of the element
29770 * @cfg {String} target label target
29771 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29772 * @cfg {String} invalidClass default "text-warning"
29773 * @cfg {String} validClass default "text-success"
29774 * @cfg {String} iconTooltip default "This field is required"
29775 * @cfg {String} indicatorpos (left|right) default left
29778 * Create a new FieldLabel
29779 * @param {Object} config The config object
29782 Roo.bootstrap.FieldLabel = function(config){
29783 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29788 * Fires after the field has been marked as invalid.
29789 * @param {Roo.form.FieldLabel} this
29790 * @param {String} msg The validation message
29795 * Fires after the field has been validated with no errors.
29796 * @param {Roo.form.FieldLabel} this
29802 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29809 invalidClass : 'has-warning',
29810 validClass : 'has-success',
29811 iconTooltip : 'This field is required',
29812 indicatorpos : 'left',
29814 getAutoCreate : function(){
29818 cls : 'roo-bootstrap-field-label ' + this.cls,
29823 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29824 tooltip : this.iconTooltip
29833 if(this.indicatorpos == 'right'){
29836 cls : 'roo-bootstrap-field-label ' + this.cls,
29845 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29846 tooltip : this.iconTooltip
29855 initEvents: function()
29857 Roo.bootstrap.Element.superclass.initEvents.call(this);
29859 this.indicator = this.indicatorEl();
29861 if(this.indicator){
29862 this.indicator.removeClass('visible');
29863 this.indicator.addClass('invisible');
29866 Roo.bootstrap.FieldLabel.register(this);
29869 indicatorEl : function()
29871 var indicator = this.el.select('i.roo-required-indicator',true).first();
29882 * Mark this field as valid
29884 markValid : function()
29886 if(this.indicator){
29887 this.indicator.removeClass('visible');
29888 this.indicator.addClass('invisible');
29891 this.el.removeClass(this.invalidClass);
29893 this.el.addClass(this.validClass);
29895 this.fireEvent('valid', this);
29899 * Mark this field as invalid
29900 * @param {String} msg The validation message
29902 markInvalid : function(msg)
29904 if(this.indicator){
29905 this.indicator.removeClass('invisible');
29906 this.indicator.addClass('visible');
29909 this.el.removeClass(this.validClass);
29911 this.el.addClass(this.invalidClass);
29913 this.fireEvent('invalid', this, msg);
29919 Roo.apply(Roo.bootstrap.FieldLabel, {
29924 * register a FieldLabel Group
29925 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29927 register : function(label)
29929 if(this.groups.hasOwnProperty(label.target)){
29933 this.groups[label.target] = label;
29937 * fetch a FieldLabel Group based on the target
29938 * @param {string} target
29939 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29941 get: function(target) {
29942 if (typeof(this.groups[target]) == 'undefined') {
29946 return this.groups[target] ;
29955 * page DateSplitField.
29961 * @class Roo.bootstrap.DateSplitField
29962 * @extends Roo.bootstrap.Component
29963 * Bootstrap DateSplitField class
29964 * @cfg {string} fieldLabel - the label associated
29965 * @cfg {Number} labelWidth set the width of label (0-12)
29966 * @cfg {String} labelAlign (top|left)
29967 * @cfg {Boolean} dayAllowBlank (true|false) default false
29968 * @cfg {Boolean} monthAllowBlank (true|false) default false
29969 * @cfg {Boolean} yearAllowBlank (true|false) default false
29970 * @cfg {string} dayPlaceholder
29971 * @cfg {string} monthPlaceholder
29972 * @cfg {string} yearPlaceholder
29973 * @cfg {string} dayFormat default 'd'
29974 * @cfg {string} monthFormat default 'm'
29975 * @cfg {string} yearFormat default 'Y'
29976 * @cfg {Number} labellg set the width of label (1-12)
29977 * @cfg {Number} labelmd set the width of label (1-12)
29978 * @cfg {Number} labelsm set the width of label (1-12)
29979 * @cfg {Number} labelxs set the width of label (1-12)
29983 * Create a new DateSplitField
29984 * @param {Object} config The config object
29987 Roo.bootstrap.DateSplitField = function(config){
29988 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29994 * getting the data of years
29995 * @param {Roo.bootstrap.DateSplitField} this
29996 * @param {Object} years
30001 * getting the data of days
30002 * @param {Roo.bootstrap.DateSplitField} this
30003 * @param {Object} days
30008 * Fires after the field has been marked as invalid.
30009 * @param {Roo.form.Field} this
30010 * @param {String} msg The validation message
30015 * Fires after the field has been validated with no errors.
30016 * @param {Roo.form.Field} this
30022 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30025 labelAlign : 'top',
30027 dayAllowBlank : false,
30028 monthAllowBlank : false,
30029 yearAllowBlank : false,
30030 dayPlaceholder : '',
30031 monthPlaceholder : '',
30032 yearPlaceholder : '',
30036 isFormField : true,
30042 getAutoCreate : function()
30046 cls : 'row roo-date-split-field-group',
30051 cls : 'form-hidden-field roo-date-split-field-group-value',
30057 var labelCls = 'col-md-12';
30058 var contentCls = 'col-md-4';
30060 if(this.fieldLabel){
30064 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30068 html : this.fieldLabel
30073 if(this.labelAlign == 'left'){
30075 if(this.labelWidth > 12){
30076 label.style = "width: " + this.labelWidth + 'px';
30079 if(this.labelWidth < 13 && this.labelmd == 0){
30080 this.labelmd = this.labelWidth;
30083 if(this.labellg > 0){
30084 labelCls = ' col-lg-' + this.labellg;
30085 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30088 if(this.labelmd > 0){
30089 labelCls = ' col-md-' + this.labelmd;
30090 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30093 if(this.labelsm > 0){
30094 labelCls = ' col-sm-' + this.labelsm;
30095 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30098 if(this.labelxs > 0){
30099 labelCls = ' col-xs-' + this.labelxs;
30100 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30104 label.cls += ' ' + labelCls;
30106 cfg.cn.push(label);
30109 Roo.each(['day', 'month', 'year'], function(t){
30112 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30119 inputEl: function ()
30121 return this.el.select('.roo-date-split-field-group-value', true).first();
30124 onRender : function(ct, position)
30128 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30130 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30132 this.dayField = new Roo.bootstrap.ComboBox({
30133 allowBlank : this.dayAllowBlank,
30134 alwaysQuery : true,
30135 displayField : 'value',
30138 forceSelection : true,
30140 placeholder : this.dayPlaceholder,
30141 selectOnFocus : true,
30142 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30143 triggerAction : 'all',
30145 valueField : 'value',
30146 store : new Roo.data.SimpleStore({
30147 data : (function() {
30149 _this.fireEvent('days', _this, days);
30152 fields : [ 'value' ]
30155 select : function (_self, record, index)
30157 _this.setValue(_this.getValue());
30162 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30164 this.monthField = new Roo.bootstrap.MonthField({
30165 after : '<i class=\"fa fa-calendar\"></i>',
30166 allowBlank : this.monthAllowBlank,
30167 placeholder : this.monthPlaceholder,
30170 render : function (_self)
30172 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30173 e.preventDefault();
30177 select : function (_self, oldvalue, newvalue)
30179 _this.setValue(_this.getValue());
30184 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30186 this.yearField = new Roo.bootstrap.ComboBox({
30187 allowBlank : this.yearAllowBlank,
30188 alwaysQuery : true,
30189 displayField : 'value',
30192 forceSelection : true,
30194 placeholder : this.yearPlaceholder,
30195 selectOnFocus : true,
30196 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30197 triggerAction : 'all',
30199 valueField : 'value',
30200 store : new Roo.data.SimpleStore({
30201 data : (function() {
30203 _this.fireEvent('years', _this, years);
30206 fields : [ 'value' ]
30209 select : function (_self, record, index)
30211 _this.setValue(_this.getValue());
30216 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30219 setValue : function(v, format)
30221 this.inputEl.dom.value = v;
30223 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30225 var d = Date.parseDate(v, f);
30232 this.setDay(d.format(this.dayFormat));
30233 this.setMonth(d.format(this.monthFormat));
30234 this.setYear(d.format(this.yearFormat));
30241 setDay : function(v)
30243 this.dayField.setValue(v);
30244 this.inputEl.dom.value = this.getValue();
30249 setMonth : function(v)
30251 this.monthField.setValue(v, true);
30252 this.inputEl.dom.value = this.getValue();
30257 setYear : function(v)
30259 this.yearField.setValue(v);
30260 this.inputEl.dom.value = this.getValue();
30265 getDay : function()
30267 return this.dayField.getValue();
30270 getMonth : function()
30272 return this.monthField.getValue();
30275 getYear : function()
30277 return this.yearField.getValue();
30280 getValue : function()
30282 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30284 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30294 this.inputEl.dom.value = '';
30299 validate : function()
30301 var d = this.dayField.validate();
30302 var m = this.monthField.validate();
30303 var y = this.yearField.validate();
30308 (!this.dayAllowBlank && !d) ||
30309 (!this.monthAllowBlank && !m) ||
30310 (!this.yearAllowBlank && !y)
30315 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30324 this.markInvalid();
30329 markValid : function()
30332 var label = this.el.select('label', true).first();
30333 var icon = this.el.select('i.fa-star', true).first();
30339 this.fireEvent('valid', this);
30343 * Mark this field as invalid
30344 * @param {String} msg The validation message
30346 markInvalid : function(msg)
30349 var label = this.el.select('label', true).first();
30350 var icon = this.el.select('i.fa-star', true).first();
30352 if(label && !icon){
30353 this.el.select('.roo-date-split-field-label', true).createChild({
30355 cls : 'text-danger fa fa-lg fa-star',
30356 tooltip : 'This field is required',
30357 style : 'margin-right:5px;'
30361 this.fireEvent('invalid', this, msg);
30364 clearInvalid : function()
30366 var label = this.el.select('label', true).first();
30367 var icon = this.el.select('i.fa-star', true).first();
30373 this.fireEvent('valid', this);
30376 getName: function()
30386 * http://masonry.desandro.com
30388 * The idea is to render all the bricks based on vertical width...
30390 * The original code extends 'outlayer' - we might need to use that....
30396 * @class Roo.bootstrap.LayoutMasonry
30397 * @extends Roo.bootstrap.Component
30398 * Bootstrap Layout Masonry class
30401 * Create a new Element
30402 * @param {Object} config The config object
30405 Roo.bootstrap.LayoutMasonry = function(config){
30407 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30411 Roo.bootstrap.LayoutMasonry.register(this);
30417 * Fire after layout the items
30418 * @param {Roo.bootstrap.LayoutMasonry} this
30419 * @param {Roo.EventObject} e
30426 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30429 * @cfg {Boolean} isLayoutInstant = no animation?
30431 isLayoutInstant : false, // needed?
30434 * @cfg {Number} boxWidth width of the columns
30439 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30444 * @cfg {Number} padWidth padding below box..
30449 * @cfg {Number} gutter gutter width..
30454 * @cfg {Number} maxCols maximum number of columns
30460 * @cfg {Boolean} isAutoInitial defalut true
30462 isAutoInitial : true,
30467 * @cfg {Boolean} isHorizontal defalut false
30469 isHorizontal : false,
30471 currentSize : null,
30477 bricks: null, //CompositeElement
30481 _isLayoutInited : false,
30483 // isAlternative : false, // only use for vertical layout...
30486 * @cfg {Number} alternativePadWidth padding below box..
30488 alternativePadWidth : 50,
30490 selectedBrick : [],
30492 getAutoCreate : function(){
30494 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30498 cls: 'blog-masonary-wrapper ' + this.cls,
30500 cls : 'mas-boxes masonary'
30507 getChildContainer: function( )
30509 if (this.boxesEl) {
30510 return this.boxesEl;
30513 this.boxesEl = this.el.select('.mas-boxes').first();
30515 return this.boxesEl;
30519 initEvents : function()
30523 if(this.isAutoInitial){
30524 Roo.log('hook children rendered');
30525 this.on('childrenrendered', function() {
30526 Roo.log('children rendered');
30532 initial : function()
30534 this.selectedBrick = [];
30536 this.currentSize = this.el.getBox(true);
30538 Roo.EventManager.onWindowResize(this.resize, this);
30540 if(!this.isAutoInitial){
30548 //this.layout.defer(500,this);
30552 resize : function()
30554 var cs = this.el.getBox(true);
30557 this.currentSize.width == cs.width &&
30558 this.currentSize.x == cs.x &&
30559 this.currentSize.height == cs.height &&
30560 this.currentSize.y == cs.y
30562 Roo.log("no change in with or X or Y");
30566 this.currentSize = cs;
30572 layout : function()
30574 this._resetLayout();
30576 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30578 this.layoutItems( isInstant );
30580 this._isLayoutInited = true;
30582 this.fireEvent('layout', this);
30586 _resetLayout : function()
30588 if(this.isHorizontal){
30589 this.horizontalMeasureColumns();
30593 this.verticalMeasureColumns();
30597 verticalMeasureColumns : function()
30599 this.getContainerWidth();
30601 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30602 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30606 var boxWidth = this.boxWidth + this.padWidth;
30608 if(this.containerWidth < this.boxWidth){
30609 boxWidth = this.containerWidth
30612 var containerWidth = this.containerWidth;
30614 var cols = Math.floor(containerWidth / boxWidth);
30616 this.cols = Math.max( cols, 1 );
30618 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30620 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30622 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30624 this.colWidth = boxWidth + avail - this.padWidth;
30626 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30627 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30630 horizontalMeasureColumns : function()
30632 this.getContainerWidth();
30634 var boxWidth = this.boxWidth;
30636 if(this.containerWidth < boxWidth){
30637 boxWidth = this.containerWidth;
30640 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30642 this.el.setHeight(boxWidth);
30646 getContainerWidth : function()
30648 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30651 layoutItems : function( isInstant )
30653 Roo.log(this.bricks);
30655 var items = Roo.apply([], this.bricks);
30657 if(this.isHorizontal){
30658 this._horizontalLayoutItems( items , isInstant );
30662 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30663 // this._verticalAlternativeLayoutItems( items , isInstant );
30667 this._verticalLayoutItems( items , isInstant );
30671 _verticalLayoutItems : function ( items , isInstant)
30673 if ( !items || !items.length ) {
30678 ['xs', 'xs', 'xs', 'tall'],
30679 ['xs', 'xs', 'tall'],
30680 ['xs', 'xs', 'sm'],
30681 ['xs', 'xs', 'xs'],
30687 ['sm', 'xs', 'xs'],
30691 ['tall', 'xs', 'xs', 'xs'],
30692 ['tall', 'xs', 'xs'],
30704 Roo.each(items, function(item, k){
30706 switch (item.size) {
30707 // these layouts take up a full box,
30718 boxes.push([item]);
30741 var filterPattern = function(box, length)
30749 var pattern = box.slice(0, length);
30753 Roo.each(pattern, function(i){
30754 format.push(i.size);
30757 Roo.each(standard, function(s){
30759 if(String(s) != String(format)){
30768 if(!match && length == 1){
30773 filterPattern(box, length - 1);
30777 queue.push(pattern);
30779 box = box.slice(length, box.length);
30781 filterPattern(box, 4);
30787 Roo.each(boxes, function(box, k){
30793 if(box.length == 1){
30798 filterPattern(box, 4);
30802 this._processVerticalLayoutQueue( queue, isInstant );
30806 // _verticalAlternativeLayoutItems : function( items , isInstant )
30808 // if ( !items || !items.length ) {
30812 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30816 _horizontalLayoutItems : function ( items , isInstant)
30818 if ( !items || !items.length || items.length < 3) {
30824 var eItems = items.slice(0, 3);
30826 items = items.slice(3, items.length);
30829 ['xs', 'xs', 'xs', 'wide'],
30830 ['xs', 'xs', 'wide'],
30831 ['xs', 'xs', 'sm'],
30832 ['xs', 'xs', 'xs'],
30838 ['sm', 'xs', 'xs'],
30842 ['wide', 'xs', 'xs', 'xs'],
30843 ['wide', 'xs', 'xs'],
30856 Roo.each(items, function(item, k){
30858 switch (item.size) {
30869 boxes.push([item]);
30893 var filterPattern = function(box, length)
30901 var pattern = box.slice(0, length);
30905 Roo.each(pattern, function(i){
30906 format.push(i.size);
30909 Roo.each(standard, function(s){
30911 if(String(s) != String(format)){
30920 if(!match && length == 1){
30925 filterPattern(box, length - 1);
30929 queue.push(pattern);
30931 box = box.slice(length, box.length);
30933 filterPattern(box, 4);
30939 Roo.each(boxes, function(box, k){
30945 if(box.length == 1){
30950 filterPattern(box, 4);
30957 var pos = this.el.getBox(true);
30961 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30963 var hit_end = false;
30965 Roo.each(queue, function(box){
30969 Roo.each(box, function(b){
30971 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30981 Roo.each(box, function(b){
30983 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30986 mx = Math.max(mx, b.x);
30990 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30994 Roo.each(box, function(b){
30996 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31010 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31013 /** Sets position of item in DOM
31014 * @param {Element} item
31015 * @param {Number} x - horizontal position
31016 * @param {Number} y - vertical position
31017 * @param {Boolean} isInstant - disables transitions
31019 _processVerticalLayoutQueue : function( queue, isInstant )
31021 var pos = this.el.getBox(true);
31026 for (var i = 0; i < this.cols; i++){
31030 Roo.each(queue, function(box, k){
31032 var col = k % this.cols;
31034 Roo.each(box, function(b,kk){
31036 b.el.position('absolute');
31038 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31039 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31041 if(b.size == 'md-left' || b.size == 'md-right'){
31042 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31043 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31046 b.el.setWidth(width);
31047 b.el.setHeight(height);
31049 b.el.select('iframe',true).setSize(width,height);
31053 for (var i = 0; i < this.cols; i++){
31055 if(maxY[i] < maxY[col]){
31060 col = Math.min(col, i);
31064 x = pos.x + col * (this.colWidth + this.padWidth);
31068 var positions = [];
31070 switch (box.length){
31072 positions = this.getVerticalOneBoxColPositions(x, y, box);
31075 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31078 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31081 positions = this.getVerticalFourBoxColPositions(x, y, box);
31087 Roo.each(box, function(b,kk){
31089 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31091 var sz = b.el.getSize();
31093 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31101 for (var i = 0; i < this.cols; i++){
31102 mY = Math.max(mY, maxY[i]);
31105 this.el.setHeight(mY - pos.y);
31109 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31111 // var pos = this.el.getBox(true);
31114 // var maxX = pos.right;
31116 // var maxHeight = 0;
31118 // Roo.each(items, function(item, k){
31122 // item.el.position('absolute');
31124 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31126 // item.el.setWidth(width);
31128 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31130 // item.el.setHeight(height);
31133 // item.el.setXY([x, y], isInstant ? false : true);
31135 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31138 // y = y + height + this.alternativePadWidth;
31140 // maxHeight = maxHeight + height + this.alternativePadWidth;
31144 // this.el.setHeight(maxHeight);
31148 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31150 var pos = this.el.getBox(true);
31155 var maxX = pos.right;
31157 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31159 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31161 Roo.each(queue, function(box, k){
31163 Roo.each(box, function(b, kk){
31165 b.el.position('absolute');
31167 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31168 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31170 if(b.size == 'md-left' || b.size == 'md-right'){
31171 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31172 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31175 b.el.setWidth(width);
31176 b.el.setHeight(height);
31184 var positions = [];
31186 switch (box.length){
31188 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31191 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31194 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31197 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31203 Roo.each(box, function(b,kk){
31205 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31207 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31215 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31217 Roo.each(eItems, function(b,k){
31219 b.size = (k == 0) ? 'sm' : 'xs';
31220 b.x = (k == 0) ? 2 : 1;
31221 b.y = (k == 0) ? 2 : 1;
31223 b.el.position('absolute');
31225 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31227 b.el.setWidth(width);
31229 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31231 b.el.setHeight(height);
31235 var positions = [];
31238 x : maxX - this.unitWidth * 2 - this.gutter,
31243 x : maxX - this.unitWidth,
31244 y : minY + (this.unitWidth + this.gutter) * 2
31248 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31252 Roo.each(eItems, function(b,k){
31254 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31260 getVerticalOneBoxColPositions : function(x, y, box)
31264 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31266 if(box[0].size == 'md-left'){
31270 if(box[0].size == 'md-right'){
31275 x : x + (this.unitWidth + this.gutter) * rand,
31282 getVerticalTwoBoxColPositions : function(x, y, box)
31286 if(box[0].size == 'xs'){
31290 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31294 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31308 x : x + (this.unitWidth + this.gutter) * 2,
31309 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31316 getVerticalThreeBoxColPositions : function(x, y, box)
31320 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31328 x : x + (this.unitWidth + this.gutter) * 1,
31333 x : x + (this.unitWidth + this.gutter) * 2,
31341 if(box[0].size == 'xs' && box[1].size == 'xs'){
31350 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31354 x : x + (this.unitWidth + this.gutter) * 1,
31368 x : x + (this.unitWidth + this.gutter) * 2,
31373 x : x + (this.unitWidth + this.gutter) * 2,
31374 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31381 getVerticalFourBoxColPositions : function(x, y, box)
31385 if(box[0].size == 'xs'){
31394 y : y + (this.unitHeight + this.gutter) * 1
31399 y : y + (this.unitHeight + this.gutter) * 2
31403 x : x + (this.unitWidth + this.gutter) * 1,
31417 x : x + (this.unitWidth + this.gutter) * 2,
31422 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31423 y : y + (this.unitHeight + this.gutter) * 1
31427 x : x + (this.unitWidth + this.gutter) * 2,
31428 y : y + (this.unitWidth + this.gutter) * 2
31435 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31439 if(box[0].size == 'md-left'){
31441 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31448 if(box[0].size == 'md-right'){
31450 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31451 y : minY + (this.unitWidth + this.gutter) * 1
31457 var rand = Math.floor(Math.random() * (4 - box[0].y));
31460 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31461 y : minY + (this.unitWidth + this.gutter) * rand
31468 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31472 if(box[0].size == 'xs'){
31475 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31480 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31481 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31489 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31494 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31495 y : minY + (this.unitWidth + this.gutter) * 2
31502 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31506 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31509 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31514 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31515 y : minY + (this.unitWidth + this.gutter) * 1
31519 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31520 y : minY + (this.unitWidth + this.gutter) * 2
31527 if(box[0].size == 'xs' && box[1].size == 'xs'){
31530 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31535 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31540 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31541 y : minY + (this.unitWidth + this.gutter) * 1
31549 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31554 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31555 y : minY + (this.unitWidth + this.gutter) * 2
31559 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31560 y : minY + (this.unitWidth + this.gutter) * 2
31567 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31571 if(box[0].size == 'xs'){
31574 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31579 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31584 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),
31589 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31590 y : minY + (this.unitWidth + this.gutter) * 1
31598 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31603 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31604 y : minY + (this.unitWidth + this.gutter) * 2
31608 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31609 y : minY + (this.unitWidth + this.gutter) * 2
31613 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),
31614 y : minY + (this.unitWidth + this.gutter) * 2
31622 * remove a Masonry Brick
31623 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31625 removeBrick : function(brick_id)
31631 for (var i = 0; i<this.bricks.length; i++) {
31632 if (this.bricks[i].id == brick_id) {
31633 this.bricks.splice(i,1);
31634 this.el.dom.removeChild(Roo.get(brick_id).dom);
31641 * adds a Masonry Brick
31642 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31644 addBrick : function(cfg)
31646 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31647 //this.register(cn);
31648 cn.parentId = this.id;
31649 cn.onRender(this.el, null);
31654 * register a Masonry Brick
31655 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31658 register : function(brick)
31660 this.bricks.push(brick);
31661 brick.masonryId = this.id;
31665 * clear all the Masonry Brick
31667 clearAll : function()
31670 //this.getChildContainer().dom.innerHTML = "";
31671 this.el.dom.innerHTML = '';
31674 getSelected : function()
31676 if (!this.selectedBrick) {
31680 return this.selectedBrick;
31684 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31688 * register a Masonry Layout
31689 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31692 register : function(layout)
31694 this.groups[layout.id] = layout;
31697 * fetch a Masonry Layout based on the masonry layout ID
31698 * @param {string} the masonry layout to add
31699 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31702 get: function(layout_id) {
31703 if (typeof(this.groups[layout_id]) == 'undefined') {
31706 return this.groups[layout_id] ;
31718 * http://masonry.desandro.com
31720 * The idea is to render all the bricks based on vertical width...
31722 * The original code extends 'outlayer' - we might need to use that....
31728 * @class Roo.bootstrap.LayoutMasonryAuto
31729 * @extends Roo.bootstrap.Component
31730 * Bootstrap Layout Masonry class
31733 * Create a new Element
31734 * @param {Object} config The config object
31737 Roo.bootstrap.LayoutMasonryAuto = function(config){
31738 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31741 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31744 * @cfg {Boolean} isFitWidth - resize the width..
31746 isFitWidth : false, // options..
31748 * @cfg {Boolean} isOriginLeft = left align?
31750 isOriginLeft : true,
31752 * @cfg {Boolean} isOriginTop = top align?
31754 isOriginTop : false,
31756 * @cfg {Boolean} isLayoutInstant = no animation?
31758 isLayoutInstant : false, // needed?
31760 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31762 isResizingContainer : true,
31764 * @cfg {Number} columnWidth width of the columns
31770 * @cfg {Number} maxCols maximum number of columns
31775 * @cfg {Number} padHeight padding below box..
31781 * @cfg {Boolean} isAutoInitial defalut true
31784 isAutoInitial : true,
31790 initialColumnWidth : 0,
31791 currentSize : null,
31793 colYs : null, // array.
31800 bricks: null, //CompositeElement
31801 cols : 0, // array?
31802 // element : null, // wrapped now this.el
31803 _isLayoutInited : null,
31806 getAutoCreate : function(){
31810 cls: 'blog-masonary-wrapper ' + this.cls,
31812 cls : 'mas-boxes masonary'
31819 getChildContainer: function( )
31821 if (this.boxesEl) {
31822 return this.boxesEl;
31825 this.boxesEl = this.el.select('.mas-boxes').first();
31827 return this.boxesEl;
31831 initEvents : function()
31835 if(this.isAutoInitial){
31836 Roo.log('hook children rendered');
31837 this.on('childrenrendered', function() {
31838 Roo.log('children rendered');
31845 initial : function()
31847 this.reloadItems();
31849 this.currentSize = this.el.getBox(true);
31851 /// was window resize... - let's see if this works..
31852 Roo.EventManager.onWindowResize(this.resize, this);
31854 if(!this.isAutoInitial){
31859 this.layout.defer(500,this);
31862 reloadItems: function()
31864 this.bricks = this.el.select('.masonry-brick', true);
31866 this.bricks.each(function(b) {
31867 //Roo.log(b.getSize());
31868 if (!b.attr('originalwidth')) {
31869 b.attr('originalwidth', b.getSize().width);
31874 Roo.log(this.bricks.elements.length);
31877 resize : function()
31880 var cs = this.el.getBox(true);
31882 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31883 Roo.log("no change in with or X");
31886 this.currentSize = cs;
31890 layout : function()
31893 this._resetLayout();
31894 //this._manageStamps();
31896 // don't animate first layout
31897 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31898 this.layoutItems( isInstant );
31900 // flag for initalized
31901 this._isLayoutInited = true;
31904 layoutItems : function( isInstant )
31906 //var items = this._getItemsForLayout( this.items );
31907 // original code supports filtering layout items.. we just ignore it..
31909 this._layoutItems( this.bricks , isInstant );
31911 this._postLayout();
31913 _layoutItems : function ( items , isInstant)
31915 //this.fireEvent( 'layout', this, items );
31918 if ( !items || !items.elements.length ) {
31919 // no items, emit event with empty array
31924 items.each(function(item) {
31925 Roo.log("layout item");
31927 // get x/y object from method
31928 var position = this._getItemLayoutPosition( item );
31930 position.item = item;
31931 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31932 queue.push( position );
31935 this._processLayoutQueue( queue );
31937 /** Sets position of item in DOM
31938 * @param {Element} item
31939 * @param {Number} x - horizontal position
31940 * @param {Number} y - vertical position
31941 * @param {Boolean} isInstant - disables transitions
31943 _processLayoutQueue : function( queue )
31945 for ( var i=0, len = queue.length; i < len; i++ ) {
31946 var obj = queue[i];
31947 obj.item.position('absolute');
31948 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31954 * Any logic you want to do after each layout,
31955 * i.e. size the container
31957 _postLayout : function()
31959 this.resizeContainer();
31962 resizeContainer : function()
31964 if ( !this.isResizingContainer ) {
31967 var size = this._getContainerSize();
31969 this.el.setSize(size.width,size.height);
31970 this.boxesEl.setSize(size.width,size.height);
31976 _resetLayout : function()
31978 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31979 this.colWidth = this.el.getWidth();
31980 //this.gutter = this.el.getWidth();
31982 this.measureColumns();
31988 this.colYs.push( 0 );
31994 measureColumns : function()
31996 this.getContainerWidth();
31997 // if columnWidth is 0, default to outerWidth of first item
31998 if ( !this.columnWidth ) {
31999 var firstItem = this.bricks.first();
32000 Roo.log(firstItem);
32001 this.columnWidth = this.containerWidth;
32002 if (firstItem && firstItem.attr('originalwidth') ) {
32003 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32005 // columnWidth fall back to item of first element
32006 Roo.log("set column width?");
32007 this.initialColumnWidth = this.columnWidth ;
32009 // if first elem has no width, default to size of container
32014 if (this.initialColumnWidth) {
32015 this.columnWidth = this.initialColumnWidth;
32020 // column width is fixed at the top - however if container width get's smaller we should
32023 // this bit calcs how man columns..
32025 var columnWidth = this.columnWidth += this.gutter;
32027 // calculate columns
32028 var containerWidth = this.containerWidth + this.gutter;
32030 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32031 // fix rounding errors, typically with gutters
32032 var excess = columnWidth - containerWidth % columnWidth;
32035 // if overshoot is less than a pixel, round up, otherwise floor it
32036 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32037 cols = Math[ mathMethod ]( cols );
32038 this.cols = Math.max( cols, 1 );
32039 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32041 // padding positioning..
32042 var totalColWidth = this.cols * this.columnWidth;
32043 var padavail = this.containerWidth - totalColWidth;
32044 // so for 2 columns - we need 3 'pads'
32046 var padNeeded = (1+this.cols) * this.padWidth;
32048 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32050 this.columnWidth += padExtra
32051 //this.padWidth = Math.floor(padavail / ( this.cols));
32053 // adjust colum width so that padding is fixed??
32055 // we have 3 columns ... total = width * 3
32056 // we have X left over... that should be used by
32058 //if (this.expandC) {
32066 getContainerWidth : function()
32068 /* // container is parent if fit width
32069 var container = this.isFitWidth ? this.element.parentNode : this.element;
32070 // check that this.size and size are there
32071 // IE8 triggers resize on body size change, so they might not be
32073 var size = getSize( container ); //FIXME
32074 this.containerWidth = size && size.innerWidth; //FIXME
32077 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32081 _getItemLayoutPosition : function( item ) // what is item?
32083 // we resize the item to our columnWidth..
32085 item.setWidth(this.columnWidth);
32086 item.autoBoxAdjust = false;
32088 var sz = item.getSize();
32090 // how many columns does this brick span
32091 var remainder = this.containerWidth % this.columnWidth;
32093 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32094 // round if off by 1 pixel, otherwise use ceil
32095 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32096 colSpan = Math.min( colSpan, this.cols );
32098 // normally this should be '1' as we dont' currently allow multi width columns..
32100 var colGroup = this._getColGroup( colSpan );
32101 // get the minimum Y value from the columns
32102 var minimumY = Math.min.apply( Math, colGroup );
32103 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32105 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32107 // position the brick
32109 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32110 y: this.currentSize.y + minimumY + this.padHeight
32114 // apply setHeight to necessary columns
32115 var setHeight = minimumY + sz.height + this.padHeight;
32116 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32118 var setSpan = this.cols + 1 - colGroup.length;
32119 for ( var i = 0; i < setSpan; i++ ) {
32120 this.colYs[ shortColIndex + i ] = setHeight ;
32127 * @param {Number} colSpan - number of columns the element spans
32128 * @returns {Array} colGroup
32130 _getColGroup : function( colSpan )
32132 if ( colSpan < 2 ) {
32133 // if brick spans only one column, use all the column Ys
32138 // how many different places could this brick fit horizontally
32139 var groupCount = this.cols + 1 - colSpan;
32140 // for each group potential horizontal position
32141 for ( var i = 0; i < groupCount; i++ ) {
32142 // make an array of colY values for that one group
32143 var groupColYs = this.colYs.slice( i, i + colSpan );
32144 // and get the max value of the array
32145 colGroup[i] = Math.max.apply( Math, groupColYs );
32150 _manageStamp : function( stamp )
32152 var stampSize = stamp.getSize();
32153 var offset = stamp.getBox();
32154 // get the columns that this stamp affects
32155 var firstX = this.isOriginLeft ? offset.x : offset.right;
32156 var lastX = firstX + stampSize.width;
32157 var firstCol = Math.floor( firstX / this.columnWidth );
32158 firstCol = Math.max( 0, firstCol );
32160 var lastCol = Math.floor( lastX / this.columnWidth );
32161 // lastCol should not go over if multiple of columnWidth #425
32162 lastCol -= lastX % this.columnWidth ? 0 : 1;
32163 lastCol = Math.min( this.cols - 1, lastCol );
32165 // set colYs to bottom of the stamp
32166 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32169 for ( var i = firstCol; i <= lastCol; i++ ) {
32170 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32175 _getContainerSize : function()
32177 this.maxY = Math.max.apply( Math, this.colYs );
32182 if ( this.isFitWidth ) {
32183 size.width = this._getContainerFitWidth();
32189 _getContainerFitWidth : function()
32191 var unusedCols = 0;
32192 // count unused columns
32195 if ( this.colYs[i] !== 0 ) {
32200 // fit container to columns that have been used
32201 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32204 needsResizeLayout : function()
32206 var previousWidth = this.containerWidth;
32207 this.getContainerWidth();
32208 return previousWidth !== this.containerWidth;
32223 * @class Roo.bootstrap.MasonryBrick
32224 * @extends Roo.bootstrap.Component
32225 * Bootstrap MasonryBrick class
32228 * Create a new MasonryBrick
32229 * @param {Object} config The config object
32232 Roo.bootstrap.MasonryBrick = function(config){
32234 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32236 Roo.bootstrap.MasonryBrick.register(this);
32242 * When a MasonryBrick is clcik
32243 * @param {Roo.bootstrap.MasonryBrick} this
32244 * @param {Roo.EventObject} e
32250 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32253 * @cfg {String} title
32257 * @cfg {String} html
32261 * @cfg {String} bgimage
32265 * @cfg {String} videourl
32269 * @cfg {String} cls
32273 * @cfg {String} href
32277 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32282 * @cfg {String} placetitle (center|bottom)
32287 * @cfg {Boolean} isFitContainer defalut true
32289 isFitContainer : true,
32292 * @cfg {Boolean} preventDefault defalut false
32294 preventDefault : false,
32297 * @cfg {Boolean} inverse defalut false
32299 maskInverse : false,
32301 getAutoCreate : function()
32303 if(!this.isFitContainer){
32304 return this.getSplitAutoCreate();
32307 var cls = 'masonry-brick masonry-brick-full';
32309 if(this.href.length){
32310 cls += ' masonry-brick-link';
32313 if(this.bgimage.length){
32314 cls += ' masonry-brick-image';
32317 if(this.maskInverse){
32318 cls += ' mask-inverse';
32321 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32322 cls += ' enable-mask';
32326 cls += ' masonry-' + this.size + '-brick';
32329 if(this.placetitle.length){
32331 switch (this.placetitle) {
32333 cls += ' masonry-center-title';
32336 cls += ' masonry-bottom-title';
32343 if(!this.html.length && !this.bgimage.length){
32344 cls += ' masonry-center-title';
32347 if(!this.html.length && this.bgimage.length){
32348 cls += ' masonry-bottom-title';
32353 cls += ' ' + this.cls;
32357 tag: (this.href.length) ? 'a' : 'div',
32362 cls: 'masonry-brick-mask'
32366 cls: 'masonry-brick-paragraph',
32372 if(this.href.length){
32373 cfg.href = this.href;
32376 var cn = cfg.cn[1].cn;
32378 if(this.title.length){
32381 cls: 'masonry-brick-title',
32386 if(this.html.length){
32389 cls: 'masonry-brick-text',
32394 if (!this.title.length && !this.html.length) {
32395 cfg.cn[1].cls += ' hide';
32398 if(this.bgimage.length){
32401 cls: 'masonry-brick-image-view',
32406 if(this.videourl.length){
32407 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32408 // youtube support only?
32411 cls: 'masonry-brick-image-view',
32414 allowfullscreen : true
32422 getSplitAutoCreate : function()
32424 var cls = 'masonry-brick masonry-brick-split';
32426 if(this.href.length){
32427 cls += ' masonry-brick-link';
32430 if(this.bgimage.length){
32431 cls += ' masonry-brick-image';
32435 cls += ' masonry-' + this.size + '-brick';
32438 switch (this.placetitle) {
32440 cls += ' masonry-center-title';
32443 cls += ' masonry-bottom-title';
32446 if(!this.bgimage.length){
32447 cls += ' masonry-center-title';
32450 if(this.bgimage.length){
32451 cls += ' masonry-bottom-title';
32457 cls += ' ' + this.cls;
32461 tag: (this.href.length) ? 'a' : 'div',
32466 cls: 'masonry-brick-split-head',
32470 cls: 'masonry-brick-paragraph',
32477 cls: 'masonry-brick-split-body',
32483 if(this.href.length){
32484 cfg.href = this.href;
32487 if(this.title.length){
32488 cfg.cn[0].cn[0].cn.push({
32490 cls: 'masonry-brick-title',
32495 if(this.html.length){
32496 cfg.cn[1].cn.push({
32498 cls: 'masonry-brick-text',
32503 if(this.bgimage.length){
32504 cfg.cn[0].cn.push({
32506 cls: 'masonry-brick-image-view',
32511 if(this.videourl.length){
32512 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32513 // youtube support only?
32514 cfg.cn[0].cn.cn.push({
32516 cls: 'masonry-brick-image-view',
32519 allowfullscreen : true
32526 initEvents: function()
32528 switch (this.size) {
32561 this.el.on('touchstart', this.onTouchStart, this);
32562 this.el.on('touchmove', this.onTouchMove, this);
32563 this.el.on('touchend', this.onTouchEnd, this);
32564 this.el.on('contextmenu', this.onContextMenu, this);
32566 this.el.on('mouseenter' ,this.enter, this);
32567 this.el.on('mouseleave', this.leave, this);
32568 this.el.on('click', this.onClick, this);
32571 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32572 this.parent().bricks.push(this);
32577 onClick: function(e, el)
32579 var time = this.endTimer - this.startTimer;
32580 // Roo.log(e.preventDefault());
32583 e.preventDefault();
32588 if(!this.preventDefault){
32592 e.preventDefault();
32594 if (this.activcClass != '') {
32595 this.selectBrick();
32598 this.fireEvent('click', this);
32601 enter: function(e, el)
32603 e.preventDefault();
32605 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32609 if(this.bgimage.length && this.html.length){
32610 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32614 leave: function(e, el)
32616 e.preventDefault();
32618 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32622 if(this.bgimage.length && this.html.length){
32623 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32627 onTouchStart: function(e, el)
32629 // e.preventDefault();
32631 this.touchmoved = false;
32633 if(!this.isFitContainer){
32637 if(!this.bgimage.length || !this.html.length){
32641 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32643 this.timer = new Date().getTime();
32647 onTouchMove: function(e, el)
32649 this.touchmoved = true;
32652 onContextMenu : function(e,el)
32654 e.preventDefault();
32655 e.stopPropagation();
32659 onTouchEnd: function(e, el)
32661 // e.preventDefault();
32663 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32670 if(!this.bgimage.length || !this.html.length){
32672 if(this.href.length){
32673 window.location.href = this.href;
32679 if(!this.isFitContainer){
32683 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32685 window.location.href = this.href;
32688 //selection on single brick only
32689 selectBrick : function() {
32691 if (!this.parentId) {
32695 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32696 var index = m.selectedBrick.indexOf(this.id);
32699 m.selectedBrick.splice(index,1);
32700 this.el.removeClass(this.activeClass);
32704 for(var i = 0; i < m.selectedBrick.length; i++) {
32705 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32706 b.el.removeClass(b.activeClass);
32709 m.selectedBrick = [];
32711 m.selectedBrick.push(this.id);
32712 this.el.addClass(this.activeClass);
32718 Roo.apply(Roo.bootstrap.MasonryBrick, {
32721 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32723 * register a Masonry Brick
32724 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32727 register : function(brick)
32729 //this.groups[brick.id] = brick;
32730 this.groups.add(brick.id, brick);
32733 * fetch a masonry brick based on the masonry brick ID
32734 * @param {string} the masonry brick to add
32735 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32738 get: function(brick_id)
32740 // if (typeof(this.groups[brick_id]) == 'undefined') {
32743 // return this.groups[brick_id] ;
32745 if(this.groups.key(brick_id)) {
32746 return this.groups.key(brick_id);
32764 * @class Roo.bootstrap.Brick
32765 * @extends Roo.bootstrap.Component
32766 * Bootstrap Brick class
32769 * Create a new Brick
32770 * @param {Object} config The config object
32773 Roo.bootstrap.Brick = function(config){
32774 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32780 * When a Brick is click
32781 * @param {Roo.bootstrap.Brick} this
32782 * @param {Roo.EventObject} e
32788 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32791 * @cfg {String} title
32795 * @cfg {String} html
32799 * @cfg {String} bgimage
32803 * @cfg {String} cls
32807 * @cfg {String} href
32811 * @cfg {String} video
32815 * @cfg {Boolean} square
32819 getAutoCreate : function()
32821 var cls = 'roo-brick';
32823 if(this.href.length){
32824 cls += ' roo-brick-link';
32827 if(this.bgimage.length){
32828 cls += ' roo-brick-image';
32831 if(!this.html.length && !this.bgimage.length){
32832 cls += ' roo-brick-center-title';
32835 if(!this.html.length && this.bgimage.length){
32836 cls += ' roo-brick-bottom-title';
32840 cls += ' ' + this.cls;
32844 tag: (this.href.length) ? 'a' : 'div',
32849 cls: 'roo-brick-paragraph',
32855 if(this.href.length){
32856 cfg.href = this.href;
32859 var cn = cfg.cn[0].cn;
32861 if(this.title.length){
32864 cls: 'roo-brick-title',
32869 if(this.html.length){
32872 cls: 'roo-brick-text',
32879 if(this.bgimage.length){
32882 cls: 'roo-brick-image-view',
32890 initEvents: function()
32892 if(this.title.length || this.html.length){
32893 this.el.on('mouseenter' ,this.enter, this);
32894 this.el.on('mouseleave', this.leave, this);
32897 Roo.EventManager.onWindowResize(this.resize, this);
32899 if(this.bgimage.length){
32900 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32901 this.imageEl.on('load', this.onImageLoad, this);
32908 onImageLoad : function()
32913 resize : function()
32915 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32917 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32919 if(this.bgimage.length){
32920 var image = this.el.select('.roo-brick-image-view', true).first();
32922 image.setWidth(paragraph.getWidth());
32925 image.setHeight(paragraph.getWidth());
32928 this.el.setHeight(image.getHeight());
32929 paragraph.setHeight(image.getHeight());
32935 enter: function(e, el)
32937 e.preventDefault();
32939 if(this.bgimage.length){
32940 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32941 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32945 leave: function(e, el)
32947 e.preventDefault();
32949 if(this.bgimage.length){
32950 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32951 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32967 * @class Roo.bootstrap.NumberField
32968 * @extends Roo.bootstrap.Input
32969 * Bootstrap NumberField class
32975 * Create a new NumberField
32976 * @param {Object} config The config object
32979 Roo.bootstrap.NumberField = function(config){
32980 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32983 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32986 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32988 allowDecimals : true,
32990 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32992 decimalSeparator : ".",
32994 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32996 decimalPrecision : 2,
32998 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33000 allowNegative : true,
33002 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33004 minValue : Number.NEGATIVE_INFINITY,
33006 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33008 maxValue : Number.MAX_VALUE,
33010 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33012 minText : "The minimum value for this field is {0}",
33014 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33016 maxText : "The maximum value for this field is {0}",
33018 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33019 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33021 nanText : "{0} is not a valid number",
33023 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33028 initEvents : function()
33030 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33032 var allowed = "0123456789";
33034 if(this.allowDecimals){
33035 allowed += this.decimalSeparator;
33038 if(this.allowNegative){
33042 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33044 var keyPress = function(e){
33046 var k = e.getKey();
33048 var c = e.getCharCode();
33051 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33052 allowed.indexOf(String.fromCharCode(c)) === -1
33058 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33062 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33067 this.el.on("keypress", keyPress, this);
33070 validateValue : function(value)
33073 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33077 var num = this.parseValue(value);
33080 this.markInvalid(String.format(this.nanText, value));
33084 if(num < this.minValue){
33085 this.markInvalid(String.format(this.minText, this.minValue));
33089 if(num > this.maxValue){
33090 this.markInvalid(String.format(this.maxText, this.maxValue));
33097 getValue : function()
33099 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33102 parseValue : function(value)
33104 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33105 return isNaN(value) ? '' : value;
33108 fixPrecision : function(value)
33110 var nan = isNaN(value);
33112 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33113 return nan ? '' : value;
33115 return parseFloat(value).toFixed(this.decimalPrecision);
33118 setValue : function(v)
33120 v = this.fixPrecision(v);
33121 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33124 decimalPrecisionFcn : function(v)
33126 return Math.floor(v);
33129 beforeBlur : function()
33135 var v = this.parseValue(this.getRawValue());
33150 * @class Roo.bootstrap.DocumentSlider
33151 * @extends Roo.bootstrap.Component
33152 * Bootstrap DocumentSlider class
33155 * Create a new DocumentViewer
33156 * @param {Object} config The config object
33159 Roo.bootstrap.DocumentSlider = function(config){
33160 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33167 * Fire after initEvent
33168 * @param {Roo.bootstrap.DocumentSlider} this
33173 * Fire after update
33174 * @param {Roo.bootstrap.DocumentSlider} this
33180 * @param {Roo.bootstrap.DocumentSlider} this
33186 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33192 getAutoCreate : function()
33196 cls : 'roo-document-slider',
33200 cls : 'roo-document-slider-header',
33204 cls : 'roo-document-slider-header-title'
33210 cls : 'roo-document-slider-body',
33214 cls : 'roo-document-slider-prev',
33218 cls : 'fa fa-chevron-left'
33224 cls : 'roo-document-slider-thumb',
33228 cls : 'roo-document-slider-image'
33234 cls : 'roo-document-slider-next',
33238 cls : 'fa fa-chevron-right'
33250 initEvents : function()
33252 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33253 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33255 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33256 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33258 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33259 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33261 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33262 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33264 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33265 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33267 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33268 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33270 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33271 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33273 this.thumbEl.on('click', this.onClick, this);
33275 this.prevIndicator.on('click', this.prev, this);
33277 this.nextIndicator.on('click', this.next, this);
33281 initial : function()
33283 if(this.files.length){
33284 this.indicator = 1;
33288 this.fireEvent('initial', this);
33291 update : function()
33293 this.imageEl.attr('src', this.files[this.indicator - 1]);
33295 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33297 this.prevIndicator.show();
33299 if(this.indicator == 1){
33300 this.prevIndicator.hide();
33303 this.nextIndicator.show();
33305 if(this.indicator == this.files.length){
33306 this.nextIndicator.hide();
33309 this.thumbEl.scrollTo('top');
33311 this.fireEvent('update', this);
33314 onClick : function(e)
33316 e.preventDefault();
33318 this.fireEvent('click', this);
33323 e.preventDefault();
33325 this.indicator = Math.max(1, this.indicator - 1);
33332 e.preventDefault();
33334 this.indicator = Math.min(this.files.length, this.indicator + 1);
33348 * @class Roo.bootstrap.RadioSet
33349 * @extends Roo.bootstrap.Input
33350 * Bootstrap RadioSet class
33351 * @cfg {String} indicatorpos (left|right) default left
33352 * @cfg {Boolean} inline (true|false) inline the element (default true)
33353 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33355 * Create a new RadioSet
33356 * @param {Object} config The config object
33359 Roo.bootstrap.RadioSet = function(config){
33361 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33365 Roo.bootstrap.RadioSet.register(this);
33370 * Fires when the element is checked or unchecked.
33371 * @param {Roo.bootstrap.RadioSet} this This radio
33372 * @param {Roo.bootstrap.Radio} item The checked item
33379 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33387 indicatorpos : 'left',
33389 getAutoCreate : function()
33393 cls : 'roo-radio-set-label',
33397 html : this.fieldLabel
33402 if(this.indicatorpos == 'left'){
33405 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33406 tooltip : 'This field is required'
33411 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33412 tooltip : 'This field is required'
33418 cls : 'roo-radio-set-items'
33421 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33423 if (align === 'left' && this.fieldLabel.length) {
33426 cls : "roo-radio-set-right",
33432 if(this.labelWidth > 12){
33433 label.style = "width: " + this.labelWidth + 'px';
33436 if(this.labelWidth < 13 && this.labelmd == 0){
33437 this.labelmd = this.labelWidth;
33440 if(this.labellg > 0){
33441 label.cls += ' col-lg-' + this.labellg;
33442 items.cls += ' col-lg-' + (12 - this.labellg);
33445 if(this.labelmd > 0){
33446 label.cls += ' col-md-' + this.labelmd;
33447 items.cls += ' col-md-' + (12 - this.labelmd);
33450 if(this.labelsm > 0){
33451 label.cls += ' col-sm-' + this.labelsm;
33452 items.cls += ' col-sm-' + (12 - this.labelsm);
33455 if(this.labelxs > 0){
33456 label.cls += ' col-xs-' + this.labelxs;
33457 items.cls += ' col-xs-' + (12 - this.labelxs);
33463 cls : 'roo-radio-set',
33467 cls : 'roo-radio-set-input',
33470 value : this.value ? this.value : ''
33477 if(this.weight.length){
33478 cfg.cls += ' roo-radio-' + this.weight;
33482 cfg.cls += ' roo-radio-set-inline';
33486 ['xs','sm','md','lg'].map(function(size){
33487 if (settings[size]) {
33488 cfg.cls += ' col-' + size + '-' + settings[size];
33496 initEvents : function()
33498 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33499 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33501 if(!this.fieldLabel.length){
33502 this.labelEl.hide();
33505 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33506 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33508 this.indicatorEl().addClass('invisible');
33510 this.originalValue = this.getValue();
33514 inputEl: function ()
33516 return this.el.select('.roo-radio-set-input', true).first();
33519 getChildContainer : function()
33521 return this.itemsEl;
33524 register : function(item)
33526 this.radioes.push(item);
33530 validate : function()
33534 Roo.each(this.radioes, function(i){
33543 if(this.allowBlank) {
33547 if(this.disabled || valid){
33552 this.markInvalid();
33557 markValid : function()
33559 if(this.labelEl.isVisible(true)){
33560 this.indicatorEl().removeClass('visible');
33561 this.indicatorEl().addClass('invisible');
33564 this.el.removeClass([this.invalidClass, this.validClass]);
33565 this.el.addClass(this.validClass);
33567 this.fireEvent('valid', this);
33570 markInvalid : function(msg)
33572 if(this.allowBlank || this.disabled){
33576 if(this.labelEl.isVisible(true)){
33577 this.indicatorEl().removeClass('invisible');
33578 this.indicatorEl().addClass('visible');
33581 this.el.removeClass([this.invalidClass, this.validClass]);
33582 this.el.addClass(this.invalidClass);
33584 this.fireEvent('invalid', this, msg);
33588 setValue : function(v, suppressEvent)
33590 if(this.value === v){
33597 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33600 Roo.each(this.radioes, function(i){
33603 i.el.removeClass('checked');
33605 if(i.value === v || i.value.toString() === v.toString()){
33607 i.el.addClass('checked');
33609 if(suppressEvent !== true){
33610 this.fireEvent('check', this, i);
33619 clearInvalid : function(){
33621 if(!this.el || this.preventMark){
33625 this.el.removeClass([this.invalidClass]);
33627 this.fireEvent('valid', this);
33632 Roo.apply(Roo.bootstrap.RadioSet, {
33636 register : function(set)
33638 this.groups[set.name] = set;
33641 get: function(name)
33643 if (typeof(this.groups[name]) == 'undefined') {
33647 return this.groups[name] ;
33653 * Ext JS Library 1.1.1
33654 * Copyright(c) 2006-2007, Ext JS, LLC.
33656 * Originally Released Under LGPL - original licence link has changed is not relivant.
33659 * <script type="text/javascript">
33664 * @class Roo.bootstrap.SplitBar
33665 * @extends Roo.util.Observable
33666 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33670 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33671 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33672 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33673 split.minSize = 100;
33674 split.maxSize = 600;
33675 split.animate = true;
33676 split.on('moved', splitterMoved);
33679 * Create a new SplitBar
33680 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33681 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33682 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33683 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33684 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33685 position of the SplitBar).
33687 Roo.bootstrap.SplitBar = function(cfg){
33692 // dragElement : elm
33693 // resizingElement: el,
33695 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33696 // placement : Roo.bootstrap.SplitBar.LEFT ,
33697 // existingProxy ???
33700 this.el = Roo.get(cfg.dragElement, true);
33701 this.el.dom.unselectable = "on";
33703 this.resizingEl = Roo.get(cfg.resizingElement, true);
33707 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33708 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33711 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33714 * The minimum size of the resizing element. (Defaults to 0)
33720 * The maximum size of the resizing element. (Defaults to 2000)
33723 this.maxSize = 2000;
33726 * Whether to animate the transition to the new size
33729 this.animate = false;
33732 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33735 this.useShim = false;
33740 if(!cfg.existingProxy){
33742 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33744 this.proxy = Roo.get(cfg.existingProxy).dom;
33747 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33750 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33753 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33756 this.dragSpecs = {};
33759 * @private The adapter to use to positon and resize elements
33761 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33762 this.adapter.init(this);
33764 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33766 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33767 this.el.addClass("roo-splitbar-h");
33770 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33771 this.el.addClass("roo-splitbar-v");
33777 * Fires when the splitter is moved (alias for {@link #event-moved})
33778 * @param {Roo.bootstrap.SplitBar} this
33779 * @param {Number} newSize the new width or height
33784 * Fires when the splitter is moved
33785 * @param {Roo.bootstrap.SplitBar} this
33786 * @param {Number} newSize the new width or height
33790 * @event beforeresize
33791 * Fires before the splitter is dragged
33792 * @param {Roo.bootstrap.SplitBar} this
33794 "beforeresize" : true,
33796 "beforeapply" : true
33799 Roo.util.Observable.call(this);
33802 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33803 onStartProxyDrag : function(x, y){
33804 this.fireEvent("beforeresize", this);
33806 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33808 o.enableDisplayMode("block");
33809 // all splitbars share the same overlay
33810 Roo.bootstrap.SplitBar.prototype.overlay = o;
33812 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33813 this.overlay.show();
33814 Roo.get(this.proxy).setDisplayed("block");
33815 var size = this.adapter.getElementSize(this);
33816 this.activeMinSize = this.getMinimumSize();;
33817 this.activeMaxSize = this.getMaximumSize();;
33818 var c1 = size - this.activeMinSize;
33819 var c2 = Math.max(this.activeMaxSize - size, 0);
33820 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33821 this.dd.resetConstraints();
33822 this.dd.setXConstraint(
33823 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33824 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33826 this.dd.setYConstraint(0, 0);
33828 this.dd.resetConstraints();
33829 this.dd.setXConstraint(0, 0);
33830 this.dd.setYConstraint(
33831 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33832 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33835 this.dragSpecs.startSize = size;
33836 this.dragSpecs.startPoint = [x, y];
33837 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33841 * @private Called after the drag operation by the DDProxy
33843 onEndProxyDrag : function(e){
33844 Roo.get(this.proxy).setDisplayed(false);
33845 var endPoint = Roo.lib.Event.getXY(e);
33847 this.overlay.hide();
33850 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33851 newSize = this.dragSpecs.startSize +
33852 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33853 endPoint[0] - this.dragSpecs.startPoint[0] :
33854 this.dragSpecs.startPoint[0] - endPoint[0]
33857 newSize = this.dragSpecs.startSize +
33858 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33859 endPoint[1] - this.dragSpecs.startPoint[1] :
33860 this.dragSpecs.startPoint[1] - endPoint[1]
33863 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33864 if(newSize != this.dragSpecs.startSize){
33865 if(this.fireEvent('beforeapply', this, newSize) !== false){
33866 this.adapter.setElementSize(this, newSize);
33867 this.fireEvent("moved", this, newSize);
33868 this.fireEvent("resize", this, newSize);
33874 * Get the adapter this SplitBar uses
33875 * @return The adapter object
33877 getAdapter : function(){
33878 return this.adapter;
33882 * Set the adapter this SplitBar uses
33883 * @param {Object} adapter A SplitBar adapter object
33885 setAdapter : function(adapter){
33886 this.adapter = adapter;
33887 this.adapter.init(this);
33891 * Gets the minimum size for the resizing element
33892 * @return {Number} The minimum size
33894 getMinimumSize : function(){
33895 return this.minSize;
33899 * Sets the minimum size for the resizing element
33900 * @param {Number} minSize The minimum size
33902 setMinimumSize : function(minSize){
33903 this.minSize = minSize;
33907 * Gets the maximum size for the resizing element
33908 * @return {Number} The maximum size
33910 getMaximumSize : function(){
33911 return this.maxSize;
33915 * Sets the maximum size for the resizing element
33916 * @param {Number} maxSize The maximum size
33918 setMaximumSize : function(maxSize){
33919 this.maxSize = maxSize;
33923 * Sets the initialize size for the resizing element
33924 * @param {Number} size The initial size
33926 setCurrentSize : function(size){
33927 var oldAnimate = this.animate;
33928 this.animate = false;
33929 this.adapter.setElementSize(this, size);
33930 this.animate = oldAnimate;
33934 * Destroy this splitbar.
33935 * @param {Boolean} removeEl True to remove the element
33937 destroy : function(removeEl){
33939 this.shim.remove();
33942 this.proxy.parentNode.removeChild(this.proxy);
33950 * @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.
33952 Roo.bootstrap.SplitBar.createProxy = function(dir){
33953 var proxy = new Roo.Element(document.createElement("div"));
33954 proxy.unselectable();
33955 var cls = 'roo-splitbar-proxy';
33956 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33957 document.body.appendChild(proxy.dom);
33962 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33963 * Default Adapter. It assumes the splitter and resizing element are not positioned
33964 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33966 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33969 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33970 // do nothing for now
33971 init : function(s){
33975 * Called before drag operations to get the current size of the resizing element.
33976 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33978 getElementSize : function(s){
33979 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33980 return s.resizingEl.getWidth();
33982 return s.resizingEl.getHeight();
33987 * Called after drag operations to set the size of the resizing element.
33988 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33989 * @param {Number} newSize The new size to set
33990 * @param {Function} onComplete A function to be invoked when resizing is complete
33992 setElementSize : function(s, newSize, onComplete){
33993 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33995 s.resizingEl.setWidth(newSize);
33997 onComplete(s, newSize);
34000 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34005 s.resizingEl.setHeight(newSize);
34007 onComplete(s, newSize);
34010 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34017 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34018 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34019 * Adapter that moves the splitter element to align with the resized sizing element.
34020 * Used with an absolute positioned SplitBar.
34021 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34022 * document.body, make sure you assign an id to the body element.
34024 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34025 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34026 this.container = Roo.get(container);
34029 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34030 init : function(s){
34031 this.basic.init(s);
34034 getElementSize : function(s){
34035 return this.basic.getElementSize(s);
34038 setElementSize : function(s, newSize, onComplete){
34039 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34042 moveSplitter : function(s){
34043 var yes = Roo.bootstrap.SplitBar;
34044 switch(s.placement){
34046 s.el.setX(s.resizingEl.getRight());
34049 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34052 s.el.setY(s.resizingEl.getBottom());
34055 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34062 * Orientation constant - Create a vertical SplitBar
34066 Roo.bootstrap.SplitBar.VERTICAL = 1;
34069 * Orientation constant - Create a horizontal SplitBar
34073 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34076 * Placement constant - The resizing element is to the left of the splitter element
34080 Roo.bootstrap.SplitBar.LEFT = 1;
34083 * Placement constant - The resizing element is to the right of the splitter element
34087 Roo.bootstrap.SplitBar.RIGHT = 2;
34090 * Placement constant - The resizing element is positioned above the splitter element
34094 Roo.bootstrap.SplitBar.TOP = 3;
34097 * Placement constant - The resizing element is positioned under splitter element
34101 Roo.bootstrap.SplitBar.BOTTOM = 4;
34102 Roo.namespace("Roo.bootstrap.layout");/*
34104 * Ext JS Library 1.1.1
34105 * Copyright(c) 2006-2007, Ext JS, LLC.
34107 * Originally Released Under LGPL - original licence link has changed is not relivant.
34110 * <script type="text/javascript">
34114 * @class Roo.bootstrap.layout.Manager
34115 * @extends Roo.bootstrap.Component
34116 * Base class for layout managers.
34118 Roo.bootstrap.layout.Manager = function(config)
34120 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34126 /** false to disable window resize monitoring @type Boolean */
34127 this.monitorWindowResize = true;
34132 * Fires when a layout is performed.
34133 * @param {Roo.LayoutManager} this
34137 * @event regionresized
34138 * Fires when the user resizes a region.
34139 * @param {Roo.LayoutRegion} region The resized region
34140 * @param {Number} newSize The new size (width for east/west, height for north/south)
34142 "regionresized" : true,
34144 * @event regioncollapsed
34145 * Fires when a region is collapsed.
34146 * @param {Roo.LayoutRegion} region The collapsed region
34148 "regioncollapsed" : true,
34150 * @event regionexpanded
34151 * Fires when a region is expanded.
34152 * @param {Roo.LayoutRegion} region The expanded region
34154 "regionexpanded" : true
34156 this.updating = false;
34159 this.el = Roo.get(config.el);
34165 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34170 monitorWindowResize : true,
34176 onRender : function(ct, position)
34179 this.el = Roo.get(ct);
34182 //this.fireEvent('render',this);
34186 initEvents: function()
34190 // ie scrollbar fix
34191 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34192 document.body.scroll = "no";
34193 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34194 this.el.position('relative');
34196 this.id = this.el.id;
34197 this.el.addClass("roo-layout-container");
34198 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34199 if(this.el.dom != document.body ) {
34200 this.el.on('resize', this.layout,this);
34201 this.el.on('show', this.layout,this);
34207 * Returns true if this layout is currently being updated
34208 * @return {Boolean}
34210 isUpdating : function(){
34211 return this.updating;
34215 * Suspend the LayoutManager from doing auto-layouts while
34216 * making multiple add or remove calls
34218 beginUpdate : function(){
34219 this.updating = true;
34223 * Restore auto-layouts and optionally disable the manager from performing a layout
34224 * @param {Boolean} noLayout true to disable a layout update
34226 endUpdate : function(noLayout){
34227 this.updating = false;
34233 layout: function(){
34237 onRegionResized : function(region, newSize){
34238 this.fireEvent("regionresized", region, newSize);
34242 onRegionCollapsed : function(region){
34243 this.fireEvent("regioncollapsed", region);
34246 onRegionExpanded : function(region){
34247 this.fireEvent("regionexpanded", region);
34251 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34252 * performs box-model adjustments.
34253 * @return {Object} The size as an object {width: (the width), height: (the height)}
34255 getViewSize : function()
34258 if(this.el.dom != document.body){
34259 size = this.el.getSize();
34261 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34263 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34264 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34269 * Returns the Element this layout is bound to.
34270 * @return {Roo.Element}
34272 getEl : function(){
34277 * Returns the specified region.
34278 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34279 * @return {Roo.LayoutRegion}
34281 getRegion : function(target){
34282 return this.regions[target.toLowerCase()];
34285 onWindowResize : function(){
34286 if(this.monitorWindowResize){
34293 * Ext JS Library 1.1.1
34294 * Copyright(c) 2006-2007, Ext JS, LLC.
34296 * Originally Released Under LGPL - original licence link has changed is not relivant.
34299 * <script type="text/javascript">
34302 * @class Roo.bootstrap.layout.Border
34303 * @extends Roo.bootstrap.layout.Manager
34304 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34305 * please see: examples/bootstrap/nested.html<br><br>
34307 <b>The container the layout is rendered into can be either the body element or any other element.
34308 If it is not the body element, the container needs to either be an absolute positioned element,
34309 or you will need to add "position:relative" to the css of the container. You will also need to specify
34310 the container size if it is not the body element.</b>
34313 * Create a new Border
34314 * @param {Object} config Configuration options
34316 Roo.bootstrap.layout.Border = function(config){
34317 config = config || {};
34318 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34322 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34323 if(config[region]){
34324 config[region].region = region;
34325 this.addRegion(config[region]);
34331 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34333 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34335 * Creates and adds a new region if it doesn't already exist.
34336 * @param {String} target The target region key (north, south, east, west or center).
34337 * @param {Object} config The regions config object
34338 * @return {BorderLayoutRegion} The new region
34340 addRegion : function(config)
34342 if(!this.regions[config.region]){
34343 var r = this.factory(config);
34344 this.bindRegion(r);
34346 return this.regions[config.region];
34350 bindRegion : function(r){
34351 this.regions[r.config.region] = r;
34353 r.on("visibilitychange", this.layout, this);
34354 r.on("paneladded", this.layout, this);
34355 r.on("panelremoved", this.layout, this);
34356 r.on("invalidated", this.layout, this);
34357 r.on("resized", this.onRegionResized, this);
34358 r.on("collapsed", this.onRegionCollapsed, this);
34359 r.on("expanded", this.onRegionExpanded, this);
34363 * Performs a layout update.
34365 layout : function()
34367 if(this.updating) {
34371 // render all the rebions if they have not been done alreayd?
34372 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34373 if(this.regions[region] && !this.regions[region].bodyEl){
34374 this.regions[region].onRender(this.el)
34378 var size = this.getViewSize();
34379 var w = size.width;
34380 var h = size.height;
34385 //var x = 0, y = 0;
34387 var rs = this.regions;
34388 var north = rs["north"];
34389 var south = rs["south"];
34390 var west = rs["west"];
34391 var east = rs["east"];
34392 var center = rs["center"];
34393 //if(this.hideOnLayout){ // not supported anymore
34394 //c.el.setStyle("display", "none");
34396 if(north && north.isVisible()){
34397 var b = north.getBox();
34398 var m = north.getMargins();
34399 b.width = w - (m.left+m.right);
34402 centerY = b.height + b.y + m.bottom;
34403 centerH -= centerY;
34404 north.updateBox(this.safeBox(b));
34406 if(south && south.isVisible()){
34407 var b = south.getBox();
34408 var m = south.getMargins();
34409 b.width = w - (m.left+m.right);
34411 var totalHeight = (b.height + m.top + m.bottom);
34412 b.y = h - totalHeight + m.top;
34413 centerH -= totalHeight;
34414 south.updateBox(this.safeBox(b));
34416 if(west && west.isVisible()){
34417 var b = west.getBox();
34418 var m = west.getMargins();
34419 b.height = centerH - (m.top+m.bottom);
34421 b.y = centerY + m.top;
34422 var totalWidth = (b.width + m.left + m.right);
34423 centerX += totalWidth;
34424 centerW -= totalWidth;
34425 west.updateBox(this.safeBox(b));
34427 if(east && east.isVisible()){
34428 var b = east.getBox();
34429 var m = east.getMargins();
34430 b.height = centerH - (m.top+m.bottom);
34431 var totalWidth = (b.width + m.left + m.right);
34432 b.x = w - totalWidth + m.left;
34433 b.y = centerY + m.top;
34434 centerW -= totalWidth;
34435 east.updateBox(this.safeBox(b));
34438 var m = center.getMargins();
34440 x: centerX + m.left,
34441 y: centerY + m.top,
34442 width: centerW - (m.left+m.right),
34443 height: centerH - (m.top+m.bottom)
34445 //if(this.hideOnLayout){
34446 //center.el.setStyle("display", "block");
34448 center.updateBox(this.safeBox(centerBox));
34451 this.fireEvent("layout", this);
34455 safeBox : function(box){
34456 box.width = Math.max(0, box.width);
34457 box.height = Math.max(0, box.height);
34462 * Adds a ContentPanel (or subclass) to this layout.
34463 * @param {String} target The target region key (north, south, east, west or center).
34464 * @param {Roo.ContentPanel} panel The panel to add
34465 * @return {Roo.ContentPanel} The added panel
34467 add : function(target, panel){
34469 target = target.toLowerCase();
34470 return this.regions[target].add(panel);
34474 * Remove a ContentPanel (or subclass) to this layout.
34475 * @param {String} target The target region key (north, south, east, west or center).
34476 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34477 * @return {Roo.ContentPanel} The removed panel
34479 remove : function(target, panel){
34480 target = target.toLowerCase();
34481 return this.regions[target].remove(panel);
34485 * Searches all regions for a panel with the specified id
34486 * @param {String} panelId
34487 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34489 findPanel : function(panelId){
34490 var rs = this.regions;
34491 for(var target in rs){
34492 if(typeof rs[target] != "function"){
34493 var p = rs[target].getPanel(panelId);
34503 * Searches all regions for a panel with the specified id and activates (shows) it.
34504 * @param {String/ContentPanel} panelId The panels id or the panel itself
34505 * @return {Roo.ContentPanel} The shown panel or null
34507 showPanel : function(panelId) {
34508 var rs = this.regions;
34509 for(var target in rs){
34510 var r = rs[target];
34511 if(typeof r != "function"){
34512 if(r.hasPanel(panelId)){
34513 return r.showPanel(panelId);
34521 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34522 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34525 restoreState : function(provider){
34527 provider = Roo.state.Manager;
34529 var sm = new Roo.LayoutStateManager();
34530 sm.init(this, provider);
34536 * Adds a xtype elements to the layout.
34540 xtype : 'ContentPanel',
34547 xtype : 'NestedLayoutPanel',
34553 items : [ ... list of content panels or nested layout panels.. ]
34557 * @param {Object} cfg Xtype definition of item to add.
34559 addxtype : function(cfg)
34561 // basically accepts a pannel...
34562 // can accept a layout region..!?!?
34563 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34566 // theory? children can only be panels??
34568 //if (!cfg.xtype.match(/Panel$/)) {
34573 if (typeof(cfg.region) == 'undefined') {
34574 Roo.log("Failed to add Panel, region was not set");
34578 var region = cfg.region;
34584 xitems = cfg.items;
34591 case 'Content': // ContentPanel (el, cfg)
34592 case 'Scroll': // ContentPanel (el, cfg)
34594 cfg.autoCreate = true;
34595 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34597 // var el = this.el.createChild();
34598 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34601 this.add(region, ret);
34605 case 'TreePanel': // our new panel!
34606 cfg.el = this.el.createChild();
34607 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34608 this.add(region, ret);
34613 // create a new Layout (which is a Border Layout...
34615 var clayout = cfg.layout;
34616 clayout.el = this.el.createChild();
34617 clayout.items = clayout.items || [];
34621 // replace this exitems with the clayout ones..
34622 xitems = clayout.items;
34624 // force background off if it's in center...
34625 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34626 cfg.background = false;
34628 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34631 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34632 //console.log('adding nested layout panel ' + cfg.toSource());
34633 this.add(region, ret);
34634 nb = {}; /// find first...
34639 // needs grid and region
34641 //var el = this.getRegion(region).el.createChild();
34643 *var el = this.el.createChild();
34644 // create the grid first...
34645 cfg.grid.container = el;
34646 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34649 if (region == 'center' && this.active ) {
34650 cfg.background = false;
34653 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34655 this.add(region, ret);
34657 if (cfg.background) {
34658 // render grid on panel activation (if panel background)
34659 ret.on('activate', function(gp) {
34660 if (!gp.grid.rendered) {
34661 // gp.grid.render(el);
34665 // cfg.grid.render(el);
34671 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34672 // it was the old xcomponent building that caused this before.
34673 // espeically if border is the top element in the tree.
34683 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34685 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34686 this.add(region, ret);
34690 throw "Can not add '" + cfg.xtype + "' to Border";
34696 this.beginUpdate();
34700 Roo.each(xitems, function(i) {
34701 region = nb && i.region ? i.region : false;
34703 var add = ret.addxtype(i);
34706 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34707 if (!i.background) {
34708 abn[region] = nb[region] ;
34715 // make the last non-background panel active..
34716 //if (nb) { Roo.log(abn); }
34719 for(var r in abn) {
34720 region = this.getRegion(r);
34722 // tried using nb[r], but it does not work..
34724 region.showPanel(abn[r]);
34735 factory : function(cfg)
34738 var validRegions = Roo.bootstrap.layout.Border.regions;
34740 var target = cfg.region;
34743 var r = Roo.bootstrap.layout;
34747 return new r.North(cfg);
34749 return new r.South(cfg);
34751 return new r.East(cfg);
34753 return new r.West(cfg);
34755 return new r.Center(cfg);
34757 throw 'Layout region "'+target+'" not supported.';
34764 * Ext JS Library 1.1.1
34765 * Copyright(c) 2006-2007, Ext JS, LLC.
34767 * Originally Released Under LGPL - original licence link has changed is not relivant.
34770 * <script type="text/javascript">
34774 * @class Roo.bootstrap.layout.Basic
34775 * @extends Roo.util.Observable
34776 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34777 * and does not have a titlebar, tabs or any other features. All it does is size and position
34778 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34779 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34780 * @cfg {string} region the region that it inhabits..
34781 * @cfg {bool} skipConfig skip config?
34785 Roo.bootstrap.layout.Basic = function(config){
34787 this.mgr = config.mgr;
34789 this.position = config.region;
34791 var skipConfig = config.skipConfig;
34795 * @scope Roo.BasicLayoutRegion
34799 * @event beforeremove
34800 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34801 * @param {Roo.LayoutRegion} this
34802 * @param {Roo.ContentPanel} panel The panel
34803 * @param {Object} e The cancel event object
34805 "beforeremove" : true,
34807 * @event invalidated
34808 * Fires when the layout for this region is changed.
34809 * @param {Roo.LayoutRegion} this
34811 "invalidated" : true,
34813 * @event visibilitychange
34814 * Fires when this region is shown or hidden
34815 * @param {Roo.LayoutRegion} this
34816 * @param {Boolean} visibility true or false
34818 "visibilitychange" : true,
34820 * @event paneladded
34821 * Fires when a panel is added.
34822 * @param {Roo.LayoutRegion} this
34823 * @param {Roo.ContentPanel} panel The panel
34825 "paneladded" : true,
34827 * @event panelremoved
34828 * Fires when a panel is removed.
34829 * @param {Roo.LayoutRegion} this
34830 * @param {Roo.ContentPanel} panel The panel
34832 "panelremoved" : true,
34834 * @event beforecollapse
34835 * Fires when this region before collapse.
34836 * @param {Roo.LayoutRegion} this
34838 "beforecollapse" : true,
34841 * Fires when this region is collapsed.
34842 * @param {Roo.LayoutRegion} this
34844 "collapsed" : true,
34847 * Fires when this region is expanded.
34848 * @param {Roo.LayoutRegion} this
34853 * Fires when this region is slid into view.
34854 * @param {Roo.LayoutRegion} this
34856 "slideshow" : true,
34859 * Fires when this region slides out of view.
34860 * @param {Roo.LayoutRegion} this
34862 "slidehide" : true,
34864 * @event panelactivated
34865 * Fires when a panel is activated.
34866 * @param {Roo.LayoutRegion} this
34867 * @param {Roo.ContentPanel} panel The activated panel
34869 "panelactivated" : true,
34872 * Fires when the user resizes this region.
34873 * @param {Roo.LayoutRegion} this
34874 * @param {Number} newSize The new size (width for east/west, height for north/south)
34878 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34879 this.panels = new Roo.util.MixedCollection();
34880 this.panels.getKey = this.getPanelId.createDelegate(this);
34882 this.activePanel = null;
34883 // ensure listeners are added...
34885 if (config.listeners || config.events) {
34886 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34887 listeners : config.listeners || {},
34888 events : config.events || {}
34892 if(skipConfig !== true){
34893 this.applyConfig(config);
34897 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34899 getPanelId : function(p){
34903 applyConfig : function(config){
34904 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34905 this.config = config;
34910 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34911 * the width, for horizontal (north, south) the height.
34912 * @param {Number} newSize The new width or height
34914 resizeTo : function(newSize){
34915 var el = this.el ? this.el :
34916 (this.activePanel ? this.activePanel.getEl() : null);
34918 switch(this.position){
34921 el.setWidth(newSize);
34922 this.fireEvent("resized", this, newSize);
34926 el.setHeight(newSize);
34927 this.fireEvent("resized", this, newSize);
34933 getBox : function(){
34934 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34937 getMargins : function(){
34938 return this.margins;
34941 updateBox : function(box){
34943 var el = this.activePanel.getEl();
34944 el.dom.style.left = box.x + "px";
34945 el.dom.style.top = box.y + "px";
34946 this.activePanel.setSize(box.width, box.height);
34950 * Returns the container element for this region.
34951 * @return {Roo.Element}
34953 getEl : function(){
34954 return this.activePanel;
34958 * Returns true if this region is currently visible.
34959 * @return {Boolean}
34961 isVisible : function(){
34962 return this.activePanel ? true : false;
34965 setActivePanel : function(panel){
34966 panel = this.getPanel(panel);
34967 if(this.activePanel && this.activePanel != panel){
34968 this.activePanel.setActiveState(false);
34969 this.activePanel.getEl().setLeftTop(-10000,-10000);
34971 this.activePanel = panel;
34972 panel.setActiveState(true);
34974 panel.setSize(this.box.width, this.box.height);
34976 this.fireEvent("panelactivated", this, panel);
34977 this.fireEvent("invalidated");
34981 * Show the specified panel.
34982 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34983 * @return {Roo.ContentPanel} The shown panel or null
34985 showPanel : function(panel){
34986 panel = this.getPanel(panel);
34988 this.setActivePanel(panel);
34994 * Get the active panel for this region.
34995 * @return {Roo.ContentPanel} The active panel or null
34997 getActivePanel : function(){
34998 return this.activePanel;
35002 * Add the passed ContentPanel(s)
35003 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35004 * @return {Roo.ContentPanel} The panel added (if only one was added)
35006 add : function(panel){
35007 if(arguments.length > 1){
35008 for(var i = 0, len = arguments.length; i < len; i++) {
35009 this.add(arguments[i]);
35013 if(this.hasPanel(panel)){
35014 this.showPanel(panel);
35017 var el = panel.getEl();
35018 if(el.dom.parentNode != this.mgr.el.dom){
35019 this.mgr.el.dom.appendChild(el.dom);
35021 if(panel.setRegion){
35022 panel.setRegion(this);
35024 this.panels.add(panel);
35025 el.setStyle("position", "absolute");
35026 if(!panel.background){
35027 this.setActivePanel(panel);
35028 if(this.config.initialSize && this.panels.getCount()==1){
35029 this.resizeTo(this.config.initialSize);
35032 this.fireEvent("paneladded", this, panel);
35037 * Returns true if the panel is in this region.
35038 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35039 * @return {Boolean}
35041 hasPanel : function(panel){
35042 if(typeof panel == "object"){ // must be panel obj
35043 panel = panel.getId();
35045 return this.getPanel(panel) ? true : false;
35049 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35050 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35051 * @param {Boolean} preservePanel Overrides the config preservePanel option
35052 * @return {Roo.ContentPanel} The panel that was removed
35054 remove : function(panel, preservePanel){
35055 panel = this.getPanel(panel);
35060 this.fireEvent("beforeremove", this, panel, e);
35061 if(e.cancel === true){
35064 var panelId = panel.getId();
35065 this.panels.removeKey(panelId);
35070 * Returns the panel specified or null if it's not in this region.
35071 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35072 * @return {Roo.ContentPanel}
35074 getPanel : function(id){
35075 if(typeof id == "object"){ // must be panel obj
35078 return this.panels.get(id);
35082 * Returns this regions position (north/south/east/west/center).
35085 getPosition: function(){
35086 return this.position;
35090 * Ext JS Library 1.1.1
35091 * Copyright(c) 2006-2007, Ext JS, LLC.
35093 * Originally Released Under LGPL - original licence link has changed is not relivant.
35096 * <script type="text/javascript">
35100 * @class Roo.bootstrap.layout.Region
35101 * @extends Roo.bootstrap.layout.Basic
35102 * This class represents a region in a layout manager.
35104 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35105 * @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})
35106 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35107 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35108 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35109 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35110 * @cfg {String} title The title for the region (overrides panel titles)
35111 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35112 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35113 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35114 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35115 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35116 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35117 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35118 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35119 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35120 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35122 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35123 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35124 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35125 * @cfg {Number} width For East/West panels
35126 * @cfg {Number} height For North/South panels
35127 * @cfg {Boolean} split To show the splitter
35128 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35130 * @cfg {string} cls Extra CSS classes to add to region
35132 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35133 * @cfg {string} region the region that it inhabits..
35136 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35137 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35139 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35140 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35141 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35143 Roo.bootstrap.layout.Region = function(config)
35145 this.applyConfig(config);
35147 var mgr = config.mgr;
35148 var pos = config.region;
35149 config.skipConfig = true;
35150 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35153 this.onRender(mgr.el);
35156 this.visible = true;
35157 this.collapsed = false;
35158 this.unrendered_panels = [];
35161 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35163 position: '', // set by wrapper (eg. north/south etc..)
35164 unrendered_panels : null, // unrendered panels.
35165 createBody : function(){
35166 /** This region's body element
35167 * @type Roo.Element */
35168 this.bodyEl = this.el.createChild({
35170 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35174 onRender: function(ctr, pos)
35176 var dh = Roo.DomHelper;
35177 /** This region's container element
35178 * @type Roo.Element */
35179 this.el = dh.append(ctr.dom, {
35181 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35183 /** This region's title element
35184 * @type Roo.Element */
35186 this.titleEl = dh.append(this.el.dom,
35189 unselectable: "on",
35190 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35192 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35193 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35196 this.titleEl.enableDisplayMode();
35197 /** This region's title text element
35198 * @type HTMLElement */
35199 this.titleTextEl = this.titleEl.dom.firstChild;
35200 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35202 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35203 this.closeBtn.enableDisplayMode();
35204 this.closeBtn.on("click", this.closeClicked, this);
35205 this.closeBtn.hide();
35207 this.createBody(this.config);
35208 if(this.config.hideWhenEmpty){
35210 this.on("paneladded", this.validateVisibility, this);
35211 this.on("panelremoved", this.validateVisibility, this);
35213 if(this.autoScroll){
35214 this.bodyEl.setStyle("overflow", "auto");
35216 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35218 //if(c.titlebar !== false){
35219 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35220 this.titleEl.hide();
35222 this.titleEl.show();
35223 if(this.config.title){
35224 this.titleTextEl.innerHTML = this.config.title;
35228 if(this.config.collapsed){
35229 this.collapse(true);
35231 if(this.config.hidden){
35235 if (this.unrendered_panels && this.unrendered_panels.length) {
35236 for (var i =0;i< this.unrendered_panels.length; i++) {
35237 this.add(this.unrendered_panels[i]);
35239 this.unrendered_panels = null;
35245 applyConfig : function(c)
35248 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35249 var dh = Roo.DomHelper;
35250 if(c.titlebar !== false){
35251 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35252 this.collapseBtn.on("click", this.collapse, this);
35253 this.collapseBtn.enableDisplayMode();
35255 if(c.showPin === true || this.showPin){
35256 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35257 this.stickBtn.enableDisplayMode();
35258 this.stickBtn.on("click", this.expand, this);
35259 this.stickBtn.hide();
35264 /** This region's collapsed element
35265 * @type Roo.Element */
35268 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35269 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35272 if(c.floatable !== false){
35273 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35274 this.collapsedEl.on("click", this.collapseClick, this);
35277 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35278 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35279 id: "message", unselectable: "on", style:{"float":"left"}});
35280 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35282 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35283 this.expandBtn.on("click", this.expand, this);
35287 if(this.collapseBtn){
35288 this.collapseBtn.setVisible(c.collapsible == true);
35291 this.cmargins = c.cmargins || this.cmargins ||
35292 (this.position == "west" || this.position == "east" ?
35293 {top: 0, left: 2, right:2, bottom: 0} :
35294 {top: 2, left: 0, right:0, bottom: 2});
35296 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35299 this.bottomTabs = c.tabPosition != "top";
35301 this.autoScroll = c.autoScroll || false;
35306 this.duration = c.duration || .30;
35307 this.slideDuration = c.slideDuration || .45;
35312 * Returns true if this region is currently visible.
35313 * @return {Boolean}
35315 isVisible : function(){
35316 return this.visible;
35320 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35321 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35323 //setCollapsedTitle : function(title){
35324 // title = title || " ";
35325 // if(this.collapsedTitleTextEl){
35326 // this.collapsedTitleTextEl.innerHTML = title;
35330 getBox : function(){
35332 // if(!this.collapsed){
35333 b = this.el.getBox(false, true);
35335 // b = this.collapsedEl.getBox(false, true);
35340 getMargins : function(){
35341 return this.margins;
35342 //return this.collapsed ? this.cmargins : this.margins;
35345 highlight : function(){
35346 this.el.addClass("x-layout-panel-dragover");
35349 unhighlight : function(){
35350 this.el.removeClass("x-layout-panel-dragover");
35353 updateBox : function(box)
35355 if (!this.bodyEl) {
35356 return; // not rendered yet..
35360 if(!this.collapsed){
35361 this.el.dom.style.left = box.x + "px";
35362 this.el.dom.style.top = box.y + "px";
35363 this.updateBody(box.width, box.height);
35365 this.collapsedEl.dom.style.left = box.x + "px";
35366 this.collapsedEl.dom.style.top = box.y + "px";
35367 this.collapsedEl.setSize(box.width, box.height);
35370 this.tabs.autoSizeTabs();
35374 updateBody : function(w, h)
35377 this.el.setWidth(w);
35378 w -= this.el.getBorderWidth("rl");
35379 if(this.config.adjustments){
35380 w += this.config.adjustments[0];
35383 if(h !== null && h > 0){
35384 this.el.setHeight(h);
35385 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35386 h -= this.el.getBorderWidth("tb");
35387 if(this.config.adjustments){
35388 h += this.config.adjustments[1];
35390 this.bodyEl.setHeight(h);
35392 h = this.tabs.syncHeight(h);
35395 if(this.panelSize){
35396 w = w !== null ? w : this.panelSize.width;
35397 h = h !== null ? h : this.panelSize.height;
35399 if(this.activePanel){
35400 var el = this.activePanel.getEl();
35401 w = w !== null ? w : el.getWidth();
35402 h = h !== null ? h : el.getHeight();
35403 this.panelSize = {width: w, height: h};
35404 this.activePanel.setSize(w, h);
35406 if(Roo.isIE && this.tabs){
35407 this.tabs.el.repaint();
35412 * Returns the container element for this region.
35413 * @return {Roo.Element}
35415 getEl : function(){
35420 * Hides this region.
35423 //if(!this.collapsed){
35424 this.el.dom.style.left = "-2000px";
35427 // this.collapsedEl.dom.style.left = "-2000px";
35428 // this.collapsedEl.hide();
35430 this.visible = false;
35431 this.fireEvent("visibilitychange", this, false);
35435 * Shows this region if it was previously hidden.
35438 //if(!this.collapsed){
35441 // this.collapsedEl.show();
35443 this.visible = true;
35444 this.fireEvent("visibilitychange", this, true);
35447 closeClicked : function(){
35448 if(this.activePanel){
35449 this.remove(this.activePanel);
35453 collapseClick : function(e){
35455 e.stopPropagation();
35458 e.stopPropagation();
35464 * Collapses this region.
35465 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35468 collapse : function(skipAnim, skipCheck = false){
35469 if(this.collapsed) {
35473 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35475 this.collapsed = true;
35477 this.split.el.hide();
35479 if(this.config.animate && skipAnim !== true){
35480 this.fireEvent("invalidated", this);
35481 this.animateCollapse();
35483 this.el.setLocation(-20000,-20000);
35485 this.collapsedEl.show();
35486 this.fireEvent("collapsed", this);
35487 this.fireEvent("invalidated", this);
35493 animateCollapse : function(){
35498 * Expands this region if it was previously collapsed.
35499 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35500 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35503 expand : function(e, skipAnim){
35505 e.stopPropagation();
35507 if(!this.collapsed || this.el.hasActiveFx()) {
35511 this.afterSlideIn();
35514 this.collapsed = false;
35515 if(this.config.animate && skipAnim !== true){
35516 this.animateExpand();
35520 this.split.el.show();
35522 this.collapsedEl.setLocation(-2000,-2000);
35523 this.collapsedEl.hide();
35524 this.fireEvent("invalidated", this);
35525 this.fireEvent("expanded", this);
35529 animateExpand : function(){
35533 initTabs : function()
35535 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35537 var ts = new Roo.bootstrap.panel.Tabs({
35538 el: this.bodyEl.dom,
35539 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35540 disableTooltips: this.config.disableTabTips,
35541 toolbar : this.config.toolbar
35544 if(this.config.hideTabs){
35545 ts.stripWrap.setDisplayed(false);
35548 ts.resizeTabs = this.config.resizeTabs === true;
35549 ts.minTabWidth = this.config.minTabWidth || 40;
35550 ts.maxTabWidth = this.config.maxTabWidth || 250;
35551 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35552 ts.monitorResize = false;
35553 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35554 ts.bodyEl.addClass('roo-layout-tabs-body');
35555 this.panels.each(this.initPanelAsTab, this);
35558 initPanelAsTab : function(panel){
35559 var ti = this.tabs.addTab(
35563 this.config.closeOnTab && panel.isClosable(),
35566 if(panel.tabTip !== undefined){
35567 ti.setTooltip(panel.tabTip);
35569 ti.on("activate", function(){
35570 this.setActivePanel(panel);
35573 if(this.config.closeOnTab){
35574 ti.on("beforeclose", function(t, e){
35576 this.remove(panel);
35580 panel.tabItem = ti;
35585 updatePanelTitle : function(panel, title)
35587 if(this.activePanel == panel){
35588 this.updateTitle(title);
35591 var ti = this.tabs.getTab(panel.getEl().id);
35593 if(panel.tabTip !== undefined){
35594 ti.setTooltip(panel.tabTip);
35599 updateTitle : function(title){
35600 if(this.titleTextEl && !this.config.title){
35601 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35605 setActivePanel : function(panel)
35607 panel = this.getPanel(panel);
35608 if(this.activePanel && this.activePanel != panel){
35609 if(this.activePanel.setActiveState(false) === false){
35613 this.activePanel = panel;
35614 panel.setActiveState(true);
35615 if(this.panelSize){
35616 panel.setSize(this.panelSize.width, this.panelSize.height);
35619 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35621 this.updateTitle(panel.getTitle());
35623 this.fireEvent("invalidated", this);
35625 this.fireEvent("panelactivated", this, panel);
35629 * Shows the specified panel.
35630 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35631 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35633 showPanel : function(panel)
35635 panel = this.getPanel(panel);
35638 var tab = this.tabs.getTab(panel.getEl().id);
35639 if(tab.isHidden()){
35640 this.tabs.unhideTab(tab.id);
35644 this.setActivePanel(panel);
35651 * Get the active panel for this region.
35652 * @return {Roo.ContentPanel} The active panel or null
35654 getActivePanel : function(){
35655 return this.activePanel;
35658 validateVisibility : function(){
35659 if(this.panels.getCount() < 1){
35660 this.updateTitle(" ");
35661 this.closeBtn.hide();
35664 if(!this.isVisible()){
35671 * Adds the passed ContentPanel(s) to this region.
35672 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35673 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35675 add : function(panel)
35677 if(arguments.length > 1){
35678 for(var i = 0, len = arguments.length; i < len; i++) {
35679 this.add(arguments[i]);
35684 // if we have not been rendered yet, then we can not really do much of this..
35685 if (!this.bodyEl) {
35686 this.unrendered_panels.push(panel);
35693 if(this.hasPanel(panel)){
35694 this.showPanel(panel);
35697 panel.setRegion(this);
35698 this.panels.add(panel);
35699 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35700 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35701 // and hide them... ???
35702 this.bodyEl.dom.appendChild(panel.getEl().dom);
35703 if(panel.background !== true){
35704 this.setActivePanel(panel);
35706 this.fireEvent("paneladded", this, panel);
35713 this.initPanelAsTab(panel);
35717 if(panel.background !== true){
35718 this.tabs.activate(panel.getEl().id);
35720 this.fireEvent("paneladded", this, panel);
35725 * Hides the tab for the specified panel.
35726 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35728 hidePanel : function(panel){
35729 if(this.tabs && (panel = this.getPanel(panel))){
35730 this.tabs.hideTab(panel.getEl().id);
35735 * Unhides the tab for a previously hidden panel.
35736 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35738 unhidePanel : function(panel){
35739 if(this.tabs && (panel = this.getPanel(panel))){
35740 this.tabs.unhideTab(panel.getEl().id);
35744 clearPanels : function(){
35745 while(this.panels.getCount() > 0){
35746 this.remove(this.panels.first());
35751 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35752 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35753 * @param {Boolean} preservePanel Overrides the config preservePanel option
35754 * @return {Roo.ContentPanel} The panel that was removed
35756 remove : function(panel, preservePanel)
35758 panel = this.getPanel(panel);
35763 this.fireEvent("beforeremove", this, panel, e);
35764 if(e.cancel === true){
35767 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35768 var panelId = panel.getId();
35769 this.panels.removeKey(panelId);
35771 document.body.appendChild(panel.getEl().dom);
35774 this.tabs.removeTab(panel.getEl().id);
35775 }else if (!preservePanel){
35776 this.bodyEl.dom.removeChild(panel.getEl().dom);
35778 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35779 var p = this.panels.first();
35780 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35781 tempEl.appendChild(p.getEl().dom);
35782 this.bodyEl.update("");
35783 this.bodyEl.dom.appendChild(p.getEl().dom);
35785 this.updateTitle(p.getTitle());
35787 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35788 this.setActivePanel(p);
35790 panel.setRegion(null);
35791 if(this.activePanel == panel){
35792 this.activePanel = null;
35794 if(this.config.autoDestroy !== false && preservePanel !== true){
35795 try{panel.destroy();}catch(e){}
35797 this.fireEvent("panelremoved", this, panel);
35802 * Returns the TabPanel component used by this region
35803 * @return {Roo.TabPanel}
35805 getTabs : function(){
35809 createTool : function(parentEl, className){
35810 var btn = Roo.DomHelper.append(parentEl, {
35812 cls: "x-layout-tools-button",
35815 cls: "roo-layout-tools-button-inner " + className,
35819 btn.addClassOnOver("roo-layout-tools-button-over");
35824 * Ext JS Library 1.1.1
35825 * Copyright(c) 2006-2007, Ext JS, LLC.
35827 * Originally Released Under LGPL - original licence link has changed is not relivant.
35830 * <script type="text/javascript">
35836 * @class Roo.SplitLayoutRegion
35837 * @extends Roo.LayoutRegion
35838 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35840 Roo.bootstrap.layout.Split = function(config){
35841 this.cursor = config.cursor;
35842 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35845 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35847 splitTip : "Drag to resize.",
35848 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35849 useSplitTips : false,
35851 applyConfig : function(config){
35852 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35855 onRender : function(ctr,pos) {
35857 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35858 if(!this.config.split){
35863 var splitEl = Roo.DomHelper.append(ctr.dom, {
35865 id: this.el.id + "-split",
35866 cls: "roo-layout-split roo-layout-split-"+this.position,
35869 /** The SplitBar for this region
35870 * @type Roo.SplitBar */
35871 // does not exist yet...
35872 Roo.log([this.position, this.orientation]);
35874 this.split = new Roo.bootstrap.SplitBar({
35875 dragElement : splitEl,
35876 resizingElement: this.el,
35877 orientation : this.orientation
35880 this.split.on("moved", this.onSplitMove, this);
35881 this.split.useShim = this.config.useShim === true;
35882 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35883 if(this.useSplitTips){
35884 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35886 //if(config.collapsible){
35887 // this.split.el.on("dblclick", this.collapse, this);
35890 if(typeof this.config.minSize != "undefined"){
35891 this.split.minSize = this.config.minSize;
35893 if(typeof this.config.maxSize != "undefined"){
35894 this.split.maxSize = this.config.maxSize;
35896 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35897 this.hideSplitter();
35902 getHMaxSize : function(){
35903 var cmax = this.config.maxSize || 10000;
35904 var center = this.mgr.getRegion("center");
35905 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35908 getVMaxSize : function(){
35909 var cmax = this.config.maxSize || 10000;
35910 var center = this.mgr.getRegion("center");
35911 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35914 onSplitMove : function(split, newSize){
35915 this.fireEvent("resized", this, newSize);
35919 * Returns the {@link Roo.SplitBar} for this region.
35920 * @return {Roo.SplitBar}
35922 getSplitBar : function(){
35927 this.hideSplitter();
35928 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35931 hideSplitter : function(){
35933 this.split.el.setLocation(-2000,-2000);
35934 this.split.el.hide();
35940 this.split.el.show();
35942 Roo.bootstrap.layout.Split.superclass.show.call(this);
35945 beforeSlide: function(){
35946 if(Roo.isGecko){// firefox overflow auto bug workaround
35947 this.bodyEl.clip();
35949 this.tabs.bodyEl.clip();
35951 if(this.activePanel){
35952 this.activePanel.getEl().clip();
35954 if(this.activePanel.beforeSlide){
35955 this.activePanel.beforeSlide();
35961 afterSlide : function(){
35962 if(Roo.isGecko){// firefox overflow auto bug workaround
35963 this.bodyEl.unclip();
35965 this.tabs.bodyEl.unclip();
35967 if(this.activePanel){
35968 this.activePanel.getEl().unclip();
35969 if(this.activePanel.afterSlide){
35970 this.activePanel.afterSlide();
35976 initAutoHide : function(){
35977 if(this.autoHide !== false){
35978 if(!this.autoHideHd){
35979 var st = new Roo.util.DelayedTask(this.slideIn, this);
35980 this.autoHideHd = {
35981 "mouseout": function(e){
35982 if(!e.within(this.el, true)){
35986 "mouseover" : function(e){
35992 this.el.on(this.autoHideHd);
35996 clearAutoHide : function(){
35997 if(this.autoHide !== false){
35998 this.el.un("mouseout", this.autoHideHd.mouseout);
35999 this.el.un("mouseover", this.autoHideHd.mouseover);
36003 clearMonitor : function(){
36004 Roo.get(document).un("click", this.slideInIf, this);
36007 // these names are backwards but not changed for compat
36008 slideOut : function(){
36009 if(this.isSlid || this.el.hasActiveFx()){
36012 this.isSlid = true;
36013 if(this.collapseBtn){
36014 this.collapseBtn.hide();
36016 this.closeBtnState = this.closeBtn.getStyle('display');
36017 this.closeBtn.hide();
36019 this.stickBtn.show();
36022 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36023 this.beforeSlide();
36024 this.el.setStyle("z-index", 10001);
36025 this.el.slideIn(this.getSlideAnchor(), {
36026 callback: function(){
36028 this.initAutoHide();
36029 Roo.get(document).on("click", this.slideInIf, this);
36030 this.fireEvent("slideshow", this);
36037 afterSlideIn : function(){
36038 this.clearAutoHide();
36039 this.isSlid = false;
36040 this.clearMonitor();
36041 this.el.setStyle("z-index", "");
36042 if(this.collapseBtn){
36043 this.collapseBtn.show();
36045 this.closeBtn.setStyle('display', this.closeBtnState);
36047 this.stickBtn.hide();
36049 this.fireEvent("slidehide", this);
36052 slideIn : function(cb){
36053 if(!this.isSlid || this.el.hasActiveFx()){
36057 this.isSlid = false;
36058 this.beforeSlide();
36059 this.el.slideOut(this.getSlideAnchor(), {
36060 callback: function(){
36061 this.el.setLeftTop(-10000, -10000);
36063 this.afterSlideIn();
36071 slideInIf : function(e){
36072 if(!e.within(this.el)){
36077 animateCollapse : function(){
36078 this.beforeSlide();
36079 this.el.setStyle("z-index", 20000);
36080 var anchor = this.getSlideAnchor();
36081 this.el.slideOut(anchor, {
36082 callback : function(){
36083 this.el.setStyle("z-index", "");
36084 this.collapsedEl.slideIn(anchor, {duration:.3});
36086 this.el.setLocation(-10000,-10000);
36088 this.fireEvent("collapsed", this);
36095 animateExpand : function(){
36096 this.beforeSlide();
36097 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36098 this.el.setStyle("z-index", 20000);
36099 this.collapsedEl.hide({
36102 this.el.slideIn(this.getSlideAnchor(), {
36103 callback : function(){
36104 this.el.setStyle("z-index", "");
36107 this.split.el.show();
36109 this.fireEvent("invalidated", this);
36110 this.fireEvent("expanded", this);
36138 getAnchor : function(){
36139 return this.anchors[this.position];
36142 getCollapseAnchor : function(){
36143 return this.canchors[this.position];
36146 getSlideAnchor : function(){
36147 return this.sanchors[this.position];
36150 getAlignAdj : function(){
36151 var cm = this.cmargins;
36152 switch(this.position){
36168 getExpandAdj : function(){
36169 var c = this.collapsedEl, cm = this.cmargins;
36170 switch(this.position){
36172 return [-(cm.right+c.getWidth()+cm.left), 0];
36175 return [cm.right+c.getWidth()+cm.left, 0];
36178 return [0, -(cm.top+cm.bottom+c.getHeight())];
36181 return [0, cm.top+cm.bottom+c.getHeight()];
36187 * Ext JS Library 1.1.1
36188 * Copyright(c) 2006-2007, Ext JS, LLC.
36190 * Originally Released Under LGPL - original licence link has changed is not relivant.
36193 * <script type="text/javascript">
36196 * These classes are private internal classes
36198 Roo.bootstrap.layout.Center = function(config){
36199 config.region = "center";
36200 Roo.bootstrap.layout.Region.call(this, config);
36201 this.visible = true;
36202 this.minWidth = config.minWidth || 20;
36203 this.minHeight = config.minHeight || 20;
36206 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36208 // center panel can't be hidden
36212 // center panel can't be hidden
36215 getMinWidth: function(){
36216 return this.minWidth;
36219 getMinHeight: function(){
36220 return this.minHeight;
36233 Roo.bootstrap.layout.North = function(config)
36235 config.region = 'north';
36236 config.cursor = 'n-resize';
36238 Roo.bootstrap.layout.Split.call(this, config);
36242 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36243 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36244 this.split.el.addClass("roo-layout-split-v");
36246 var size = config.initialSize || config.height;
36247 if(typeof size != "undefined"){
36248 this.el.setHeight(size);
36251 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36253 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36257 getBox : function(){
36258 if(this.collapsed){
36259 return this.collapsedEl.getBox();
36261 var box = this.el.getBox();
36263 box.height += this.split.el.getHeight();
36268 updateBox : function(box){
36269 if(this.split && !this.collapsed){
36270 box.height -= this.split.el.getHeight();
36271 this.split.el.setLeft(box.x);
36272 this.split.el.setTop(box.y+box.height);
36273 this.split.el.setWidth(box.width);
36275 if(this.collapsed){
36276 this.updateBody(box.width, null);
36278 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36286 Roo.bootstrap.layout.South = function(config){
36287 config.region = 'south';
36288 config.cursor = 's-resize';
36289 Roo.bootstrap.layout.Split.call(this, config);
36291 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36292 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36293 this.split.el.addClass("roo-layout-split-v");
36295 var size = config.initialSize || config.height;
36296 if(typeof size != "undefined"){
36297 this.el.setHeight(size);
36301 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36302 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36303 getBox : function(){
36304 if(this.collapsed){
36305 return this.collapsedEl.getBox();
36307 var box = this.el.getBox();
36309 var sh = this.split.el.getHeight();
36316 updateBox : function(box){
36317 if(this.split && !this.collapsed){
36318 var sh = this.split.el.getHeight();
36321 this.split.el.setLeft(box.x);
36322 this.split.el.setTop(box.y-sh);
36323 this.split.el.setWidth(box.width);
36325 if(this.collapsed){
36326 this.updateBody(box.width, null);
36328 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36332 Roo.bootstrap.layout.East = function(config){
36333 config.region = "east";
36334 config.cursor = "e-resize";
36335 Roo.bootstrap.layout.Split.call(this, config);
36337 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36338 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36339 this.split.el.addClass("roo-layout-split-h");
36341 var size = config.initialSize || config.width;
36342 if(typeof size != "undefined"){
36343 this.el.setWidth(size);
36346 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36347 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36348 getBox : function(){
36349 if(this.collapsed){
36350 return this.collapsedEl.getBox();
36352 var box = this.el.getBox();
36354 var sw = this.split.el.getWidth();
36361 updateBox : function(box){
36362 if(this.split && !this.collapsed){
36363 var sw = this.split.el.getWidth();
36365 this.split.el.setLeft(box.x);
36366 this.split.el.setTop(box.y);
36367 this.split.el.setHeight(box.height);
36370 if(this.collapsed){
36371 this.updateBody(null, box.height);
36373 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36377 Roo.bootstrap.layout.West = function(config){
36378 config.region = "west";
36379 config.cursor = "w-resize";
36381 Roo.bootstrap.layout.Split.call(this, config);
36383 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36384 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36385 this.split.el.addClass("roo-layout-split-h");
36389 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36390 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36392 onRender: function(ctr, pos)
36394 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36395 var size = this.config.initialSize || this.config.width;
36396 if(typeof size != "undefined"){
36397 this.el.setWidth(size);
36401 getBox : function(){
36402 if(this.collapsed){
36403 return this.collapsedEl.getBox();
36405 var box = this.el.getBox();
36407 box.width += this.split.el.getWidth();
36412 updateBox : function(box){
36413 if(this.split && !this.collapsed){
36414 var sw = this.split.el.getWidth();
36416 this.split.el.setLeft(box.x+box.width);
36417 this.split.el.setTop(box.y);
36418 this.split.el.setHeight(box.height);
36420 if(this.collapsed){
36421 this.updateBody(null, box.height);
36423 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36426 Roo.namespace("Roo.bootstrap.panel");/*
36428 * Ext JS Library 1.1.1
36429 * Copyright(c) 2006-2007, Ext JS, LLC.
36431 * Originally Released Under LGPL - original licence link has changed is not relivant.
36434 * <script type="text/javascript">
36437 * @class Roo.ContentPanel
36438 * @extends Roo.util.Observable
36439 * A basic ContentPanel element.
36440 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36441 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36442 * @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
36443 * @cfg {Boolean} closable True if the panel can be closed/removed
36444 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36445 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36446 * @cfg {Toolbar} toolbar A toolbar for this panel
36447 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36448 * @cfg {String} title The title for this panel
36449 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36450 * @cfg {String} url Calls {@link #setUrl} with this value
36451 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36452 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36453 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36454 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36455 * @cfg {Boolean} badges render the badges
36458 * Create a new ContentPanel.
36459 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36460 * @param {String/Object} config A string to set only the title or a config object
36461 * @param {String} content (optional) Set the HTML content for this panel
36462 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36464 Roo.bootstrap.panel.Content = function( config){
36466 this.tpl = config.tpl || false;
36468 var el = config.el;
36469 var content = config.content;
36471 if(config.autoCreate){ // xtype is available if this is called from factory
36474 this.el = Roo.get(el);
36475 if(!this.el && config && config.autoCreate){
36476 if(typeof config.autoCreate == "object"){
36477 if(!config.autoCreate.id){
36478 config.autoCreate.id = config.id||el;
36480 this.el = Roo.DomHelper.append(document.body,
36481 config.autoCreate, true);
36483 var elcfg = { tag: "div",
36484 cls: "roo-layout-inactive-content",
36488 elcfg.html = config.html;
36492 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36495 this.closable = false;
36496 this.loaded = false;
36497 this.active = false;
36500 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36502 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36504 this.wrapEl = this.el; //this.el.wrap();
36506 if (config.toolbar.items) {
36507 ti = config.toolbar.items ;
36508 delete config.toolbar.items ;
36512 this.toolbar.render(this.wrapEl, 'before');
36513 for(var i =0;i < ti.length;i++) {
36514 // Roo.log(['add child', items[i]]);
36515 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36517 this.toolbar.items = nitems;
36518 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36519 delete config.toolbar;
36523 // xtype created footer. - not sure if will work as we normally have to render first..
36524 if (this.footer && !this.footer.el && this.footer.xtype) {
36525 if (!this.wrapEl) {
36526 this.wrapEl = this.el.wrap();
36529 this.footer.container = this.wrapEl.createChild();
36531 this.footer = Roo.factory(this.footer, Roo);
36536 if(typeof config == "string"){
36537 this.title = config;
36539 Roo.apply(this, config);
36543 this.resizeEl = Roo.get(this.resizeEl, true);
36545 this.resizeEl = this.el;
36547 // handle view.xtype
36555 * Fires when this panel is activated.
36556 * @param {Roo.ContentPanel} this
36560 * @event deactivate
36561 * Fires when this panel is activated.
36562 * @param {Roo.ContentPanel} this
36564 "deactivate" : true,
36568 * Fires when this panel is resized if fitToFrame is true.
36569 * @param {Roo.ContentPanel} this
36570 * @param {Number} width The width after any component adjustments
36571 * @param {Number} height The height after any component adjustments
36577 * Fires when this tab is created
36578 * @param {Roo.ContentPanel} this
36589 if(this.autoScroll){
36590 this.resizeEl.setStyle("overflow", "auto");
36592 // fix randome scrolling
36593 //this.el.on('scroll', function() {
36594 // Roo.log('fix random scolling');
36595 // this.scrollTo('top',0);
36598 content = content || this.content;
36600 this.setContent(content);
36602 if(config && config.url){
36603 this.setUrl(this.url, this.params, this.loadOnce);
36608 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36610 if (this.view && typeof(this.view.xtype) != 'undefined') {
36611 this.view.el = this.el.appendChild(document.createElement("div"));
36612 this.view = Roo.factory(this.view);
36613 this.view.render && this.view.render(false, '');
36617 this.fireEvent('render', this);
36620 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36624 setRegion : function(region){
36625 this.region = region;
36626 this.setActiveClass(region && !this.background);
36630 setActiveClass: function(state)
36633 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36634 this.el.setStyle('position','relative');
36636 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36637 this.el.setStyle('position', 'absolute');
36642 * Returns the toolbar for this Panel if one was configured.
36643 * @return {Roo.Toolbar}
36645 getToolbar : function(){
36646 return this.toolbar;
36649 setActiveState : function(active)
36651 this.active = active;
36652 this.setActiveClass(active);
36654 if(this.fireEvent("deactivate", this) === false){
36659 this.fireEvent("activate", this);
36663 * Updates this panel's element
36664 * @param {String} content The new content
36665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36667 setContent : function(content, loadScripts){
36668 this.el.update(content, loadScripts);
36671 ignoreResize : function(w, h){
36672 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36675 this.lastSize = {width: w, height: h};
36680 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36681 * @return {Roo.UpdateManager} The UpdateManager
36683 getUpdateManager : function(){
36684 return this.el.getUpdateManager();
36687 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36688 * @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:
36691 url: "your-url.php",
36692 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36693 callback: yourFunction,
36694 scope: yourObject, //(optional scope)
36697 text: "Loading...",
36702 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36703 * 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.
36704 * @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}
36705 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36706 * @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.
36707 * @return {Roo.ContentPanel} this
36710 var um = this.el.getUpdateManager();
36711 um.update.apply(um, arguments);
36717 * 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.
36718 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36719 * @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)
36720 * @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)
36721 * @return {Roo.UpdateManager} The UpdateManager
36723 setUrl : function(url, params, loadOnce){
36724 if(this.refreshDelegate){
36725 this.removeListener("activate", this.refreshDelegate);
36727 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36728 this.on("activate", this.refreshDelegate);
36729 return this.el.getUpdateManager();
36732 _handleRefresh : function(url, params, loadOnce){
36733 if(!loadOnce || !this.loaded){
36734 var updater = this.el.getUpdateManager();
36735 updater.update(url, params, this._setLoaded.createDelegate(this));
36739 _setLoaded : function(){
36740 this.loaded = true;
36744 * Returns this panel's id
36747 getId : function(){
36752 * Returns this panel's element - used by regiosn to add.
36753 * @return {Roo.Element}
36755 getEl : function(){
36756 return this.wrapEl || this.el;
36761 adjustForComponents : function(width, height)
36763 //Roo.log('adjustForComponents ');
36764 if(this.resizeEl != this.el){
36765 width -= this.el.getFrameWidth('lr');
36766 height -= this.el.getFrameWidth('tb');
36769 var te = this.toolbar.getEl();
36770 te.setWidth(width);
36771 height -= te.getHeight();
36774 var te = this.footer.getEl();
36775 te.setWidth(width);
36776 height -= te.getHeight();
36780 if(this.adjustments){
36781 width += this.adjustments[0];
36782 height += this.adjustments[1];
36784 return {"width": width, "height": height};
36787 setSize : function(width, height){
36788 if(this.fitToFrame && !this.ignoreResize(width, height)){
36789 if(this.fitContainer && this.resizeEl != this.el){
36790 this.el.setSize(width, height);
36792 var size = this.adjustForComponents(width, height);
36793 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36794 this.fireEvent('resize', this, size.width, size.height);
36799 * Returns this panel's title
36802 getTitle : function(){
36804 if (typeof(this.title) != 'object') {
36809 for (var k in this.title) {
36810 if (!this.title.hasOwnProperty(k)) {
36814 if (k.indexOf('-') >= 0) {
36815 var s = k.split('-');
36816 for (var i = 0; i<s.length; i++) {
36817 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36820 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36827 * Set this panel's title
36828 * @param {String} title
36830 setTitle : function(title){
36831 this.title = title;
36833 this.region.updatePanelTitle(this, title);
36838 * Returns true is this panel was configured to be closable
36839 * @return {Boolean}
36841 isClosable : function(){
36842 return this.closable;
36845 beforeSlide : function(){
36847 this.resizeEl.clip();
36850 afterSlide : function(){
36852 this.resizeEl.unclip();
36856 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36857 * Will fail silently if the {@link #setUrl} method has not been called.
36858 * This does not activate the panel, just updates its content.
36860 refresh : function(){
36861 if(this.refreshDelegate){
36862 this.loaded = false;
36863 this.refreshDelegate();
36868 * Destroys this panel
36870 destroy : function(){
36871 this.el.removeAllListeners();
36872 var tempEl = document.createElement("span");
36873 tempEl.appendChild(this.el.dom);
36874 tempEl.innerHTML = "";
36880 * form - if the content panel contains a form - this is a reference to it.
36881 * @type {Roo.form.Form}
36885 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36886 * This contains a reference to it.
36892 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36902 * @param {Object} cfg Xtype definition of item to add.
36906 getChildContainer: function () {
36907 return this.getEl();
36912 var ret = new Roo.factory(cfg);
36917 if (cfg.xtype.match(/^Form$/)) {
36920 //if (this.footer) {
36921 // el = this.footer.container.insertSibling(false, 'before');
36923 el = this.el.createChild();
36926 this.form = new Roo.form.Form(cfg);
36929 if ( this.form.allItems.length) {
36930 this.form.render(el.dom);
36934 // should only have one of theses..
36935 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36936 // views.. should not be just added - used named prop 'view''
36938 cfg.el = this.el.appendChild(document.createElement("div"));
36941 var ret = new Roo.factory(cfg);
36943 ret.render && ret.render(false, ''); // render blank..
36953 * @class Roo.bootstrap.panel.Grid
36954 * @extends Roo.bootstrap.panel.Content
36956 * Create a new GridPanel.
36957 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36958 * @param {Object} config A the config object
36964 Roo.bootstrap.panel.Grid = function(config)
36968 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36969 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36971 config.el = this.wrapper;
36972 //this.el = this.wrapper;
36974 if (config.container) {
36975 // ctor'ed from a Border/panel.grid
36978 this.wrapper.setStyle("overflow", "hidden");
36979 this.wrapper.addClass('roo-grid-container');
36984 if(config.toolbar){
36985 var tool_el = this.wrapper.createChild();
36986 this.toolbar = Roo.factory(config.toolbar);
36988 if (config.toolbar.items) {
36989 ti = config.toolbar.items ;
36990 delete config.toolbar.items ;
36994 this.toolbar.render(tool_el);
36995 for(var i =0;i < ti.length;i++) {
36996 // Roo.log(['add child', items[i]]);
36997 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36999 this.toolbar.items = nitems;
37001 delete config.toolbar;
37004 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37005 config.grid.scrollBody = true;;
37006 config.grid.monitorWindowResize = false; // turn off autosizing
37007 config.grid.autoHeight = false;
37008 config.grid.autoWidth = false;
37010 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37012 if (config.background) {
37013 // render grid on panel activation (if panel background)
37014 this.on('activate', function(gp) {
37015 if (!gp.grid.rendered) {
37016 gp.grid.render(this.wrapper);
37017 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37022 this.grid.render(this.wrapper);
37023 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37026 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37027 // ??? needed ??? config.el = this.wrapper;
37032 // xtype created footer. - not sure if will work as we normally have to render first..
37033 if (this.footer && !this.footer.el && this.footer.xtype) {
37035 var ctr = this.grid.getView().getFooterPanel(true);
37036 this.footer.dataSource = this.grid.dataSource;
37037 this.footer = Roo.factory(this.footer, Roo);
37038 this.footer.render(ctr);
37048 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37049 getId : function(){
37050 return this.grid.id;
37054 * Returns the grid for this panel
37055 * @return {Roo.bootstrap.Table}
37057 getGrid : function(){
37061 setSize : function(width, height){
37062 if(!this.ignoreResize(width, height)){
37063 var grid = this.grid;
37064 var size = this.adjustForComponents(width, height);
37065 var gridel = grid.getGridEl();
37066 gridel.setSize(size.width, size.height);
37068 var thd = grid.getGridEl().select('thead',true).first();
37069 var tbd = grid.getGridEl().select('tbody', true).first();
37071 tbd.setSize(width, height - thd.getHeight());
37080 beforeSlide : function(){
37081 this.grid.getView().scroller.clip();
37084 afterSlide : function(){
37085 this.grid.getView().scroller.unclip();
37088 destroy : function(){
37089 this.grid.destroy();
37091 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37096 * @class Roo.bootstrap.panel.Nest
37097 * @extends Roo.bootstrap.panel.Content
37099 * Create a new Panel, that can contain a layout.Border.
37102 * @param {Roo.BorderLayout} layout The layout for this panel
37103 * @param {String/Object} config A string to set only the title or a config object
37105 Roo.bootstrap.panel.Nest = function(config)
37107 // construct with only one argument..
37108 /* FIXME - implement nicer consturctors
37109 if (layout.layout) {
37111 layout = config.layout;
37112 delete config.layout;
37114 if (layout.xtype && !layout.getEl) {
37115 // then layout needs constructing..
37116 layout = Roo.factory(layout, Roo);
37120 config.el = config.layout.getEl();
37122 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37124 config.layout.monitorWindowResize = false; // turn off autosizing
37125 this.layout = config.layout;
37126 this.layout.getEl().addClass("roo-layout-nested-layout");
37133 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37135 setSize : function(width, height){
37136 if(!this.ignoreResize(width, height)){
37137 var size = this.adjustForComponents(width, height);
37138 var el = this.layout.getEl();
37139 if (size.height < 1) {
37140 el.setWidth(size.width);
37142 el.setSize(size.width, size.height);
37144 var touch = el.dom.offsetWidth;
37145 this.layout.layout();
37146 // ie requires a double layout on the first pass
37147 if(Roo.isIE && !this.initialized){
37148 this.initialized = true;
37149 this.layout.layout();
37154 // activate all subpanels if not currently active..
37156 setActiveState : function(active){
37157 this.active = active;
37158 this.setActiveClass(active);
37161 this.fireEvent("deactivate", this);
37165 this.fireEvent("activate", this);
37166 // not sure if this should happen before or after..
37167 if (!this.layout) {
37168 return; // should not happen..
37171 for (var r in this.layout.regions) {
37172 reg = this.layout.getRegion(r);
37173 if (reg.getActivePanel()) {
37174 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37175 reg.setActivePanel(reg.getActivePanel());
37178 if (!reg.panels.length) {
37181 reg.showPanel(reg.getPanel(0));
37190 * Returns the nested BorderLayout for this panel
37191 * @return {Roo.BorderLayout}
37193 getLayout : function(){
37194 return this.layout;
37198 * Adds a xtype elements to the layout of the nested panel
37202 xtype : 'ContentPanel',
37209 xtype : 'NestedLayoutPanel',
37215 items : [ ... list of content panels or nested layout panels.. ]
37219 * @param {Object} cfg Xtype definition of item to add.
37221 addxtype : function(cfg) {
37222 return this.layout.addxtype(cfg);
37227 * Ext JS Library 1.1.1
37228 * Copyright(c) 2006-2007, Ext JS, LLC.
37230 * Originally Released Under LGPL - original licence link has changed is not relivant.
37233 * <script type="text/javascript">
37236 * @class Roo.TabPanel
37237 * @extends Roo.util.Observable
37238 * A lightweight tab container.
37242 // basic tabs 1, built from existing content
37243 var tabs = new Roo.TabPanel("tabs1");
37244 tabs.addTab("script", "View Script");
37245 tabs.addTab("markup", "View Markup");
37246 tabs.activate("script");
37248 // more advanced tabs, built from javascript
37249 var jtabs = new Roo.TabPanel("jtabs");
37250 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37252 // set up the UpdateManager
37253 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37254 var updater = tab2.getUpdateManager();
37255 updater.setDefaultUrl("ajax1.htm");
37256 tab2.on('activate', updater.refresh, updater, true);
37258 // Use setUrl for Ajax loading
37259 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37260 tab3.setUrl("ajax2.htm", null, true);
37263 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37266 jtabs.activate("jtabs-1");
37269 * Create a new TabPanel.
37270 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37271 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37273 Roo.bootstrap.panel.Tabs = function(config){
37275 * The container element for this TabPanel.
37276 * @type Roo.Element
37278 this.el = Roo.get(config.el);
37281 if(typeof config == "boolean"){
37282 this.tabPosition = config ? "bottom" : "top";
37284 Roo.apply(this, config);
37288 if(this.tabPosition == "bottom"){
37289 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37290 this.el.addClass("roo-tabs-bottom");
37292 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37293 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37294 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37296 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37298 if(this.tabPosition != "bottom"){
37299 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37300 * @type Roo.Element
37302 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37303 this.el.addClass("roo-tabs-top");
37307 this.bodyEl.setStyle("position", "relative");
37309 this.active = null;
37310 this.activateDelegate = this.activate.createDelegate(this);
37315 * Fires when the active tab changes
37316 * @param {Roo.TabPanel} this
37317 * @param {Roo.TabPanelItem} activePanel The new active tab
37321 * @event beforetabchange
37322 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37323 * @param {Roo.TabPanel} this
37324 * @param {Object} e Set cancel to true on this object to cancel the tab change
37325 * @param {Roo.TabPanelItem} tab The tab being changed to
37327 "beforetabchange" : true
37330 Roo.EventManager.onWindowResize(this.onResize, this);
37331 this.cpad = this.el.getPadding("lr");
37332 this.hiddenCount = 0;
37335 // toolbar on the tabbar support...
37336 if (this.toolbar) {
37337 alert("no toolbar support yet");
37338 this.toolbar = false;
37340 var tcfg = this.toolbar;
37341 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37342 this.toolbar = new Roo.Toolbar(tcfg);
37343 if (Roo.isSafari) {
37344 var tbl = tcfg.container.child('table', true);
37345 tbl.setAttribute('width', '100%');
37353 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37356 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37358 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37360 tabPosition : "top",
37362 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37364 currentTabWidth : 0,
37366 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37370 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37374 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37376 preferredTabWidth : 175,
37378 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37380 resizeTabs : false,
37382 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37384 monitorResize : true,
37386 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37391 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37392 * @param {String} id The id of the div to use <b>or create</b>
37393 * @param {String} text The text for the tab
37394 * @param {String} content (optional) Content to put in the TabPanelItem body
37395 * @param {Boolean} closable (optional) True to create a close icon on the tab
37396 * @return {Roo.TabPanelItem} The created TabPanelItem
37398 addTab : function(id, text, content, closable, tpl)
37400 var item = new Roo.bootstrap.panel.TabItem({
37404 closable : closable,
37407 this.addTabItem(item);
37409 item.setContent(content);
37415 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37416 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37417 * @return {Roo.TabPanelItem}
37419 getTab : function(id){
37420 return this.items[id];
37424 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37425 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37427 hideTab : function(id){
37428 var t = this.items[id];
37431 this.hiddenCount++;
37432 this.autoSizeTabs();
37437 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37438 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37440 unhideTab : function(id){
37441 var t = this.items[id];
37443 t.setHidden(false);
37444 this.hiddenCount--;
37445 this.autoSizeTabs();
37450 * Adds an existing {@link Roo.TabPanelItem}.
37451 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37453 addTabItem : function(item){
37454 this.items[item.id] = item;
37455 this.items.push(item);
37456 // if(this.resizeTabs){
37457 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37458 // this.autoSizeTabs();
37460 // item.autoSize();
37465 * Removes a {@link Roo.TabPanelItem}.
37466 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37468 removeTab : function(id){
37469 var items = this.items;
37470 var tab = items[id];
37471 if(!tab) { return; }
37472 var index = items.indexOf(tab);
37473 if(this.active == tab && items.length > 1){
37474 var newTab = this.getNextAvailable(index);
37479 this.stripEl.dom.removeChild(tab.pnode.dom);
37480 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37481 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37483 items.splice(index, 1);
37484 delete this.items[tab.id];
37485 tab.fireEvent("close", tab);
37486 tab.purgeListeners();
37487 this.autoSizeTabs();
37490 getNextAvailable : function(start){
37491 var items = this.items;
37493 // look for a next tab that will slide over to
37494 // replace the one being removed
37495 while(index < items.length){
37496 var item = items[++index];
37497 if(item && !item.isHidden()){
37501 // if one isn't found select the previous tab (on the left)
37504 var item = items[--index];
37505 if(item && !item.isHidden()){
37513 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37514 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37516 disableTab : function(id){
37517 var tab = this.items[id];
37518 if(tab && this.active != tab){
37524 * Enables a {@link Roo.TabPanelItem} that is disabled.
37525 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37527 enableTab : function(id){
37528 var tab = this.items[id];
37533 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37534 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37535 * @return {Roo.TabPanelItem} The TabPanelItem.
37537 activate : function(id){
37538 var tab = this.items[id];
37542 if(tab == this.active || tab.disabled){
37546 this.fireEvent("beforetabchange", this, e, tab);
37547 if(e.cancel !== true && !tab.disabled){
37549 this.active.hide();
37551 this.active = this.items[id];
37552 this.active.show();
37553 this.fireEvent("tabchange", this, this.active);
37559 * Gets the active {@link Roo.TabPanelItem}.
37560 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37562 getActiveTab : function(){
37563 return this.active;
37567 * Updates the tab body element to fit the height of the container element
37568 * for overflow scrolling
37569 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37571 syncHeight : function(targetHeight){
37572 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37573 var bm = this.bodyEl.getMargins();
37574 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37575 this.bodyEl.setHeight(newHeight);
37579 onResize : function(){
37580 if(this.monitorResize){
37581 this.autoSizeTabs();
37586 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37588 beginUpdate : function(){
37589 this.updating = true;
37593 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37595 endUpdate : function(){
37596 this.updating = false;
37597 this.autoSizeTabs();
37601 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37603 autoSizeTabs : function(){
37604 var count = this.items.length;
37605 var vcount = count - this.hiddenCount;
37606 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37609 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37610 var availWidth = Math.floor(w / vcount);
37611 var b = this.stripBody;
37612 if(b.getWidth() > w){
37613 var tabs = this.items;
37614 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37615 if(availWidth < this.minTabWidth){
37616 /*if(!this.sleft){ // incomplete scrolling code
37617 this.createScrollButtons();
37620 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37623 if(this.currentTabWidth < this.preferredTabWidth){
37624 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37630 * Returns the number of tabs in this TabPanel.
37633 getCount : function(){
37634 return this.items.length;
37638 * Resizes all the tabs to the passed width
37639 * @param {Number} The new width
37641 setTabWidth : function(width){
37642 this.currentTabWidth = width;
37643 for(var i = 0, len = this.items.length; i < len; i++) {
37644 if(!this.items[i].isHidden()) {
37645 this.items[i].setWidth(width);
37651 * Destroys this TabPanel
37652 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37654 destroy : function(removeEl){
37655 Roo.EventManager.removeResizeListener(this.onResize, this);
37656 for(var i = 0, len = this.items.length; i < len; i++){
37657 this.items[i].purgeListeners();
37659 if(removeEl === true){
37660 this.el.update("");
37665 createStrip : function(container)
37667 var strip = document.createElement("nav");
37668 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37669 container.appendChild(strip);
37673 createStripList : function(strip)
37675 // div wrapper for retard IE
37676 // returns the "tr" element.
37677 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37678 //'<div class="x-tabs-strip-wrap">'+
37679 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37680 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37681 return strip.firstChild; //.firstChild.firstChild.firstChild;
37683 createBody : function(container)
37685 var body = document.createElement("div");
37686 Roo.id(body, "tab-body");
37687 //Roo.fly(body).addClass("x-tabs-body");
37688 Roo.fly(body).addClass("tab-content");
37689 container.appendChild(body);
37692 createItemBody :function(bodyEl, id){
37693 var body = Roo.getDom(id);
37695 body = document.createElement("div");
37698 //Roo.fly(body).addClass("x-tabs-item-body");
37699 Roo.fly(body).addClass("tab-pane");
37700 bodyEl.insertBefore(body, bodyEl.firstChild);
37704 createStripElements : function(stripEl, text, closable, tpl)
37706 var td = document.createElement("li"); // was td..
37709 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37712 stripEl.appendChild(td);
37714 td.className = "x-tabs-closable";
37715 if(!this.closeTpl){
37716 this.closeTpl = new Roo.Template(
37717 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37718 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37719 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37722 var el = this.closeTpl.overwrite(td, {"text": text});
37723 var close = el.getElementsByTagName("div")[0];
37724 var inner = el.getElementsByTagName("em")[0];
37725 return {"el": el, "close": close, "inner": inner};
37728 // not sure what this is..
37729 // if(!this.tabTpl){
37730 //this.tabTpl = new Roo.Template(
37731 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37732 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37734 // this.tabTpl = new Roo.Template(
37735 // '<a href="#">' +
37736 // '<span unselectable="on"' +
37737 // (this.disableTooltips ? '' : ' title="{text}"') +
37738 // ' >{text}</span></a>'
37744 var template = tpl || this.tabTpl || false;
37748 template = new Roo.Template(
37750 '<span unselectable="on"' +
37751 (this.disableTooltips ? '' : ' title="{text}"') +
37752 ' >{text}</span></a>'
37756 switch (typeof(template)) {
37760 template = new Roo.Template(template);
37766 var el = template.overwrite(td, {"text": text});
37768 var inner = el.getElementsByTagName("span")[0];
37770 return {"el": el, "inner": inner};
37778 * @class Roo.TabPanelItem
37779 * @extends Roo.util.Observable
37780 * Represents an individual item (tab plus body) in a TabPanel.
37781 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37782 * @param {String} id The id of this TabPanelItem
37783 * @param {String} text The text for the tab of this TabPanelItem
37784 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37786 Roo.bootstrap.panel.TabItem = function(config){
37788 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37789 * @type Roo.TabPanel
37791 this.tabPanel = config.panel;
37793 * The id for this TabPanelItem
37796 this.id = config.id;
37798 this.disabled = false;
37800 this.text = config.text;
37802 this.loaded = false;
37803 this.closable = config.closable;
37806 * The body element for this TabPanelItem.
37807 * @type Roo.Element
37809 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37810 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37811 this.bodyEl.setStyle("display", "block");
37812 this.bodyEl.setStyle("zoom", "1");
37813 //this.hideAction();
37815 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37817 this.el = Roo.get(els.el);
37818 this.inner = Roo.get(els.inner, true);
37819 this.textEl = Roo.get(this.el.dom.firstChild, true);
37820 this.pnode = Roo.get(els.el.parentNode, true);
37821 // this.el.on("mousedown", this.onTabMouseDown, this);
37822 this.el.on("click", this.onTabClick, this);
37824 if(config.closable){
37825 var c = Roo.get(els.close, true);
37826 c.dom.title = this.closeText;
37827 c.addClassOnOver("close-over");
37828 c.on("click", this.closeClick, this);
37834 * Fires when this tab becomes the active tab.
37835 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37836 * @param {Roo.TabPanelItem} this
37840 * @event beforeclose
37841 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37842 * @param {Roo.TabPanelItem} this
37843 * @param {Object} e Set cancel to true on this object to cancel the close.
37845 "beforeclose": true,
37848 * Fires when this tab is closed.
37849 * @param {Roo.TabPanelItem} this
37853 * @event deactivate
37854 * Fires when this tab is no longer the active tab.
37855 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37856 * @param {Roo.TabPanelItem} this
37858 "deactivate" : true
37860 this.hidden = false;
37862 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37865 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37867 purgeListeners : function(){
37868 Roo.util.Observable.prototype.purgeListeners.call(this);
37869 this.el.removeAllListeners();
37872 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37875 this.pnode.addClass("active");
37878 this.tabPanel.stripWrap.repaint();
37880 this.fireEvent("activate", this.tabPanel, this);
37884 * Returns true if this tab is the active tab.
37885 * @return {Boolean}
37887 isActive : function(){
37888 return this.tabPanel.getActiveTab() == this;
37892 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37895 this.pnode.removeClass("active");
37897 this.fireEvent("deactivate", this.tabPanel, this);
37900 hideAction : function(){
37901 this.bodyEl.hide();
37902 this.bodyEl.setStyle("position", "absolute");
37903 this.bodyEl.setLeft("-20000px");
37904 this.bodyEl.setTop("-20000px");
37907 showAction : function(){
37908 this.bodyEl.setStyle("position", "relative");
37909 this.bodyEl.setTop("");
37910 this.bodyEl.setLeft("");
37911 this.bodyEl.show();
37915 * Set the tooltip for the tab.
37916 * @param {String} tooltip The tab's tooltip
37918 setTooltip : function(text){
37919 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37920 this.textEl.dom.qtip = text;
37921 this.textEl.dom.removeAttribute('title');
37923 this.textEl.dom.title = text;
37927 onTabClick : function(e){
37928 e.preventDefault();
37929 this.tabPanel.activate(this.id);
37932 onTabMouseDown : function(e){
37933 e.preventDefault();
37934 this.tabPanel.activate(this.id);
37937 getWidth : function(){
37938 return this.inner.getWidth();
37941 setWidth : function(width){
37942 var iwidth = width - this.pnode.getPadding("lr");
37943 this.inner.setWidth(iwidth);
37944 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37945 this.pnode.setWidth(width);
37949 * Show or hide the tab
37950 * @param {Boolean} hidden True to hide or false to show.
37952 setHidden : function(hidden){
37953 this.hidden = hidden;
37954 this.pnode.setStyle("display", hidden ? "none" : "");
37958 * Returns true if this tab is "hidden"
37959 * @return {Boolean}
37961 isHidden : function(){
37962 return this.hidden;
37966 * Returns the text for this tab
37969 getText : function(){
37973 autoSize : function(){
37974 //this.el.beginMeasure();
37975 this.textEl.setWidth(1);
37977 * #2804 [new] Tabs in Roojs
37978 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37980 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37981 //this.el.endMeasure();
37985 * Sets the text for the tab (Note: this also sets the tooltip text)
37986 * @param {String} text The tab's text and tooltip
37988 setText : function(text){
37990 this.textEl.update(text);
37991 this.setTooltip(text);
37992 //if(!this.tabPanel.resizeTabs){
37993 // this.autoSize();
37997 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37999 activate : function(){
38000 this.tabPanel.activate(this.id);
38004 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38006 disable : function(){
38007 if(this.tabPanel.active != this){
38008 this.disabled = true;
38009 this.pnode.addClass("disabled");
38014 * Enables this TabPanelItem if it was previously disabled.
38016 enable : function(){
38017 this.disabled = false;
38018 this.pnode.removeClass("disabled");
38022 * Sets the content for this TabPanelItem.
38023 * @param {String} content The content
38024 * @param {Boolean} loadScripts true to look for and load scripts
38026 setContent : function(content, loadScripts){
38027 this.bodyEl.update(content, loadScripts);
38031 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38032 * @return {Roo.UpdateManager} The UpdateManager
38034 getUpdateManager : function(){
38035 return this.bodyEl.getUpdateManager();
38039 * Set a URL to be used to load the content for this TabPanelItem.
38040 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38041 * @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)
38042 * @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)
38043 * @return {Roo.UpdateManager} The UpdateManager
38045 setUrl : function(url, params, loadOnce){
38046 if(this.refreshDelegate){
38047 this.un('activate', this.refreshDelegate);
38049 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38050 this.on("activate", this.refreshDelegate);
38051 return this.bodyEl.getUpdateManager();
38055 _handleRefresh : function(url, params, loadOnce){
38056 if(!loadOnce || !this.loaded){
38057 var updater = this.bodyEl.getUpdateManager();
38058 updater.update(url, params, this._setLoaded.createDelegate(this));
38063 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38064 * Will fail silently if the setUrl method has not been called.
38065 * This does not activate the panel, just updates its content.
38067 refresh : function(){
38068 if(this.refreshDelegate){
38069 this.loaded = false;
38070 this.refreshDelegate();
38075 _setLoaded : function(){
38076 this.loaded = true;
38080 closeClick : function(e){
38083 this.fireEvent("beforeclose", this, o);
38084 if(o.cancel !== true){
38085 this.tabPanel.removeTab(this.id);
38089 * The text displayed in the tooltip for the close icon.
38092 closeText : "Close this tab"
38095 * This script refer to:
38096 * Title: International Telephone Input
38097 * Author: Jack O'Connor
38098 * Code version: v12.1.12
38099 * Availability: https://github.com/jackocnr/intl-tel-input.git
38102 Roo.bootstrap.PhoneInputData = function() {
38105 "Afghanistan (افغانستان)",
38110 "Albania (Shqipëri)",
38115 "Algeria (الجزائر)",
38140 "Antigua and Barbuda",
38150 "Armenia (Հայաստան)",
38166 "Austria (Österreich)",
38171 "Azerbaijan (Azərbaycan)",
38181 "Bahrain (البحرين)",
38186 "Bangladesh (বাংলাদেশ)",
38196 "Belarus (Беларусь)",
38201 "Belgium (België)",
38231 "Bosnia and Herzegovina (Босна и Херцеговина)",
38246 "British Indian Ocean Territory",
38251 "British Virgin Islands",
38261 "Bulgaria (България)",
38271 "Burundi (Uburundi)",
38276 "Cambodia (កម្ពុជា)",
38281 "Cameroon (Cameroun)",
38290 ["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"]
38293 "Cape Verde (Kabu Verdi)",
38298 "Caribbean Netherlands",
38309 "Central African Republic (République centrafricaine)",
38329 "Christmas Island",
38335 "Cocos (Keeling) Islands",
38346 "Comoros (جزر القمر)",
38351 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38356 "Congo (Republic) (Congo-Brazzaville)",
38376 "Croatia (Hrvatska)",
38397 "Czech Republic (Česká republika)",
38402 "Denmark (Danmark)",
38417 "Dominican Republic (República Dominicana)",
38421 ["809", "829", "849"]
38439 "Equatorial Guinea (Guinea Ecuatorial)",
38459 "Falkland Islands (Islas Malvinas)",
38464 "Faroe Islands (Føroyar)",
38485 "French Guiana (Guyane française)",
38490 "French Polynesia (Polynésie française)",
38505 "Georgia (საქართველო)",
38510 "Germany (Deutschland)",
38530 "Greenland (Kalaallit Nunaat)",
38567 "Guinea-Bissau (Guiné Bissau)",
38592 "Hungary (Magyarország)",
38597 "Iceland (Ísland)",
38617 "Iraq (العراق)",
38633 "Israel (ישראל)",
38660 "Jordan (الأردن)",
38665 "Kazakhstan (Казахстан)",
38686 "Kuwait (الكويت)",
38691 "Kyrgyzstan (Кыргызстан)",
38701 "Latvia (Latvija)",
38706 "Lebanon (لبنان)",
38721 "Libya (ليبيا)",
38731 "Lithuania (Lietuva)",
38746 "Macedonia (FYROM) (Македонија)",
38751 "Madagascar (Madagasikara)",
38781 "Marshall Islands",
38791 "Mauritania (موريتانيا)",
38796 "Mauritius (Moris)",
38817 "Moldova (Republica Moldova)",
38827 "Mongolia (Монгол)",
38832 "Montenegro (Crna Gora)",
38842 "Morocco (المغرب)",
38848 "Mozambique (Moçambique)",
38853 "Myanmar (Burma) (မြန်မာ)",
38858 "Namibia (Namibië)",
38873 "Netherlands (Nederland)",
38878 "New Caledonia (Nouvelle-Calédonie)",
38913 "North Korea (조선 민주주의 인민 공화국)",
38918 "Northern Mariana Islands",
38934 "Pakistan (پاکستان)",
38944 "Palestine (فلسطين)",
38954 "Papua New Guinea",
38996 "Réunion (La Réunion)",
39002 "Romania (România)",
39018 "Saint Barthélemy",
39029 "Saint Kitts and Nevis",
39039 "Saint Martin (Saint-Martin (partie française))",
39045 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39050 "Saint Vincent and the Grenadines",
39065 "São Tomé and Príncipe (São Tomé e Príncipe)",
39070 "Saudi Arabia (المملكة العربية السعودية)",
39075 "Senegal (Sénégal)",
39105 "Slovakia (Slovensko)",
39110 "Slovenia (Slovenija)",
39120 "Somalia (Soomaaliya)",
39130 "South Korea (대한민국)",
39135 "South Sudan (جنوب السودان)",
39145 "Sri Lanka (ශ්රී ලංකාව)",
39150 "Sudan (السودان)",
39160 "Svalbard and Jan Mayen",
39171 "Sweden (Sverige)",
39176 "Switzerland (Schweiz)",
39181 "Syria (سوريا)",
39226 "Trinidad and Tobago",
39231 "Tunisia (تونس)",
39236 "Turkey (Türkiye)",
39246 "Turks and Caicos Islands",
39256 "U.S. Virgin Islands",
39266 "Ukraine (Україна)",
39271 "United Arab Emirates (الإمارات العربية المتحدة)",
39293 "Uzbekistan (Oʻzbekiston)",
39303 "Vatican City (Città del Vaticano)",
39314 "Vietnam (Việt Nam)",
39319 "Wallis and Futuna (Wallis-et-Futuna)",
39324 "Western Sahara (الصحراء الغربية)",
39330 "Yemen (اليمن)",
39354 * This script refer to:
39355 * Title: International Telephone Input
39356 * Author: Jack O'Connor
39357 * Code version: v12.1.12
39358 * Availability: https://github.com/jackocnr/intl-tel-input.git
39362 * @class Roo.bootstrap.PhoneInput
39363 * @extends Roo.bootstrap.TriggerField
39364 * An input with International dial-code selection
39366 * @cfg {String} defaultDialCode default '+852'
39367 * @cfg {Array} preferedCountries default []
39370 * Create a new PhoneInput.
39371 * @param {Object} config Configuration options
39374 Roo.bootstrap.PhoneInput = function(config) {
39375 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39378 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39380 listWidth: undefined,
39382 selectedClass: 'active',
39384 invalidClass : "has-warning",
39386 validClass: 'has-success',
39388 allowed: '0123456789',
39391 * @cfg {String} defaultDialCode The default dial code when initializing the input
39393 defaultDialCode: '+852',
39396 * @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
39398 preferedCountries: false,
39400 getAutoCreate : function()
39402 var data = Roo.bootstrap.PhoneInputData();
39403 var align = this.labelAlign || this.parentLabelAlign();
39406 this.allCountries = [];
39407 this.dialCodeMapping = [];
39409 for (var i = 0; i < data.length; i++) {
39411 this.allCountries[i] = {
39415 priority: c[3] || 0,
39416 areaCodes: c[4] || null
39418 this.dialCodeMapping[c[2]] = {
39421 priority: c[3] || 0,
39422 areaCodes: c[4] || null
39434 cls : 'form-control tel-input',
39435 autocomplete: 'new-password'
39438 var hiddenInput = {
39441 cls: 'hidden-tel-input'
39445 hiddenInput.name = this.name;
39448 if (this.disabled) {
39449 input.disabled = true;
39452 var flag_container = {
39469 cls: this.hasFeedback ? 'has-feedback' : '',
39475 cls: 'dial-code-holder',
39482 cls: 'roo-select2-container input-group',
39489 if (this.fieldLabel.length) {
39492 tooltip: 'This field is required'
39498 cls: 'control-label',
39504 html: this.fieldLabel
39507 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39513 if(this.indicatorpos == 'right') {
39514 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39521 if(align == 'left') {
39529 if(this.labelWidth > 12){
39530 label.style = "width: " + this.labelWidth + 'px';
39532 if(this.labelWidth < 13 && this.labelmd == 0){
39533 this.labelmd = this.labelWidth;
39535 if(this.labellg > 0){
39536 label.cls += ' col-lg-' + this.labellg;
39537 input.cls += ' col-lg-' + (12 - this.labellg);
39539 if(this.labelmd > 0){
39540 label.cls += ' col-md-' + this.labelmd;
39541 container.cls += ' col-md-' + (12 - this.labelmd);
39543 if(this.labelsm > 0){
39544 label.cls += ' col-sm-' + this.labelsm;
39545 container.cls += ' col-sm-' + (12 - this.labelsm);
39547 if(this.labelxs > 0){
39548 label.cls += ' col-xs-' + this.labelxs;
39549 container.cls += ' col-xs-' + (12 - this.labelxs);
39559 var settings = this;
39561 ['xs','sm','md','lg'].map(function(size){
39562 if (settings[size]) {
39563 cfg.cls += ' col-' + size + '-' + settings[size];
39567 this.store = new Roo.data.Store({
39568 proxy : new Roo.data.MemoryProxy({}),
39569 reader : new Roo.data.JsonReader({
39580 'name' : 'dialCode',
39584 'name' : 'priority',
39588 'name' : 'areaCodes',
39595 if(!this.preferedCountries) {
39596 this.preferedCountries = [
39603 var p = this.preferedCountries.reverse();
39606 for (var i = 0; i < p.length; i++) {
39607 for (var j = 0; j < this.allCountries.length; j++) {
39608 if(this.allCountries[j].iso2 == p[i]) {
39609 var t = this.allCountries[j];
39610 this.allCountries.splice(j,1);
39611 this.allCountries.unshift(t);
39617 this.store.proxy.data = {
39619 data: this.allCountries
39625 initEvents : function()
39628 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39630 this.indicator = this.indicatorEl();
39631 this.flag = this.flagEl();
39632 this.dialCodeHolder = this.dialCodeHolderEl();
39634 this.trigger = this.el.select('div.flag-box',true).first();
39635 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39640 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39641 _this.list.setWidth(lw);
39644 this.list.on('mouseover', this.onViewOver, this);
39645 this.list.on('mousemove', this.onViewMove, this);
39646 this.inputEl().on("keyup", this.onKeyUp, this);
39648 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39650 this.view = new Roo.View(this.list, this.tpl, {
39651 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39654 this.view.on('click', this.onViewClick, this);
39655 this.setValue(this.defaultDialCode);
39658 onTriggerClick : function(e)
39660 Roo.log('trigger click');
39665 if(this.isExpanded()){
39667 this.hasFocus = false;
39669 this.store.load({});
39670 this.hasFocus = true;
39675 isExpanded : function()
39677 return this.list.isVisible();
39680 collapse : function()
39682 if(!this.isExpanded()){
39686 Roo.get(document).un('mousedown', this.collapseIf, this);
39687 Roo.get(document).un('mousewheel', this.collapseIf, this);
39688 this.fireEvent('collapse', this);
39692 expand : function()
39696 if(this.isExpanded() || !this.hasFocus){
39700 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39701 this.list.setWidth(lw);
39704 this.restrictHeight();
39706 Roo.get(document).on('mousedown', this.collapseIf, this);
39707 Roo.get(document).on('mousewheel', this.collapseIf, this);
39709 this.fireEvent('expand', this);
39712 restrictHeight : function()
39714 this.list.alignTo(this.inputEl(), this.listAlign);
39715 this.list.alignTo(this.inputEl(), this.listAlign);
39718 onViewOver : function(e, t)
39720 if(this.inKeyMode){
39723 var item = this.view.findItemFromChild(t);
39726 var index = this.view.indexOf(item);
39727 this.select(index, false);
39732 onViewClick : function(view, doFocus, el, e)
39734 var index = this.view.getSelectedIndexes()[0];
39736 var r = this.store.getAt(index);
39739 this.onSelect(r, index);
39741 if(doFocus !== false && !this.blockFocus){
39742 this.inputEl().focus();
39746 onViewMove : function(e, t)
39748 this.inKeyMode = false;
39751 select : function(index, scrollIntoView)
39753 this.selectedIndex = index;
39754 this.view.select(index);
39755 if(scrollIntoView !== false){
39756 var el = this.view.getNode(index);
39758 this.list.scrollChildIntoView(el, false);
39763 createList : function()
39765 this.list = Roo.get(document.body).createChild({
39767 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39768 style: 'display:none'
39770 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39773 collapseIf : function(e)
39775 var in_combo = e.within(this.el);
39776 var in_list = e.within(this.list);
39777 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39779 if (in_combo || in_list || is_list) {
39785 onSelect : function(record, index)
39787 if(this.fireEvent('beforeselect', this, record, index) !== false){
39789 this.setFlagClass(record.data.iso2);
39790 this.setDialCode(record.data.dialCode);
39791 this.hasFocus = false;
39793 this.fireEvent('select', this, record, index);
39797 flagEl : function()
39799 var flag = this.el.select('div.flag',true).first();
39806 dialCodeHolderEl : function()
39808 var d = this.el.select('input.dial-code-holder',true).first();
39815 setDialCode : function(v)
39817 this.dialCodeHolder.dom.value = '+'+v;
39820 setFlagClass : function(n)
39822 this.flag.dom.className = 'flag '+n;
39825 getValue : function()
39827 var v = this.inputEl().getValue();
39828 if(this.dialCodeHolder) {
39829 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39834 setValue : function(v)
39836 var d = this.getDialCode(v);
39838 //invalid dial code
39839 if(v.length == 0 || !d || d.length == 0) {
39841 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39842 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39848 this.setFlagClass(this.dialCodeMapping[d].iso2);
39849 this.setDialCode(d);
39850 this.inputEl().dom.value = v.replace('+'+d,'');
39851 this.hiddenEl().dom.value = this.getValue();
39856 getDialCode : function(v = '')
39858 if (v.length == 0) {
39859 return this.dialCodeHolder.dom.value;
39863 if (v.charAt(0) != "+") {
39866 var numericChars = "";
39867 for (var i = 1; i < v.length; i++) {
39868 var c = v.charAt(i);
39871 if (this.dialCodeMapping[numericChars]) {
39872 dialCode = v.substr(1, i);
39874 if (numericChars.length == 4) {
39884 this.setValue(this.defaultDialCode);
39888 hiddenEl : function()
39890 return this.el.select('input.hidden-tel-input',true).first();
39893 onKeyUp : function(e){
39895 var k = e.getKey();
39896 var c = e.getCharCode();
39899 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39900 this.allowed.indexOf(String.fromCharCode(c)) === -1
39905 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39908 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39912 this.setValue(this.getValue());
39917 * @class Roo.bootstrap.MoneyField
39918 * @extends Roo.bootstrap.ComboBox
39919 * Bootstrap MoneyField class
39922 * Create a new MoneyField.
39923 * @param {Object} config Configuration options
39926 Roo.bootstrap.MoneyField = function(config) {
39928 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39932 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39935 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39937 allowDecimals : true,
39939 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39941 decimalSeparator : ".",
39943 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39945 decimalPrecision : 2,
39947 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39949 allowNegative : true,
39951 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39953 minValue : Number.NEGATIVE_INFINITY,
39955 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39957 maxValue : Number.MAX_VALUE,
39959 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39961 minText : "The minimum value for this field is {0}",
39963 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39965 maxText : "The maximum value for this field is {0}",
39967 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39968 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39970 nanText : "{0} is not a valid number",
39972 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39976 * @cfg {String} defaults currency of the MoneyField
39977 * value should be in lkey
39979 defaultCurrency : false,
39989 getAutoCreate : function()
39991 var align = this.labelAlign || this.parentLabelAlign();
40003 cls : 'form-control roo-money-amount-input',
40004 autocomplete: 'new-password'
40008 input.name = this.name;
40011 if (this.disabled) {
40012 input.disabled = true;
40015 var clg = 12 - this.inputlg;
40016 var cmd = 12 - this.inputmd;
40017 var csm = 12 - this.inputsm;
40018 var cxs = 12 - this.inputxs;
40022 cls : 'row roo-money-field',
40026 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40030 cls: 'roo-select2-container input-group',
40034 cls : 'form-control roo-money-currency-input',
40035 autocomplete: 'new-password',
40037 name : this.currencyName
40041 cls : 'input-group-addon',
40055 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40059 cls: this.hasFeedback ? 'has-feedback' : '',
40070 if (this.fieldLabel.length) {
40073 tooltip: 'This field is required'
40079 cls: 'control-label',
40085 html: this.fieldLabel
40088 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40094 if(this.indicatorpos == 'right') {
40095 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40102 if(align == 'left') {
40110 if(this.labelWidth > 12){
40111 label.style = "width: " + this.labelWidth + 'px';
40113 if(this.labelWidth < 13 && this.labelmd == 0){
40114 this.labelmd = this.labelWidth;
40116 if(this.labellg > 0){
40117 label.cls += ' col-lg-' + this.labellg;
40118 input.cls += ' col-lg-' + (12 - this.labellg);
40120 if(this.labelmd > 0){
40121 label.cls += ' col-md-' + this.labelmd;
40122 container.cls += ' col-md-' + (12 - this.labelmd);
40124 if(this.labelsm > 0){
40125 label.cls += ' col-sm-' + this.labelsm;
40126 container.cls += ' col-sm-' + (12 - this.labelsm);
40128 if(this.labelxs > 0){
40129 label.cls += ' col-xs-' + this.labelxs;
40130 container.cls += ' col-xs-' + (12 - this.labelxs);
40140 var settings = this;
40142 ['xs','sm','md','lg'].map(function(size){
40143 if (settings[size]) {
40144 cfg.cls += ' col-' + size + '-' + settings[size];
40152 initEvents : function()
40154 this.indicator = this.indicatorEl();
40156 this.initCurrencyEvent();
40158 this.initNumberEvent();
40162 initCurrencyEvent : function()
40165 throw "can not find store for combo";
40168 this.store = Roo.factory(this.store, Roo.data);
40169 this.store.parent = this;
40173 this.triggerEl = this.el.select('.input-group-addon', true).first();
40175 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40180 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40181 _this.list.setWidth(lw);
40184 this.list.on('mouseover', this.onViewOver, this);
40185 this.list.on('mousemove', this.onViewMove, this);
40186 this.list.on('scroll', this.onViewScroll, this);
40189 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40192 this.view = new Roo.View(this.list, this.tpl, {
40193 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40196 this.view.on('click', this.onViewClick, this);
40198 this.store.on('beforeload', this.onBeforeLoad, this);
40199 this.store.on('load', this.onLoad, this);
40200 this.store.on('loadexception', this.onLoadException, this);
40202 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40203 "up" : function(e){
40204 this.inKeyMode = true;
40208 "down" : function(e){
40209 if(!this.isExpanded()){
40210 this.onTriggerClick();
40212 this.inKeyMode = true;
40217 "enter" : function(e){
40220 if(this.fireEvent("specialkey", this, e)){
40221 this.onViewClick(false);
40227 "esc" : function(e){
40231 "tab" : function(e){
40234 if(this.fireEvent("specialkey", this, e)){
40235 this.onViewClick(false);
40243 doRelay : function(foo, bar, hname){
40244 if(hname == 'down' || this.scope.isExpanded()){
40245 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40253 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40257 initNumberEvent : function(e)
40259 this.inputEl().on("keydown" , this.fireKey, this);
40260 this.inputEl().on("focus", this.onFocus, this);
40261 this.inputEl().on("blur", this.onBlur, this);
40263 this.inputEl().relayEvent('keyup', this);
40265 if(this.indicator){
40266 this.indicator.addClass('invisible');
40269 this.originalValue = this.getValue();
40271 if(this.validationEvent == 'keyup'){
40272 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40273 this.inputEl().on('keyup', this.filterValidation, this);
40275 else if(this.validationEvent !== false){
40276 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40279 if(this.selectOnFocus){
40280 this.on("focus", this.preFocus, this);
40283 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40284 this.inputEl().on("keypress", this.filterKeys, this);
40286 this.inputEl().relayEvent('keypress', this);
40289 var allowed = "0123456789";
40291 if(this.allowDecimals){
40292 allowed += this.decimalSeparator;
40295 if(this.allowNegative){
40299 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40301 var keyPress = function(e){
40303 var k = e.getKey();
40305 var c = e.getCharCode();
40308 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40309 allowed.indexOf(String.fromCharCode(c)) === -1
40315 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40319 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40324 this.inputEl().on("keypress", keyPress, this);
40328 onTriggerClick : function(e)
40335 this.loadNext = false;
40337 if(this.isExpanded()){
40342 this.hasFocus = true;
40344 if(this.triggerAction == 'all') {
40345 this.doQuery(this.allQuery, true);
40349 this.doQuery(this.getRawValue());
40352 getCurrency : function()
40354 var v = this.currencyEl().getValue();
40359 restrictHeight : function()
40361 this.list.alignTo(this.currencyEl(), this.listAlign);
40362 this.list.alignTo(this.currencyEl(), this.listAlign);
40365 onViewClick : function(view, doFocus, el, e)
40367 var index = this.view.getSelectedIndexes()[0];
40369 var r = this.store.getAt(index);
40372 this.onSelect(r, index);
40376 onSelect : function(record, index){
40378 if(this.fireEvent('beforeselect', this, record, index) !== false){
40380 this.setFromCurrencyData(index > -1 ? record.data : false);
40384 this.fireEvent('select', this, record, index);
40388 setFromCurrencyData : function(o)
40392 this.lastCurrency = o;
40394 if (this.currencyField) {
40395 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40397 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40400 this.lastSelectionText = currency;
40402 //setting default currency
40403 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40404 this.setCurrency(this.defaultCurrency);
40408 this.setCurrency(currency);
40411 setFromData : function(o)
40415 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40417 this.setFromCurrencyData(c);
40422 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40424 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40427 this.setValue(value);
40431 setCurrency : function(v)
40433 this.currencyValue = v;
40436 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40441 setValue : function(v)
40443 v = this.fixPrecision(v);
40445 v = String(v).replace(".", this.decimalSeparator);
40450 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40455 getRawValue : function()
40457 var v = this.inputEl().getValue();
40462 getValue : function()
40464 return this.fixPrecision(this.parseValue(this.getRawValue()));
40467 parseValue : function(value)
40469 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40470 return isNaN(value) ? '' : value;
40473 fixPrecision : function(value)
40475 var nan = isNaN(value);
40477 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40478 return nan ? '' : value;
40481 return parseFloat(value).toFixed(this.decimalPrecision);
40484 decimalPrecisionFcn : function(v)
40486 return Math.floor(v);
40489 validateValue : function(value)
40491 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40495 var num = this.parseValue(value);
40498 this.markInvalid(String.format(this.nanText, value));
40502 if(num < this.minValue){
40503 this.markInvalid(String.format(this.minText, this.minValue));
40507 if(num > this.maxValue){
40508 this.markInvalid(String.format(this.maxText, this.maxValue));
40515 validate : function()
40517 if(this.disabled || this.allowBlank){
40522 var currency = this.getCurrency();
40524 if(this.validateValue(this.getRawValue()) && currency.length){
40529 this.markInvalid();
40533 getName: function()
40538 beforeBlur : function()
40544 var v = this.parseValue(this.getRawValue());
40551 onBlur : function()
40555 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40556 //this.el.removeClass(this.focusClass);
40559 this.hasFocus = false;
40561 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40565 var v = this.getValue();
40567 if(String(v) !== String(this.startValue)){
40568 this.fireEvent('change', this, v, this.startValue);
40571 this.fireEvent("blur", this);
40574 inputEl : function()
40576 return this.el.select('.roo-money-amount-input', true).first();
40579 currencyEl : function()
40581 return this.el.select('.roo-money-currency-input', true).first();