4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 Roo.log('start render...');
313 Roo.log(this[cntr](true));
314 if(cn.render && cn.render(this[cntr](true)) === false){
319 // then add the element..
327 if (typeof (tree.menu) != 'undefined') {
328 tree.menu.parentType = cn.xtype;
329 tree.menu.triggerEl = cn.el;
330 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
334 if (!tree.items || !tree.items.length) {
336 //Roo.log(["no children", this]);
341 var items = tree.items;
344 //Roo.log(items.length);
346 if (!skip_children) {
347 for(var i =0;i < items.length;i++) {
348 // Roo.log(['add child', items[i]]);
349 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
355 //Roo.log("fire childrenrendered");
357 cn.fireEvent('childrenrendered', this);
362 * Show a component - removes 'hidden' class
367 this.el.removeClass('hidden');
371 * Hide a component - adds 'hidden' class
375 if (this.el && !this.el.hasClass('hidden')) {
376 this.el.addClass('hidden');
389 * @class Roo.bootstrap.Body
390 * @extends Roo.bootstrap.Component
391 * Bootstrap Body class
395 * @param {Object} config The config object
398 Roo.bootstrap.Body = function(config){
400 config = config || {};
402 Roo.bootstrap.Body.superclass.constructor.call(this, config);
403 this.el = Roo.get(config.el ? config.el : document.body );
404 if (this.cls && this.cls.length) {
405 Roo.get(document.body).addClass(this.cls);
409 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
411 is_body : true,// just to make sure it's constructed?
416 onRender : function(ct, position)
418 /* Roo.log("Roo.bootstrap.Body - onRender");
419 if (this.cls && this.cls.length) {
420 Roo.get(document.body).addClass(this.cls);
439 * @class Roo.bootstrap.ButtonGroup
440 * @extends Roo.bootstrap.Component
441 * Bootstrap ButtonGroup class
442 * @cfg {String} size lg | sm | xs (default empty normal)
443 * @cfg {String} align vertical | justified (default none)
444 * @cfg {String} direction up | down (default down)
445 * @cfg {Boolean} toolbar false | true
446 * @cfg {Boolean} btn true | false
451 * @param {Object} config The config object
454 Roo.bootstrap.ButtonGroup = function(config){
455 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
458 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
466 getAutoCreate : function(){
472 cfg.html = this.html || cfg.html;
483 if (['vertical','justified'].indexOf(this.align)!==-1) {
484 cfg.cls = 'btn-group-' + this.align;
486 if (this.align == 'justified') {
487 console.log(this.items);
491 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
492 cfg.cls += ' btn-group-' + this.size;
495 if (this.direction == 'up') {
496 cfg.cls += ' dropup' ;
512 * @class Roo.bootstrap.Button
513 * @extends Roo.bootstrap.Component
514 * Bootstrap Button class
515 * @cfg {String} html The button content
516 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
517 * @cfg {String} size ( lg | sm | xs)
518 * @cfg {String} tag ( a | input | submit)
519 * @cfg {String} href empty or href
520 * @cfg {Boolean} disabled default false;
521 * @cfg {Boolean} isClose default false;
522 * @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)
523 * @cfg {String} badge text for badge
524 * @cfg {String} theme default
525 * @cfg {Boolean} inverse
526 * @cfg {Boolean} toggle
527 * @cfg {String} ontext text for on toggle state
528 * @cfg {String} offtext text for off toggle state
529 * @cfg {Boolean} defaulton
530 * @cfg {Boolean} preventDefault default true
531 * @cfg {Boolean} removeClass remove the standard class..
532 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
535 * Create a new button
536 * @param {Object} config The config object
540 Roo.bootstrap.Button = function(config){
541 Roo.bootstrap.Button.superclass.constructor.call(this, config);
542 this.weightClass = ["btn-default",
554 * When a butotn is pressed
555 * @param {Roo.bootstrap.Button} this
556 * @param {Roo.EventObject} e
561 * After the button has been toggles
562 * @param {Roo.EventObject} e
563 * @param {boolean} pressed (also available as button.pressed)
569 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
587 preventDefault: true,
596 getAutoCreate : function(){
604 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
605 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
610 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
612 if (this.toggle == true) {
615 cls: 'slider-frame roo-button',
620 'data-off-text':'OFF',
621 cls: 'slider-button',
627 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
628 cfg.cls += ' '+this.weight;
637 cfg["aria-hidden"] = true;
639 cfg.html = "×";
645 if (this.theme==='default') {
646 cfg.cls = 'btn roo-button';
648 //if (this.parentType != 'Navbar') {
649 this.weight = this.weight.length ? this.weight : 'default';
651 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
653 cfg.cls += ' btn-' + this.weight;
655 } else if (this.theme==='glow') {
658 cfg.cls = 'btn-glow roo-button';
660 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
662 cfg.cls += ' ' + this.weight;
668 this.cls += ' inverse';
673 cfg.cls += ' active';
677 cfg.disabled = 'disabled';
681 Roo.log('changing to ul' );
683 this.glyphicon = 'caret';
686 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
688 //gsRoo.log(this.parentType);
689 if (this.parentType === 'Navbar' && !this.parent().bar) {
690 Roo.log('changing to li?');
699 href : this.href || '#'
702 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
703 cfg.cls += ' dropdown';
710 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
712 if (this.glyphicon) {
713 cfg.html = ' ' + cfg.html;
718 cls: 'glyphicon glyphicon-' + this.glyphicon
728 // cfg.cls='btn roo-button';
732 var value = cfg.html;
737 cls: 'glyphicon glyphicon-' + this.glyphicon,
756 cfg.cls += ' dropdown';
757 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
760 if (cfg.tag !== 'a' && this.href !== '') {
761 throw "Tag must be a to set href.";
762 } else if (this.href.length > 0) {
763 cfg.href = this.href;
766 if(this.removeClass){
771 cfg.target = this.target;
776 initEvents: function() {
777 // Roo.log('init events?');
778 // Roo.log(this.el.dom);
781 if (typeof (this.menu) != 'undefined') {
782 this.menu.parentType = this.xtype;
783 this.menu.triggerEl = this.el;
784 this.addxtype(Roo.apply({}, this.menu));
788 if (this.el.hasClass('roo-button')) {
789 this.el.on('click', this.onClick, this);
791 this.el.select('.roo-button').on('click', this.onClick, this);
794 if(this.removeClass){
795 this.el.on('click', this.onClick, this);
798 this.el.enableDisplayMode();
801 onClick : function(e)
808 Roo.log('button on click ');
809 if(this.preventDefault){
812 if (this.pressed === true || this.pressed === false) {
813 this.pressed = !this.pressed;
814 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
815 this.fireEvent('toggle', this, e, this.pressed);
819 this.fireEvent('click', this, e);
823 * Enables this button
827 this.disabled = false;
828 this.el.removeClass('disabled');
832 * Disable this button
836 this.disabled = true;
837 this.el.addClass('disabled');
840 * sets the active state on/off,
841 * @param {Boolean} state (optional) Force a particular state
843 setActive : function(v) {
845 this.el[v ? 'addClass' : 'removeClass']('active');
848 * toggles the current active state
850 toggleActive : function()
852 var active = this.el.hasClass('active');
853 this.setActive(!active);
857 setText : function(str)
859 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
863 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
874 setWeight : function(str)
876 this.el.removeClass(this.weightClass);
877 this.el.addClass('btn-' + str);
891 * @class Roo.bootstrap.Column
892 * @extends Roo.bootstrap.Component
893 * Bootstrap Column class
894 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
895 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
896 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
897 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
898 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
899 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
900 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
901 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
904 * @cfg {Boolean} hidden (true|false) hide the element
905 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
906 * @cfg {String} fa (ban|check|...) font awesome icon
907 * @cfg {Number} fasize (1|2|....) font awsome size
909 * @cfg {String} icon (info-sign|check|...) glyphicon name
911 * @cfg {String} html content of column.
914 * Create a new Column
915 * @param {Object} config The config object
918 Roo.bootstrap.Column = function(config){
919 Roo.bootstrap.Column.superclass.constructor.call(this, config);
922 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
940 getAutoCreate : function(){
941 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
949 ['xs','sm','md','lg'].map(function(size){
950 //Roo.log( size + ':' + settings[size]);
952 if (settings[size+'off'] !== false) {
953 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
956 if (settings[size] === false) {
960 if (!settings[size]) { // 0 = hidden
961 cfg.cls += ' hidden-' + size;
964 cfg.cls += ' col-' + size + '-' + settings[size];
969 cfg.cls += ' hidden';
972 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
973 cfg.cls +=' alert alert-' + this.alert;
977 if (this.html.length) {
978 cfg.html = this.html;
982 if (this.fasize > 1) {
983 fasize = ' fa-' + this.fasize + 'x';
985 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
990 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1009 * @class Roo.bootstrap.Container
1010 * @extends Roo.bootstrap.Component
1011 * Bootstrap Container class
1012 * @cfg {Boolean} jumbotron is it a jumbotron element
1013 * @cfg {String} html content of element
1014 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1015 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1016 * @cfg {String} header content of header (for panel)
1017 * @cfg {String} footer content of footer (for panel)
1018 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1019 * @cfg {String} tag (header|aside|section) type of HTML tag.
1020 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1021 * @cfg {String} fa font awesome icon
1022 * @cfg {String} icon (info-sign|check|...) glyphicon name
1023 * @cfg {Boolean} hidden (true|false) hide the element
1024 * @cfg {Boolean} expandable (true|false) default false
1025 * @cfg {Boolean} expanded (true|false) default true
1026 * @cfg {String} rheader contet on the right of header
1027 * @cfg {Boolean} clickable (true|false) default false
1031 * Create a new Container
1032 * @param {Object} config The config object
1035 Roo.bootstrap.Container = function(config){
1036 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1042 * After the panel has been expand
1044 * @param {Roo.bootstrap.Container} this
1049 * After the panel has been collapsed
1051 * @param {Roo.bootstrap.Container} this
1056 * When a element is chick
1057 * @param {Roo.bootstrap.Container} this
1058 * @param {Roo.EventObject} e
1064 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1082 getChildContainer : function() {
1088 if (this.panel.length) {
1089 return this.el.select('.panel-body',true).first();
1096 getAutoCreate : function(){
1099 tag : this.tag || 'div',
1103 if (this.jumbotron) {
1104 cfg.cls = 'jumbotron';
1109 // - this is applied by the parent..
1111 // cfg.cls = this.cls + '';
1114 if (this.sticky.length) {
1116 var bd = Roo.get(document.body);
1117 if (!bd.hasClass('bootstrap-sticky')) {
1118 bd.addClass('bootstrap-sticky');
1119 Roo.select('html',true).setStyle('height', '100%');
1122 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1126 if (this.well.length) {
1127 switch (this.well) {
1130 cfg.cls +=' well well-' +this.well;
1139 cfg.cls += ' hidden';
1143 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1144 cfg.cls +=' alert alert-' + this.alert;
1149 if (this.panel.length) {
1150 cfg.cls += ' panel panel-' + this.panel;
1152 if (this.header.length) {
1156 if(this.expandable){
1158 cfg.cls = cfg.cls + ' expandable';
1162 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1170 cls : 'panel-title',
1171 html : (this.expandable ? ' ' : '') + this.header
1175 cls: 'panel-header-right',
1181 cls : 'panel-heading',
1182 style : this.expandable ? 'cursor: pointer' : '',
1190 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1195 if (this.footer.length) {
1197 cls : 'panel-footer',
1206 body.html = this.html || cfg.html;
1207 // prefix with the icons..
1209 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1212 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1217 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1218 cfg.cls = 'container';
1224 initEvents: function()
1226 if(this.expandable){
1227 var headerEl = this.headerEl();
1230 headerEl.on('click', this.onToggleClick, this);
1235 this.el.on('click', this.onClick, this);
1240 onToggleClick : function()
1242 var headerEl = this.headerEl();
1258 if(this.fireEvent('expand', this)) {
1260 this.expanded = true;
1262 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1264 this.el.select('.panel-body',true).first().removeClass('hide');
1266 var toggleEl = this.toggleEl();
1272 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1277 collapse : function()
1279 if(this.fireEvent('collapse', this)) {
1281 this.expanded = false;
1283 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1284 this.el.select('.panel-body',true).first().addClass('hide');
1286 var toggleEl = this.toggleEl();
1292 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1296 toggleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1302 return this.el.select('.panel-heading .fa',true).first();
1305 headerEl : function()
1307 if(!this.el || !this.panel.length || !this.header.length){
1311 return this.el.select('.panel-heading',true).first()
1316 if(!this.el || !this.panel.length){
1320 return this.el.select('.panel-body',true).first()
1323 titleEl : function()
1325 if(!this.el || !this.panel.length || !this.header.length){
1329 return this.el.select('.panel-title',true).first();
1332 setTitle : function(v)
1334 var titleEl = this.titleEl();
1340 titleEl.dom.innerHTML = v;
1343 getTitle : function()
1346 var titleEl = this.titleEl();
1352 return titleEl.dom.innerHTML;
1355 setRightTitle : function(v)
1357 var t = this.el.select('.panel-header-right',true).first();
1363 t.dom.innerHTML = v;
1366 onClick : function(e)
1370 this.fireEvent('click', this, e);
1384 * @class Roo.bootstrap.Img
1385 * @extends Roo.bootstrap.Component
1386 * Bootstrap Img class
1387 * @cfg {Boolean} imgResponsive false | true
1388 * @cfg {String} border rounded | circle | thumbnail
1389 * @cfg {String} src image source
1390 * @cfg {String} alt image alternative text
1391 * @cfg {String} href a tag href
1392 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1393 * @cfg {String} xsUrl xs image source
1394 * @cfg {String} smUrl sm image source
1395 * @cfg {String} mdUrl md image source
1396 * @cfg {String} lgUrl lg image source
1399 * Create a new Input
1400 * @param {Object} config The config object
1403 Roo.bootstrap.Img = function(config){
1404 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1410 * The img click event for the img.
1411 * @param {Roo.EventObject} e
1417 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1419 imgResponsive: true,
1429 getAutoCreate : function()
1431 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1432 return this.createSingleImg();
1437 cls: 'roo-image-responsive-group',
1442 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1444 if(!_this[size + 'Url']){
1450 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1451 html: _this.html || cfg.html,
1452 src: _this[size + 'Url']
1455 img.cls += ' roo-image-responsive-' + size;
1457 var s = ['xs', 'sm', 'md', 'lg'];
1459 s.splice(s.indexOf(size), 1);
1461 Roo.each(s, function(ss){
1462 img.cls += ' hidden-' + ss;
1465 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1466 cfg.cls += ' img-' + _this.border;
1470 cfg.alt = _this.alt;
1483 a.target = _this.target;
1487 cfg.cn.push((_this.href) ? a : img);
1494 createSingleImg : function()
1498 cls: (this.imgResponsive) ? 'img-responsive' : '',
1500 src : 'about:blank' // just incase src get's set to undefined?!?
1503 cfg.html = this.html || cfg.html;
1505 cfg.src = this.src || cfg.src;
1507 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1508 cfg.cls += ' img-' + this.border;
1525 a.target = this.target;
1530 return (this.href) ? a : cfg;
1533 initEvents: function()
1536 this.el.on('click', this.onClick, this);
1541 onClick : function(e)
1543 Roo.log('img onclick');
1544 this.fireEvent('click', this, e);
1547 * Sets the url of the image - used to update it
1548 * @param {String} url the url of the image
1551 setSrc : function(url)
1555 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1556 this.el.dom.src = url;
1560 this.el.select('img', true).first().dom.src = url;
1576 * @class Roo.bootstrap.Link
1577 * @extends Roo.bootstrap.Component
1578 * Bootstrap Link Class
1579 * @cfg {String} alt image alternative text
1580 * @cfg {String} href a tag href
1581 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1582 * @cfg {String} html the content of the link.
1583 * @cfg {String} anchor name for the anchor link
1584 * @cfg {String} fa - favicon
1586 * @cfg {Boolean} preventDefault (true | false) default false
1590 * Create a new Input
1591 * @param {Object} config The config object
1594 Roo.bootstrap.Link = function(config){
1595 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1601 * The img click event for the img.
1602 * @param {Roo.EventObject} e
1608 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1612 preventDefault: false,
1618 getAutoCreate : function()
1620 var html = this.html || '';
1622 if (this.fa !== false) {
1623 html = '<i class="fa fa-' + this.fa + '"></i>';
1628 // anchor's do not require html/href...
1629 if (this.anchor === false) {
1631 cfg.href = this.href || '#';
1633 cfg.name = this.anchor;
1634 if (this.html !== false || this.fa !== false) {
1637 if (this.href !== false) {
1638 cfg.href = this.href;
1642 if(this.alt !== false){
1647 if(this.target !== false) {
1648 cfg.target = this.target;
1654 initEvents: function() {
1656 if(!this.href || this.preventDefault){
1657 this.el.on('click', this.onClick, this);
1661 onClick : function(e)
1663 if(this.preventDefault){
1666 //Roo.log('img onclick');
1667 this.fireEvent('click', this, e);
1680 * @class Roo.bootstrap.Header
1681 * @extends Roo.bootstrap.Component
1682 * Bootstrap Header class
1683 * @cfg {String} html content of header
1684 * @cfg {Number} level (1|2|3|4|5|6) default 1
1687 * Create a new Header
1688 * @param {Object} config The config object
1692 Roo.bootstrap.Header = function(config){
1693 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1696 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1704 getAutoCreate : function(){
1709 tag: 'h' + (1 *this.level),
1710 html: this.html || ''
1722 * Ext JS Library 1.1.1
1723 * Copyright(c) 2006-2007, Ext JS, LLC.
1725 * Originally Released Under LGPL - original licence link has changed is not relivant.
1728 * <script type="text/javascript">
1732 * @class Roo.bootstrap.MenuMgr
1733 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1736 Roo.bootstrap.MenuMgr = function(){
1737 var menus, active, groups = {}, attached = false, lastShow = new Date();
1739 // private - called when first menu is created
1742 active = new Roo.util.MixedCollection();
1743 Roo.get(document).addKeyListener(27, function(){
1744 if(active.length > 0){
1752 if(active && active.length > 0){
1753 var c = active.clone();
1763 if(active.length < 1){
1764 Roo.get(document).un("mouseup", onMouseDown);
1772 var last = active.last();
1773 lastShow = new Date();
1776 Roo.get(document).on("mouseup", onMouseDown);
1781 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1782 m.parentMenu.activeChild = m;
1783 }else if(last && last.isVisible()){
1784 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1789 function onBeforeHide(m){
1791 m.activeChild.hide();
1793 if(m.autoHideTimer){
1794 clearTimeout(m.autoHideTimer);
1795 delete m.autoHideTimer;
1800 function onBeforeShow(m){
1801 var pm = m.parentMenu;
1802 if(!pm && !m.allowOtherMenus){
1804 }else if(pm && pm.activeChild && active != m){
1805 pm.activeChild.hide();
1809 // private this should really trigger on mouseup..
1810 function onMouseDown(e){
1811 Roo.log("on Mouse Up");
1813 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1814 Roo.log("MenuManager hideAll");
1823 function onBeforeCheck(mi, state){
1825 var g = groups[mi.group];
1826 for(var i = 0, l = g.length; i < l; i++){
1828 g[i].setChecked(false);
1837 * Hides all menus that are currently visible
1839 hideAll : function(){
1844 register : function(menu){
1848 menus[menu.id] = menu;
1849 menu.on("beforehide", onBeforeHide);
1850 menu.on("hide", onHide);
1851 menu.on("beforeshow", onBeforeShow);
1852 menu.on("show", onShow);
1854 if(g && menu.events["checkchange"]){
1858 groups[g].push(menu);
1859 menu.on("checkchange", onCheck);
1864 * Returns a {@link Roo.menu.Menu} object
1865 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1866 * be used to generate and return a new Menu instance.
1868 get : function(menu){
1869 if(typeof menu == "string"){ // menu id
1871 }else if(menu.events){ // menu instance
1874 /*else if(typeof menu.length == 'number'){ // array of menu items?
1875 return new Roo.bootstrap.Menu({items:menu});
1876 }else{ // otherwise, must be a config
1877 return new Roo.bootstrap.Menu(menu);
1884 unregister : function(menu){
1885 delete menus[menu.id];
1886 menu.un("beforehide", onBeforeHide);
1887 menu.un("hide", onHide);
1888 menu.un("beforeshow", onBeforeShow);
1889 menu.un("show", onShow);
1891 if(g && menu.events["checkchange"]){
1892 groups[g].remove(menu);
1893 menu.un("checkchange", onCheck);
1898 registerCheckable : function(menuItem){
1899 var g = menuItem.group;
1904 groups[g].push(menuItem);
1905 menuItem.on("beforecheckchange", onBeforeCheck);
1910 unregisterCheckable : function(menuItem){
1911 var g = menuItem.group;
1913 groups[g].remove(menuItem);
1914 menuItem.un("beforecheckchange", onBeforeCheck);
1926 * @class Roo.bootstrap.Menu
1927 * @extends Roo.bootstrap.Component
1928 * Bootstrap Menu class - container for MenuItems
1929 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1930 * @cfg {bool} hidden if the menu should be hidden when rendered.
1931 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1932 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1936 * @param {Object} config The config object
1940 Roo.bootstrap.Menu = function(config){
1941 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1942 if (this.registerMenu && this.type != 'treeview') {
1943 Roo.bootstrap.MenuMgr.register(this);
1948 * Fires before this menu is displayed
1949 * @param {Roo.menu.Menu} this
1954 * Fires before this menu is hidden
1955 * @param {Roo.menu.Menu} this
1960 * Fires after this menu is displayed
1961 * @param {Roo.menu.Menu} this
1966 * Fires after this menu is hidden
1967 * @param {Roo.menu.Menu} this
1972 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1973 * @param {Roo.menu.Menu} this
1974 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1975 * @param {Roo.EventObject} e
1980 * Fires when the mouse is hovering over this menu
1981 * @param {Roo.menu.Menu} this
1982 * @param {Roo.EventObject} e
1983 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1988 * Fires when the mouse exits this menu
1989 * @param {Roo.menu.Menu} this
1990 * @param {Roo.EventObject} e
1991 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1996 * Fires when a menu item contained in this menu is clicked
1997 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1998 * @param {Roo.EventObject} e
2002 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2005 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2009 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2012 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2014 registerMenu : true,
2016 menuItems :false, // stores the menu items..
2026 getChildContainer : function() {
2030 getAutoCreate : function(){
2032 //if (['right'].indexOf(this.align)!==-1) {
2033 // cfg.cn[1].cls += ' pull-right'
2039 cls : 'dropdown-menu' ,
2040 style : 'z-index:1000'
2044 if (this.type === 'submenu') {
2045 cfg.cls = 'submenu active';
2047 if (this.type === 'treeview') {
2048 cfg.cls = 'treeview-menu';
2053 initEvents : function() {
2055 // Roo.log("ADD event");
2056 // Roo.log(this.triggerEl.dom);
2058 this.triggerEl.on('click', this.onTriggerClick, this);
2060 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2062 this.triggerEl.addClass('dropdown-toggle');
2065 this.el.on('touchstart' , this.onTouch, this);
2067 this.el.on('click' , this.onClick, this);
2069 this.el.on("mouseover", this.onMouseOver, this);
2070 this.el.on("mouseout", this.onMouseOut, this);
2074 findTargetItem : function(e)
2076 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2080 //Roo.log(t); Roo.log(t.id);
2082 //Roo.log(this.menuitems);
2083 return this.menuitems.get(t.id);
2085 //return this.items.get(t.menuItemId);
2091 onTouch : function(e)
2093 Roo.log("menu.onTouch");
2094 //e.stopEvent(); this make the user popdown broken
2098 onClick : function(e)
2100 Roo.log("menu.onClick");
2102 var t = this.findTargetItem(e);
2103 if(!t || t.isContainer){
2108 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2109 if(t == this.activeItem && t.shouldDeactivate(e)){
2110 this.activeItem.deactivate();
2111 delete this.activeItem;
2115 this.setActiveItem(t, true);
2123 Roo.log('pass click event');
2127 this.fireEvent("click", this, t, e);
2131 if(!t.href.length || t.href == '#'){
2132 (function() { _this.hide(); }).defer(100);
2137 onMouseOver : function(e){
2138 var t = this.findTargetItem(e);
2141 // if(t.canActivate && !t.disabled){
2142 // this.setActiveItem(t, true);
2146 this.fireEvent("mouseover", this, e, t);
2148 isVisible : function(){
2149 return !this.hidden;
2151 onMouseOut : function(e){
2152 var t = this.findTargetItem(e);
2155 // if(t == this.activeItem && t.shouldDeactivate(e)){
2156 // this.activeItem.deactivate();
2157 // delete this.activeItem;
2160 this.fireEvent("mouseout", this, e, t);
2165 * Displays this menu relative to another element
2166 * @param {String/HTMLElement/Roo.Element} element The element to align to
2167 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2168 * the element (defaults to this.defaultAlign)
2169 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2171 show : function(el, pos, parentMenu){
2172 this.parentMenu = parentMenu;
2176 this.fireEvent("beforeshow", this);
2177 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2180 * Displays this menu at a specific xy position
2181 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2182 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2184 showAt : function(xy, parentMenu, /* private: */_e){
2185 this.parentMenu = parentMenu;
2190 this.fireEvent("beforeshow", this);
2191 //xy = this.el.adjustForConstraints(xy);
2195 this.hideMenuItems();
2196 this.hidden = false;
2197 this.triggerEl.addClass('open');
2199 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2200 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2203 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2208 this.fireEvent("show", this);
2214 this.doFocus.defer(50, this);
2218 doFocus : function(){
2220 this.focusEl.focus();
2225 * Hides this menu and optionally all parent menus
2226 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2228 hide : function(deep)
2231 this.hideMenuItems();
2232 if(this.el && this.isVisible()){
2233 this.fireEvent("beforehide", this);
2234 if(this.activeItem){
2235 this.activeItem.deactivate();
2236 this.activeItem = null;
2238 this.triggerEl.removeClass('open');;
2240 this.fireEvent("hide", this);
2242 if(deep === true && this.parentMenu){
2243 this.parentMenu.hide(true);
2247 onTriggerClick : function(e)
2249 Roo.log('trigger click');
2251 var target = e.getTarget();
2253 Roo.log(target.nodeName.toLowerCase());
2255 if(target.nodeName.toLowerCase() === 'i'){
2261 onTriggerPress : function(e)
2263 Roo.log('trigger press');
2264 //Roo.log(e.getTarget());
2265 // Roo.log(this.triggerEl.dom);
2267 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2268 var pel = Roo.get(e.getTarget());
2269 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2270 Roo.log('is treeview or dropdown?');
2274 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2278 if (this.isVisible()) {
2283 this.show(this.triggerEl, false, false);
2286 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2293 hideMenuItems : function()
2295 Roo.log("hide Menu Items");
2299 //$(backdrop).remove()
2300 this.el.select('.open',true).each(function(aa) {
2302 aa.removeClass('open');
2303 //var parent = getParent($(this))
2304 //var relatedTarget = { relatedTarget: this }
2306 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2307 //if (e.isDefaultPrevented()) return
2308 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2311 addxtypeChild : function (tree, cntr) {
2312 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2314 this.menuitems.add(comp);
2335 * @class Roo.bootstrap.MenuItem
2336 * @extends Roo.bootstrap.Component
2337 * Bootstrap MenuItem class
2338 * @cfg {String} html the menu label
2339 * @cfg {String} href the link
2340 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2341 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2342 * @cfg {Boolean} active used on sidebars to highlight active itesm
2343 * @cfg {String} fa favicon to show on left of menu item.
2344 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2348 * Create a new MenuItem
2349 * @param {Object} config The config object
2353 Roo.bootstrap.MenuItem = function(config){
2354 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2359 * The raw click event for the entire grid.
2360 * @param {Roo.bootstrap.MenuItem} this
2361 * @param {Roo.EventObject} e
2367 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2371 preventDefault: false,
2372 isContainer : false,
2376 getAutoCreate : function(){
2378 if(this.isContainer){
2381 cls: 'dropdown-menu-item'
2395 if (this.fa !== false) {
2398 cls : 'fa fa-' + this.fa
2407 cls: 'dropdown-menu-item',
2410 if (this.parent().type == 'treeview') {
2411 cfg.cls = 'treeview-menu';
2414 cfg.cls += ' active';
2419 anc.href = this.href || cfg.cn[0].href ;
2420 ctag.html = this.html || cfg.cn[0].html ;
2424 initEvents: function()
2426 if (this.parent().type == 'treeview') {
2427 this.el.select('a').on('click', this.onClick, this);
2431 this.menu.parentType = this.xtype;
2432 this.menu.triggerEl = this.el;
2433 this.menu = this.addxtype(Roo.apply({}, this.menu));
2437 onClick : function(e)
2439 Roo.log('item on click ');
2441 if(this.preventDefault){
2444 //this.parent().hideMenuItems();
2446 this.fireEvent('click', this, e);
2465 * @class Roo.bootstrap.MenuSeparator
2466 * @extends Roo.bootstrap.Component
2467 * Bootstrap MenuSeparator class
2470 * Create a new MenuItem
2471 * @param {Object} config The config object
2475 Roo.bootstrap.MenuSeparator = function(config){
2476 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2479 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2481 getAutoCreate : function(){
2500 * @class Roo.bootstrap.Modal
2501 * @extends Roo.bootstrap.Component
2502 * Bootstrap Modal class
2503 * @cfg {String} title Title of dialog
2504 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2505 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2506 * @cfg {Boolean} specificTitle default false
2507 * @cfg {Array} buttons Array of buttons or standard button set..
2508 * @cfg {String} buttonPosition (left|right|center) default right
2509 * @cfg {Boolean} animate default true
2510 * @cfg {Boolean} allow_close default true
2511 * @cfg {Boolean} fitwindow default false
2512 * @cfg {String} size (sm|lg) default empty
2516 * Create a new Modal Dialog
2517 * @param {Object} config The config object
2520 Roo.bootstrap.Modal = function(config){
2521 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2526 * The raw btnclick event for the button
2527 * @param {Roo.EventObject} e
2532 * Fire when dialog resize
2533 * @param {Roo.bootstrap.Modal} this
2534 * @param {Roo.EventObject} e
2538 this.buttons = this.buttons || [];
2541 this.tmpl = Roo.factory(this.tmpl);
2546 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2548 title : 'test dialog',
2558 specificTitle: false,
2560 buttonPosition: 'right',
2579 onRender : function(ct, position)
2581 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2584 var cfg = Roo.apply({}, this.getAutoCreate());
2587 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2589 //if (!cfg.name.length) {
2593 cfg.cls += ' ' + this.cls;
2596 cfg.style = this.style;
2598 this.el = Roo.get(document.body).createChild(cfg, position);
2600 //var type = this.el.dom.type;
2603 if(this.tabIndex !== undefined){
2604 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2607 this.dialogEl = this.el.select('.modal-dialog',true).first();
2608 this.bodyEl = this.el.select('.modal-body',true).first();
2609 this.closeEl = this.el.select('.modal-header .close', true).first();
2610 this.headerEl = this.el.select('.modal-header',true).first();
2611 this.titleEl = this.el.select('.modal-title',true).first();
2612 this.footerEl = this.el.select('.modal-footer',true).first();
2614 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2615 this.maskEl.enableDisplayMode("block");
2617 //this.el.addClass("x-dlg-modal");
2619 if (this.buttons.length) {
2620 Roo.each(this.buttons, function(bb) {
2621 var b = Roo.apply({}, bb);
2622 b.xns = b.xns || Roo.bootstrap;
2623 b.xtype = b.xtype || 'Button';
2624 if (typeof(b.listeners) == 'undefined') {
2625 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2628 var btn = Roo.factory(b);
2630 btn.render(this.el.select('.modal-footer div').first());
2634 // render the children.
2637 if(typeof(this.items) != 'undefined'){
2638 var items = this.items;
2641 for(var i =0;i < items.length;i++) {
2642 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2646 this.items = nitems;
2648 // where are these used - they used to be body/close/footer
2652 //this.el.addClass([this.fieldClass, this.cls]);
2656 getAutoCreate : function(){
2661 html : this.html || ''
2666 cls : 'modal-title',
2670 if(this.specificTitle){
2676 if (this.allow_close) {
2688 if(this.size.length){
2689 size = 'modal-' + this.size;
2694 style : 'display: none',
2697 cls: "modal-dialog " + size,
2700 cls : "modal-content",
2703 cls : 'modal-header',
2708 cls : 'modal-footer',
2712 cls: 'btn-' + this.buttonPosition
2729 modal.cls += ' fade';
2735 getChildContainer : function() {
2740 getButtonContainer : function() {
2741 return this.el.select('.modal-footer div',true).first();
2744 initEvents : function()
2746 if (this.allow_close) {
2747 this.closeEl.on('click', this.hide, this);
2749 Roo.EventManager.onWindowResize(this.resize, this, true);
2756 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2757 if (this.fitwindow) {
2758 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2759 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2764 setSize : function(w,h)
2774 if (!this.rendered) {
2778 this.el.setStyle('display', 'block');
2780 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2783 this.el.addClass('in');
2786 this.el.addClass('in');
2790 // not sure how we can show data in here..
2792 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2795 Roo.get(document.body).addClass("x-body-masked");
2797 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2798 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2803 this.fireEvent('show', this);
2805 // set zindex here - otherwise it appears to be ignored...
2806 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2809 this.items.forEach( function(e) {
2810 e.layout ? e.layout() : false;
2818 if(this.fireEvent("beforehide", this) !== false){
2820 Roo.get(document.body).removeClass("x-body-masked");
2821 this.el.removeClass('in');
2822 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2824 if(this.animate){ // why
2826 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2828 this.el.setStyle('display', 'none');
2830 this.fireEvent('hide', this);
2834 addButton : function(str, cb)
2838 var b = Roo.apply({}, { html : str } );
2839 b.xns = b.xns || Roo.bootstrap;
2840 b.xtype = b.xtype || 'Button';
2841 if (typeof(b.listeners) == 'undefined') {
2842 b.listeners = { click : cb.createDelegate(this) };
2845 var btn = Roo.factory(b);
2847 btn.render(this.el.select('.modal-footer div').first());
2853 setDefaultButton : function(btn)
2855 //this.el.select('.modal-footer').()
2859 resizeTo: function(w,h)
2863 this.dialogEl.setWidth(w);
2864 if (this.diff === false) {
2865 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2868 this.bodyEl.setHeight(h-this.diff);
2870 this.fireEvent('resize', this);
2873 setContentSize : function(w, h)
2877 onButtonClick: function(btn,e)
2880 this.fireEvent('btnclick', btn.name, e);
2883 * Set the title of the Dialog
2884 * @param {String} str new Title
2886 setTitle: function(str) {
2887 this.titleEl.dom.innerHTML = str;
2890 * Set the body of the Dialog
2891 * @param {String} str new Title
2893 setBody: function(str) {
2894 this.bodyEl.dom.innerHTML = str;
2897 * Set the body of the Dialog using the template
2898 * @param {Obj} data - apply this data to the template and replace the body contents.
2900 applyBody: function(obj)
2903 Roo.log("Error - using apply Body without a template");
2906 this.tmpl.overwrite(this.bodyEl, obj);
2912 Roo.apply(Roo.bootstrap.Modal, {
2914 * Button config that displays a single OK button
2923 * Button config that displays Yes and No buttons
2939 * Button config that displays OK and Cancel buttons
2954 * Button config that displays Yes, No and Cancel buttons
2978 * messagebox - can be used as a replace
2982 * @class Roo.MessageBox
2983 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2987 Roo.Msg.alert('Status', 'Changes saved successfully.');
2989 // Prompt for user data:
2990 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2992 // process text value...
2996 // Show a dialog using config options:
2998 title:'Save Changes?',
2999 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3000 buttons: Roo.Msg.YESNOCANCEL,
3007 Roo.bootstrap.MessageBox = function(){
3008 var dlg, opt, mask, waitTimer;
3009 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3010 var buttons, activeTextEl, bwidth;
3014 var handleButton = function(button){
3016 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3020 var handleHide = function(){
3022 dlg.el.removeClass(opt.cls);
3025 // Roo.TaskMgr.stop(waitTimer);
3026 // waitTimer = null;
3031 var updateButtons = function(b){
3034 buttons["ok"].hide();
3035 buttons["cancel"].hide();
3036 buttons["yes"].hide();
3037 buttons["no"].hide();
3038 //dlg.footer.dom.style.display = 'none';
3041 dlg.footerEl.dom.style.display = '';
3042 for(var k in buttons){
3043 if(typeof buttons[k] != "function"){
3046 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3047 width += buttons[k].el.getWidth()+15;
3057 var handleEsc = function(d, k, e){
3058 if(opt && opt.closable !== false){
3068 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3069 * @return {Roo.BasicDialog} The BasicDialog element
3071 getDialog : function(){
3073 dlg = new Roo.bootstrap.Modal( {
3076 //constraintoviewport:false,
3078 //collapsible : false,
3083 //buttonAlign:"center",
3084 closeClick : function(){
3085 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3088 handleButton("cancel");
3093 dlg.on("hide", handleHide);
3095 //dlg.addKeyListener(27, handleEsc);
3097 this.buttons = buttons;
3098 var bt = this.buttonText;
3099 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3100 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3101 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3102 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3104 bodyEl = dlg.bodyEl.createChild({
3106 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3107 '<textarea class="roo-mb-textarea"></textarea>' +
3108 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3110 msgEl = bodyEl.dom.firstChild;
3111 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3112 textboxEl.enableDisplayMode();
3113 textboxEl.addKeyListener([10,13], function(){
3114 if(dlg.isVisible() && opt && opt.buttons){
3117 }else if(opt.buttons.yes){
3118 handleButton("yes");
3122 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3123 textareaEl.enableDisplayMode();
3124 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3125 progressEl.enableDisplayMode();
3127 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3128 var pf = progressEl.dom.firstChild;
3130 pp = Roo.get(pf.firstChild);
3131 pp.setHeight(pf.offsetHeight);
3139 * Updates the message box body text
3140 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3141 * the XHTML-compliant non-breaking space character '&#160;')
3142 * @return {Roo.MessageBox} This message box
3144 updateText : function(text)
3146 if(!dlg.isVisible() && !opt.width){
3147 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3148 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3150 msgEl.innerHTML = text || ' ';
3152 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3153 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3155 Math.min(opt.width || cw , this.maxWidth),
3156 Math.max(opt.minWidth || this.minWidth, bwidth)
3159 activeTextEl.setWidth(w);
3161 if(dlg.isVisible()){
3162 dlg.fixedcenter = false;
3164 // to big, make it scroll. = But as usual stupid IE does not support
3167 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3168 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3169 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3171 bodyEl.dom.style.height = '';
3172 bodyEl.dom.style.overflowY = '';
3175 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3177 bodyEl.dom.style.overflowX = '';
3180 dlg.setContentSize(w, bodyEl.getHeight());
3181 if(dlg.isVisible()){
3182 dlg.fixedcenter = true;
3188 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3189 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3190 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3191 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3192 * @return {Roo.MessageBox} This message box
3194 updateProgress : function(value, text){
3196 this.updateText(text);
3199 if (pp) { // weird bug on my firefox - for some reason this is not defined
3200 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3201 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3207 * Returns true if the message box is currently displayed
3208 * @return {Boolean} True if the message box is visible, else false
3210 isVisible : function(){
3211 return dlg && dlg.isVisible();
3215 * Hides the message box if it is displayed
3218 if(this.isVisible()){
3224 * Displays a new message box, or reinitializes an existing message box, based on the config options
3225 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3226 * The following config object properties are supported:
3228 Property Type Description
3229 ---------- --------------- ------------------------------------------------------------------------------------
3230 animEl String/Element An id or Element from which the message box should animate as it opens and
3231 closes (defaults to undefined)
3232 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3233 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3234 closable Boolean False to hide the top-right close button (defaults to true). Note that
3235 progress and wait dialogs will ignore this property and always hide the
3236 close button as they can only be closed programmatically.
3237 cls String A custom CSS class to apply to the message box element
3238 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3239 displayed (defaults to 75)
3240 fn Function A callback function to execute after closing the dialog. The arguments to the
3241 function will be btn (the name of the button that was clicked, if applicable,
3242 e.g. "ok"), and text (the value of the active text field, if applicable).
3243 Progress and wait dialogs will ignore this option since they do not respond to
3244 user actions and can only be closed programmatically, so any required function
3245 should be called by the same code after it closes the dialog.
3246 icon String A CSS class that provides a background image to be used as an icon for
3247 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3248 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3249 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3250 modal Boolean False to allow user interaction with the page while the message box is
3251 displayed (defaults to true)
3252 msg String A string that will replace the existing message box body text (defaults
3253 to the XHTML-compliant non-breaking space character ' ')
3254 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3255 progress Boolean True to display a progress bar (defaults to false)
3256 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3257 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3258 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3259 title String The title text
3260 value String The string value to set into the active textbox element if displayed
3261 wait Boolean True to display a progress bar (defaults to false)
3262 width Number The width of the dialog in pixels
3269 msg: 'Please enter your address:',
3271 buttons: Roo.MessageBox.OKCANCEL,
3274 animEl: 'addAddressBtn'
3277 * @param {Object} config Configuration options
3278 * @return {Roo.MessageBox} This message box
3280 show : function(options)
3283 // this causes nightmares if you show one dialog after another
3284 // especially on callbacks..
3286 if(this.isVisible()){
3289 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3290 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3291 Roo.log("New Dialog Message:" + options.msg )
3292 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3293 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3296 var d = this.getDialog();
3298 d.setTitle(opt.title || " ");
3299 d.closeEl.setDisplayed(opt.closable !== false);
3300 activeTextEl = textboxEl;
3301 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3306 textareaEl.setHeight(typeof opt.multiline == "number" ?
3307 opt.multiline : this.defaultTextHeight);
3308 activeTextEl = textareaEl;
3317 progressEl.setDisplayed(opt.progress === true);
3318 this.updateProgress(0);
3319 activeTextEl.dom.value = opt.value || "";
3321 dlg.setDefaultButton(activeTextEl);
3323 var bs = opt.buttons;
3327 }else if(bs && bs.yes){
3328 db = buttons["yes"];
3330 dlg.setDefaultButton(db);
3332 bwidth = updateButtons(opt.buttons);
3333 this.updateText(opt.msg);
3335 d.el.addClass(opt.cls);
3337 d.proxyDrag = opt.proxyDrag === true;
3338 d.modal = opt.modal !== false;
3339 d.mask = opt.modal !== false ? mask : false;
3341 // force it to the end of the z-index stack so it gets a cursor in FF
3342 document.body.appendChild(dlg.el.dom);
3343 d.animateTarget = null;
3344 d.show(options.animEl);
3350 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3351 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3352 * and closing the message box when the process is complete.
3353 * @param {String} title The title bar text
3354 * @param {String} msg The message box body text
3355 * @return {Roo.MessageBox} This message box
3357 progress : function(title, msg){
3364 minWidth: this.minProgressWidth,
3371 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3372 * If a callback function is passed it will be called after the user clicks the button, and the
3373 * id of the button that was clicked will be passed as the only parameter to the callback
3374 * (could also be the top-right close button).
3375 * @param {String} title The title bar text
3376 * @param {String} msg The message box body text
3377 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3378 * @param {Object} scope (optional) The scope of the callback function
3379 * @return {Roo.MessageBox} This message box
3381 alert : function(title, msg, fn, scope)
3396 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3397 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3398 * You are responsible for closing the message box when the process is complete.
3399 * @param {String} msg The message box body text
3400 * @param {String} title (optional) The title bar text
3401 * @return {Roo.MessageBox} This message box
3403 wait : function(msg, title){
3414 waitTimer = Roo.TaskMgr.start({
3416 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3424 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3425 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3426 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3427 * @param {String} title The title bar text
3428 * @param {String} msg The message box body text
3429 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3430 * @param {Object} scope (optional) The scope of the callback function
3431 * @return {Roo.MessageBox} This message box
3433 confirm : function(title, msg, fn, scope){
3437 buttons: this.YESNO,
3446 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3447 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3448 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3449 * (could also be the top-right close button) and the text that was entered will be passed as the two
3450 * parameters to the callback.
3451 * @param {String} title The title bar text
3452 * @param {String} msg The message box body text
3453 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3454 * @param {Object} scope (optional) The scope of the callback function
3455 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3456 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3457 * @return {Roo.MessageBox} This message box
3459 prompt : function(title, msg, fn, scope, multiline){
3463 buttons: this.OKCANCEL,
3468 multiline: multiline,
3475 * Button config that displays a single OK button
3480 * Button config that displays Yes and No buttons
3483 YESNO : {yes:true, no:true},
3485 * Button config that displays OK and Cancel buttons
3488 OKCANCEL : {ok:true, cancel:true},
3490 * Button config that displays Yes, No and Cancel buttons
3493 YESNOCANCEL : {yes:true, no:true, cancel:true},
3496 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3499 defaultTextHeight : 75,
3501 * The maximum width in pixels of the message box (defaults to 600)
3506 * The minimum width in pixels of the message box (defaults to 100)
3511 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3512 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3515 minProgressWidth : 250,
3517 * An object containing the default button text strings that can be overriden for localized language support.
3518 * Supported properties are: ok, cancel, yes and no.
3519 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3532 * Shorthand for {@link Roo.MessageBox}
3534 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3535 Roo.Msg = Roo.Msg || Roo.MessageBox;
3544 * @class Roo.bootstrap.Navbar
3545 * @extends Roo.bootstrap.Component
3546 * Bootstrap Navbar class
3549 * Create a new Navbar
3550 * @param {Object} config The config object
3554 Roo.bootstrap.Navbar = function(config){
3555 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3559 * @event beforetoggle
3560 * Fire before toggle the menu
3561 * @param {Roo.EventObject} e
3563 "beforetoggle" : true
3567 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3576 getAutoCreate : function(){
3579 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3583 initEvents :function ()
3585 //Roo.log(this.el.select('.navbar-toggle',true));
3586 this.el.select('.navbar-toggle',true).on('click', function() {
3587 if(this.fireEvent('beforetoggle', this) !== false){
3588 this.el.select('.navbar-collapse',true).toggleClass('in');
3598 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3600 var size = this.el.getSize();
3601 this.maskEl.setSize(size.width, size.height);
3602 this.maskEl.enableDisplayMode("block");
3611 getChildContainer : function()
3613 if (this.el.select('.collapse').getCount()) {
3614 return this.el.select('.collapse',true).first();
3647 * @class Roo.bootstrap.NavSimplebar
3648 * @extends Roo.bootstrap.Navbar
3649 * Bootstrap Sidebar class
3651 * @cfg {Boolean} inverse is inverted color
3653 * @cfg {String} type (nav | pills | tabs)
3654 * @cfg {Boolean} arrangement stacked | justified
3655 * @cfg {String} align (left | right) alignment
3657 * @cfg {Boolean} main (true|false) main nav bar? default false
3658 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3660 * @cfg {String} tag (header|footer|nav|div) default is nav
3666 * Create a new Sidebar
3667 * @param {Object} config The config object
3671 Roo.bootstrap.NavSimplebar = function(config){
3672 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3675 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3691 getAutoCreate : function(){
3695 tag : this.tag || 'div',
3708 this.type = this.type || 'nav';
3709 if (['tabs','pills'].indexOf(this.type)!==-1) {
3710 cfg.cn[0].cls += ' nav-' + this.type
3714 if (this.type!=='nav') {
3715 Roo.log('nav type must be nav/tabs/pills')
3717 cfg.cn[0].cls += ' navbar-nav'
3723 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3724 cfg.cn[0].cls += ' nav-' + this.arrangement;
3728 if (this.align === 'right') {
3729 cfg.cn[0].cls += ' navbar-right';
3733 cfg.cls += ' navbar-inverse';
3760 * @class Roo.bootstrap.NavHeaderbar
3761 * @extends Roo.bootstrap.NavSimplebar
3762 * Bootstrap Sidebar class
3764 * @cfg {String} brand what is brand
3765 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3766 * @cfg {String} brand_href href of the brand
3767 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3768 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3769 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3770 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3773 * Create a new Sidebar
3774 * @param {Object} config The config object
3778 Roo.bootstrap.NavHeaderbar = function(config){
3779 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3783 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3790 desktopCenter : false,
3793 getAutoCreate : function(){
3796 tag: this.nav || 'nav',
3803 if (this.desktopCenter) {
3804 cn.push({cls : 'container', cn : []});
3811 cls: 'navbar-header',
3816 cls: 'navbar-toggle',
3817 'data-toggle': 'collapse',
3822 html: 'Toggle navigation'
3844 cls: 'collapse navbar-collapse',
3848 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3850 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3851 cfg.cls += ' navbar-' + this.position;
3853 // tag can override this..
3855 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3858 if (this.brand !== '') {
3861 href: this.brand_href ? this.brand_href : '#',
3862 cls: 'navbar-brand',
3870 cfg.cls += ' main-nav';
3878 getHeaderChildContainer : function()
3880 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3881 return this.el.select('.navbar-header',true).first();
3884 return this.getChildContainer();
3888 initEvents : function()
3890 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3892 if (this.autohide) {
3897 Roo.get(document).on('scroll',function(e) {
3898 var ns = Roo.get(document).getScroll().top;
3899 var os = prevScroll;
3903 ft.removeClass('slideDown');
3904 ft.addClass('slideUp');
3907 ft.removeClass('slideUp');
3908 ft.addClass('slideDown');
3929 * @class Roo.bootstrap.NavSidebar
3930 * @extends Roo.bootstrap.Navbar
3931 * Bootstrap Sidebar class
3934 * Create a new Sidebar
3935 * @param {Object} config The config object
3939 Roo.bootstrap.NavSidebar = function(config){
3940 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3943 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3945 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3947 getAutoCreate : function(){
3952 cls: 'sidebar sidebar-nav'
3974 * @class Roo.bootstrap.NavGroup
3975 * @extends Roo.bootstrap.Component
3976 * Bootstrap NavGroup class
3977 * @cfg {String} align (left|right)
3978 * @cfg {Boolean} inverse
3979 * @cfg {String} type (nav|pills|tab) default nav
3980 * @cfg {String} navId - reference Id for navbar.
3984 * Create a new nav group
3985 * @param {Object} config The config object
3988 Roo.bootstrap.NavGroup = function(config){
3989 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3992 Roo.bootstrap.NavGroup.register(this);
3996 * Fires when the active item changes
3997 * @param {Roo.bootstrap.NavGroup} this
3998 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3999 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4006 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4017 getAutoCreate : function()
4019 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4026 if (['tabs','pills'].indexOf(this.type)!==-1) {
4027 cfg.cls += ' nav-' + this.type
4029 if (this.type!=='nav') {
4030 Roo.log('nav type must be nav/tabs/pills')
4032 cfg.cls += ' navbar-nav'
4035 if (this.parent() && this.parent().sidebar) {
4038 cls: 'dashboard-menu sidebar-menu'
4044 if (this.form === true) {
4050 if (this.align === 'right') {
4051 cfg.cls += ' navbar-right';
4053 cfg.cls += ' navbar-left';
4057 if (this.align === 'right') {
4058 cfg.cls += ' navbar-right';
4062 cfg.cls += ' navbar-inverse';
4070 * sets the active Navigation item
4071 * @param {Roo.bootstrap.NavItem} the new current navitem
4073 setActiveItem : function(item)
4076 Roo.each(this.navItems, function(v){
4081 v.setActive(false, true);
4088 item.setActive(true, true);
4089 this.fireEvent('changed', this, item, prev);
4094 * gets the active Navigation item
4095 * @return {Roo.bootstrap.NavItem} the current navitem
4097 getActive : function()
4101 Roo.each(this.navItems, function(v){
4112 indexOfNav : function()
4116 Roo.each(this.navItems, function(v,i){
4127 * adds a Navigation item
4128 * @param {Roo.bootstrap.NavItem} the navitem to add
4130 addItem : function(cfg)
4132 var cn = new Roo.bootstrap.NavItem(cfg);
4134 cn.parentId = this.id;
4135 cn.onRender(this.el, null);
4139 * register a Navigation item
4140 * @param {Roo.bootstrap.NavItem} the navitem to add
4142 register : function(item)
4144 this.navItems.push( item);
4145 item.navId = this.navId;
4150 * clear all the Navigation item
4153 clearAll : function()
4156 this.el.dom.innerHTML = '';
4159 getNavItem: function(tabId)
4162 Roo.each(this.navItems, function(e) {
4163 if (e.tabId == tabId) {
4173 setActiveNext : function()
4175 var i = this.indexOfNav(this.getActive());
4176 if (i > this.navItems.length) {
4179 this.setActiveItem(this.navItems[i+1]);
4181 setActivePrev : function()
4183 var i = this.indexOfNav(this.getActive());
4187 this.setActiveItem(this.navItems[i-1]);
4189 clearWasActive : function(except) {
4190 Roo.each(this.navItems, function(e) {
4191 if (e.tabId != except.tabId && e.was_active) {
4192 e.was_active = false;
4199 getWasActive : function ()
4202 Roo.each(this.navItems, function(e) {
4217 Roo.apply(Roo.bootstrap.NavGroup, {
4221 * register a Navigation Group
4222 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4224 register : function(navgrp)
4226 this.groups[navgrp.navId] = navgrp;
4230 * fetch a Navigation Group based on the navigation ID
4231 * @param {string} the navgroup to add
4232 * @returns {Roo.bootstrap.NavGroup} the navgroup
4234 get: function(navId) {
4235 if (typeof(this.groups[navId]) == 'undefined') {
4237 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4239 return this.groups[navId] ;
4254 * @class Roo.bootstrap.NavItem
4255 * @extends Roo.bootstrap.Component
4256 * Bootstrap Navbar.NavItem class
4257 * @cfg {String} href link to
4258 * @cfg {String} html content of button
4259 * @cfg {String} badge text inside badge
4260 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4261 * @cfg {String} glyphicon name of glyphicon
4262 * @cfg {String} icon name of font awesome icon
4263 * @cfg {Boolean} active Is item active
4264 * @cfg {Boolean} disabled Is item disabled
4266 * @cfg {Boolean} preventDefault (true | false) default false
4267 * @cfg {String} tabId the tab that this item activates.
4268 * @cfg {String} tagtype (a|span) render as a href or span?
4269 * @cfg {Boolean} animateRef (true|false) link to element default false
4272 * Create a new Navbar Item
4273 * @param {Object} config The config object
4275 Roo.bootstrap.NavItem = function(config){
4276 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4281 * The raw click event for the entire grid.
4282 * @param {Roo.EventObject} e
4287 * Fires when the active item active state changes
4288 * @param {Roo.bootstrap.NavItem} this
4289 * @param {boolean} state the new state
4295 * Fires when scroll to element
4296 * @param {Roo.bootstrap.NavItem} this
4297 * @param {Object} options
4298 * @param {Roo.EventObject} e
4306 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4314 preventDefault : false,
4321 getAutoCreate : function(){
4330 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4332 if (this.disabled) {
4333 cfg.cls += ' disabled';
4336 if (this.href || this.html || this.glyphicon || this.icon) {
4340 href : this.href || "#",
4341 html: this.html || ''
4346 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4349 if(this.glyphicon) {
4350 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4355 cfg.cn[0].html += " <span class='caret'></span>";
4359 if (this.badge !== '') {
4361 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4369 initEvents: function()
4371 if (typeof (this.menu) != 'undefined') {
4372 this.menu.parentType = this.xtype;
4373 this.menu.triggerEl = this.el;
4374 this.menu = this.addxtype(Roo.apply({}, this.menu));
4377 this.el.select('a',true).on('click', this.onClick, this);
4379 if(this.tagtype == 'span'){
4380 this.el.select('span',true).on('click', this.onClick, this);
4383 // at this point parent should be available..
4384 this.parent().register(this);
4387 onClick : function(e)
4389 if (e.getTarget('.dropdown-menu-item')) {
4390 // did you click on a menu itemm.... - then don't trigger onclick..
4395 this.preventDefault ||
4398 Roo.log("NavItem - prevent Default?");
4402 if (this.disabled) {
4406 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4407 if (tg && tg.transition) {
4408 Roo.log("waiting for the transitionend");
4414 //Roo.log("fire event clicked");
4415 if(this.fireEvent('click', this, e) === false){
4419 if(this.tagtype == 'span'){
4423 //Roo.log(this.href);
4424 var ael = this.el.select('a',true).first();
4427 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4428 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4429 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4430 return; // ignore... - it's a 'hash' to another page.
4432 Roo.log("NavItem - prevent Default?");
4434 this.scrollToElement(e);
4438 var p = this.parent();
4440 if (['tabs','pills'].indexOf(p.type)!==-1) {
4441 if (typeof(p.setActiveItem) !== 'undefined') {
4442 p.setActiveItem(this);
4446 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4447 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4448 // remove the collapsed menu expand...
4449 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4453 isActive: function () {
4456 setActive : function(state, fire, is_was_active)
4458 if (this.active && !state && this.navId) {
4459 this.was_active = true;
4460 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4462 nv.clearWasActive(this);
4466 this.active = state;
4469 this.el.removeClass('active');
4470 } else if (!this.el.hasClass('active')) {
4471 this.el.addClass('active');
4474 this.fireEvent('changed', this, state);
4477 // show a panel if it's registered and related..
4479 if (!this.navId || !this.tabId || !state || is_was_active) {
4483 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4487 var pan = tg.getPanelByName(this.tabId);
4491 // if we can not flip to new panel - go back to old nav highlight..
4492 if (false == tg.showPanel(pan)) {
4493 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4495 var onav = nv.getWasActive();
4497 onav.setActive(true, false, true);
4506 // this should not be here...
4507 setDisabled : function(state)
4509 this.disabled = state;
4511 this.el.removeClass('disabled');
4512 } else if (!this.el.hasClass('disabled')) {
4513 this.el.addClass('disabled');
4519 * Fetch the element to display the tooltip on.
4520 * @return {Roo.Element} defaults to this.el
4522 tooltipEl : function()
4524 return this.el.select('' + this.tagtype + '', true).first();
4527 scrollToElement : function(e)
4529 var c = document.body;
4532 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4534 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4535 c = document.documentElement;
4538 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4544 var o = target.calcOffsetsTo(c);
4551 this.fireEvent('scrollto', this, options, e);
4553 Roo.get(c).scrollTo('top', options.value, true);
4566 * <span> icon </span>
4567 * <span> text </span>
4568 * <span>badge </span>
4572 * @class Roo.bootstrap.NavSidebarItem
4573 * @extends Roo.bootstrap.NavItem
4574 * Bootstrap Navbar.NavSidebarItem class
4575 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4576 * {Boolean} open is the menu open
4577 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4578 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4579 * {String} buttonSize (sm|md|lg)the extra classes for the button
4580 * {Boolean} showArrow show arrow next to the text (default true)
4582 * Create a new Navbar Button
4583 * @param {Object} config The config object
4585 Roo.bootstrap.NavSidebarItem = function(config){
4586 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4591 * The raw click event for the entire grid.
4592 * @param {Roo.EventObject} e
4597 * Fires when the active item active state changes
4598 * @param {Roo.bootstrap.NavSidebarItem} this
4599 * @param {boolean} state the new state
4607 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4609 badgeWeight : 'default',
4615 buttonWeight : 'default',
4621 getAutoCreate : function(){
4626 href : this.href || '#',
4632 if(this.buttonView){
4635 href : this.href || '#',
4636 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4649 cfg.cls += ' active';
4652 if (this.disabled) {
4653 cfg.cls += ' disabled';
4656 cfg.cls += ' open x-open';
4659 if (this.glyphicon || this.icon) {
4660 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4661 a.cn.push({ tag : 'i', cls : c }) ;
4664 if(!this.buttonView){
4667 html : this.html || ''
4674 if (this.badge !== '') {
4675 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4681 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4684 a.cls += ' dropdown-toggle treeview' ;
4690 initEvents : function()
4692 if (typeof (this.menu) != 'undefined') {
4693 this.menu.parentType = this.xtype;
4694 this.menu.triggerEl = this.el;
4695 this.menu = this.addxtype(Roo.apply({}, this.menu));
4698 this.el.on('click', this.onClick, this);
4700 if(this.badge !== ''){
4701 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4706 onClick : function(e)
4713 if(this.preventDefault){
4717 this.fireEvent('click', this);
4720 disable : function()
4722 this.setDisabled(true);
4727 this.setDisabled(false);
4730 setDisabled : function(state)
4732 if(this.disabled == state){
4736 this.disabled = state;
4739 this.el.addClass('disabled');
4743 this.el.removeClass('disabled');
4748 setActive : function(state)
4750 if(this.active == state){
4754 this.active = state;
4757 this.el.addClass('active');
4761 this.el.removeClass('active');
4766 isActive: function ()
4771 setBadge : function(str)
4777 this.badgeEl.dom.innerHTML = str;
4794 * @class Roo.bootstrap.Row
4795 * @extends Roo.bootstrap.Component
4796 * Bootstrap Row class (contains columns...)
4800 * @param {Object} config The config object
4803 Roo.bootstrap.Row = function(config){
4804 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4807 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4809 getAutoCreate : function(){
4828 * @class Roo.bootstrap.Element
4829 * @extends Roo.bootstrap.Component
4830 * Bootstrap Element class
4831 * @cfg {String} html contents of the element
4832 * @cfg {String} tag tag of the element
4833 * @cfg {String} cls class of the element
4834 * @cfg {Boolean} preventDefault (true|false) default false
4835 * @cfg {Boolean} clickable (true|false) default false
4838 * Create a new Element
4839 * @param {Object} config The config object
4842 Roo.bootstrap.Element = function(config){
4843 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4849 * When a element is chick
4850 * @param {Roo.bootstrap.Element} this
4851 * @param {Roo.EventObject} e
4857 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4862 preventDefault: false,
4865 getAutoCreate : function(){
4876 initEvents: function()
4878 Roo.bootstrap.Element.superclass.initEvents.call(this);
4881 this.el.on('click', this.onClick, this);
4886 onClick : function(e)
4888 if(this.preventDefault){
4892 this.fireEvent('click', this, e);
4895 getValue : function()
4897 return this.el.dom.innerHTML;
4900 setValue : function(value)
4902 this.el.dom.innerHTML = value;
4917 * @class Roo.bootstrap.Pagination
4918 * @extends Roo.bootstrap.Component
4919 * Bootstrap Pagination class
4920 * @cfg {String} size xs | sm | md | lg
4921 * @cfg {Boolean} inverse false | true
4924 * Create a new Pagination
4925 * @param {Object} config The config object
4928 Roo.bootstrap.Pagination = function(config){
4929 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4932 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4938 getAutoCreate : function(){
4944 cfg.cls += ' inverse';
4950 cfg.cls += " " + this.cls;
4968 * @class Roo.bootstrap.PaginationItem
4969 * @extends Roo.bootstrap.Component
4970 * Bootstrap PaginationItem class
4971 * @cfg {String} html text
4972 * @cfg {String} href the link
4973 * @cfg {Boolean} preventDefault (true | false) default true
4974 * @cfg {Boolean} active (true | false) default false
4975 * @cfg {Boolean} disabled default false
4979 * Create a new PaginationItem
4980 * @param {Object} config The config object
4984 Roo.bootstrap.PaginationItem = function(config){
4985 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4990 * The raw click event for the entire grid.
4991 * @param {Roo.EventObject} e
4997 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5001 preventDefault: true,
5006 getAutoCreate : function(){
5012 href : this.href ? this.href : '#',
5013 html : this.html ? this.html : ''
5023 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5027 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5033 initEvents: function() {
5035 this.el.on('click', this.onClick, this);
5038 onClick : function(e)
5040 Roo.log('PaginationItem on click ');
5041 if(this.preventDefault){
5049 this.fireEvent('click', this, e);
5065 * @class Roo.bootstrap.Slider
5066 * @extends Roo.bootstrap.Component
5067 * Bootstrap Slider class
5070 * Create a new Slider
5071 * @param {Object} config The config object
5074 Roo.bootstrap.Slider = function(config){
5075 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5078 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5080 getAutoCreate : function(){
5084 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5088 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5100 * Ext JS Library 1.1.1
5101 * Copyright(c) 2006-2007, Ext JS, LLC.
5103 * Originally Released Under LGPL - original licence link has changed is not relivant.
5106 * <script type="text/javascript">
5111 * @class Roo.grid.ColumnModel
5112 * @extends Roo.util.Observable
5113 * This is the default implementation of a ColumnModel used by the Grid. It defines
5114 * the columns in the grid.
5117 var colModel = new Roo.grid.ColumnModel([
5118 {header: "Ticker", width: 60, sortable: true, locked: true},
5119 {header: "Company Name", width: 150, sortable: true},
5120 {header: "Market Cap.", width: 100, sortable: true},
5121 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5122 {header: "Employees", width: 100, sortable: true, resizable: false}
5127 * The config options listed for this class are options which may appear in each
5128 * individual column definition.
5129 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5131 * @param {Object} config An Array of column config objects. See this class's
5132 * config objects for details.
5134 Roo.grid.ColumnModel = function(config){
5136 * The config passed into the constructor
5138 this.config = config;
5141 // if no id, create one
5142 // if the column does not have a dataIndex mapping,
5143 // map it to the order it is in the config
5144 for(var i = 0, len = config.length; i < len; i++){
5146 if(typeof c.dataIndex == "undefined"){
5149 if(typeof c.renderer == "string"){
5150 c.renderer = Roo.util.Format[c.renderer];
5152 if(typeof c.id == "undefined"){
5155 if(c.editor && c.editor.xtype){
5156 c.editor = Roo.factory(c.editor, Roo.grid);
5158 if(c.editor && c.editor.isFormField){
5159 c.editor = new Roo.grid.GridEditor(c.editor);
5161 this.lookup[c.id] = c;
5165 * The width of columns which have no width specified (defaults to 100)
5168 this.defaultWidth = 100;
5171 * Default sortable of columns which have no sortable specified (defaults to false)
5174 this.defaultSortable = false;
5178 * @event widthchange
5179 * Fires when the width of a column changes.
5180 * @param {ColumnModel} this
5181 * @param {Number} columnIndex The column index
5182 * @param {Number} newWidth The new width
5184 "widthchange": true,
5186 * @event headerchange
5187 * Fires when the text of a header changes.
5188 * @param {ColumnModel} this
5189 * @param {Number} columnIndex The column index
5190 * @param {Number} newText The new header text
5192 "headerchange": true,
5194 * @event hiddenchange
5195 * Fires when a column is hidden or "unhidden".
5196 * @param {ColumnModel} this
5197 * @param {Number} columnIndex The column index
5198 * @param {Boolean} hidden true if hidden, false otherwise
5200 "hiddenchange": true,
5202 * @event columnmoved
5203 * Fires when a column is moved.
5204 * @param {ColumnModel} this
5205 * @param {Number} oldIndex
5206 * @param {Number} newIndex
5208 "columnmoved" : true,
5210 * @event columlockchange
5211 * Fires when a column's locked state is changed
5212 * @param {ColumnModel} this
5213 * @param {Number} colIndex
5214 * @param {Boolean} locked true if locked
5216 "columnlockchange" : true
5218 Roo.grid.ColumnModel.superclass.constructor.call(this);
5220 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5222 * @cfg {String} header The header text to display in the Grid view.
5225 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5226 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5227 * specified, the column's index is used as an index into the Record's data Array.
5230 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5231 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5234 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5235 * Defaults to the value of the {@link #defaultSortable} property.
5236 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5239 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5242 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5245 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5248 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5251 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5252 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5253 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5254 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5257 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5260 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5263 * @cfg {String} cursor (Optional)
5266 * @cfg {String} tooltip (Optional)
5269 * @cfg {Number} xs (Optional)
5272 * @cfg {Number} sm (Optional)
5275 * @cfg {Number} md (Optional)
5278 * @cfg {Number} lg (Optional)
5281 * Returns the id of the column at the specified index.
5282 * @param {Number} index The column index
5283 * @return {String} the id
5285 getColumnId : function(index){
5286 return this.config[index].id;
5290 * Returns the column for a specified id.
5291 * @param {String} id The column id
5292 * @return {Object} the column
5294 getColumnById : function(id){
5295 return this.lookup[id];
5300 * Returns the column for a specified dataIndex.
5301 * @param {String} dataIndex The column dataIndex
5302 * @return {Object|Boolean} the column or false if not found
5304 getColumnByDataIndex: function(dataIndex){
5305 var index = this.findColumnIndex(dataIndex);
5306 return index > -1 ? this.config[index] : false;
5310 * Returns the index for a specified column id.
5311 * @param {String} id The column id
5312 * @return {Number} the index, or -1 if not found
5314 getIndexById : function(id){
5315 for(var i = 0, len = this.config.length; i < len; i++){
5316 if(this.config[i].id == id){
5324 * Returns the index for a specified column dataIndex.
5325 * @param {String} dataIndex The column dataIndex
5326 * @return {Number} the index, or -1 if not found
5329 findColumnIndex : function(dataIndex){
5330 for(var i = 0, len = this.config.length; i < len; i++){
5331 if(this.config[i].dataIndex == dataIndex){
5339 moveColumn : function(oldIndex, newIndex){
5340 var c = this.config[oldIndex];
5341 this.config.splice(oldIndex, 1);
5342 this.config.splice(newIndex, 0, c);
5343 this.dataMap = null;
5344 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5347 isLocked : function(colIndex){
5348 return this.config[colIndex].locked === true;
5351 setLocked : function(colIndex, value, suppressEvent){
5352 if(this.isLocked(colIndex) == value){
5355 this.config[colIndex].locked = value;
5357 this.fireEvent("columnlockchange", this, colIndex, value);
5361 getTotalLockedWidth : function(){
5363 for(var i = 0; i < this.config.length; i++){
5364 if(this.isLocked(i) && !this.isHidden(i)){
5365 this.totalWidth += this.getColumnWidth(i);
5371 getLockedCount : function(){
5372 for(var i = 0, len = this.config.length; i < len; i++){
5373 if(!this.isLocked(i)){
5378 return this.config.length;
5382 * Returns the number of columns.
5385 getColumnCount : function(visibleOnly){
5386 if(visibleOnly === true){
5388 for(var i = 0, len = this.config.length; i < len; i++){
5389 if(!this.isHidden(i)){
5395 return this.config.length;
5399 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5400 * @param {Function} fn
5401 * @param {Object} scope (optional)
5402 * @return {Array} result
5404 getColumnsBy : function(fn, scope){
5406 for(var i = 0, len = this.config.length; i < len; i++){
5407 var c = this.config[i];
5408 if(fn.call(scope||this, c, i) === true){
5416 * Returns true if the specified column is sortable.
5417 * @param {Number} col The column index
5420 isSortable : function(col){
5421 if(typeof this.config[col].sortable == "undefined"){
5422 return this.defaultSortable;
5424 return this.config[col].sortable;
5428 * Returns the rendering (formatting) function defined for the column.
5429 * @param {Number} col The column index.
5430 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5432 getRenderer : function(col){
5433 if(!this.config[col].renderer){
5434 return Roo.grid.ColumnModel.defaultRenderer;
5436 return this.config[col].renderer;
5440 * Sets the rendering (formatting) function for a column.
5441 * @param {Number} col The column index
5442 * @param {Function} fn The function to use to process the cell's raw data
5443 * to return HTML markup for the grid view. The render function is called with
5444 * the following parameters:<ul>
5445 * <li>Data value.</li>
5446 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5447 * <li>css A CSS style string to apply to the table cell.</li>
5448 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5449 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5450 * <li>Row index</li>
5451 * <li>Column index</li>
5452 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5454 setRenderer : function(col, fn){
5455 this.config[col].renderer = fn;
5459 * Returns the width for the specified column.
5460 * @param {Number} col The column index
5463 getColumnWidth : function(col){
5464 return this.config[col].width * 1 || this.defaultWidth;
5468 * Sets the width for a column.
5469 * @param {Number} col The column index
5470 * @param {Number} width The new width
5472 setColumnWidth : function(col, width, suppressEvent){
5473 this.config[col].width = width;
5474 this.totalWidth = null;
5476 this.fireEvent("widthchange", this, col, width);
5481 * Returns the total width of all columns.
5482 * @param {Boolean} includeHidden True to include hidden column widths
5485 getTotalWidth : function(includeHidden){
5486 if(!this.totalWidth){
5487 this.totalWidth = 0;
5488 for(var i = 0, len = this.config.length; i < len; i++){
5489 if(includeHidden || !this.isHidden(i)){
5490 this.totalWidth += this.getColumnWidth(i);
5494 return this.totalWidth;
5498 * Returns the header for the specified column.
5499 * @param {Number} col The column index
5502 getColumnHeader : function(col){
5503 return this.config[col].header;
5507 * Sets the header for a column.
5508 * @param {Number} col The column index
5509 * @param {String} header The new header
5511 setColumnHeader : function(col, header){
5512 this.config[col].header = header;
5513 this.fireEvent("headerchange", this, col, header);
5517 * Returns the tooltip for the specified column.
5518 * @param {Number} col The column index
5521 getColumnTooltip : function(col){
5522 return this.config[col].tooltip;
5525 * Sets the tooltip for a column.
5526 * @param {Number} col The column index
5527 * @param {String} tooltip The new tooltip
5529 setColumnTooltip : function(col, tooltip){
5530 this.config[col].tooltip = tooltip;
5534 * Returns the dataIndex for the specified column.
5535 * @param {Number} col The column index
5538 getDataIndex : function(col){
5539 return this.config[col].dataIndex;
5543 * Sets the dataIndex for a column.
5544 * @param {Number} col The column index
5545 * @param {Number} dataIndex The new dataIndex
5547 setDataIndex : function(col, dataIndex){
5548 this.config[col].dataIndex = dataIndex;
5554 * Returns true if the cell is editable.
5555 * @param {Number} colIndex The column index
5556 * @param {Number} rowIndex The row index - this is nto actually used..?
5559 isCellEditable : function(colIndex, rowIndex){
5560 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5564 * Returns the editor defined for the cell/column.
5565 * return false or null to disable editing.
5566 * @param {Number} colIndex The column index
5567 * @param {Number} rowIndex The row index
5570 getCellEditor : function(colIndex, rowIndex){
5571 return this.config[colIndex].editor;
5575 * Sets if a column is editable.
5576 * @param {Number} col The column index
5577 * @param {Boolean} editable True if the column is editable
5579 setEditable : function(col, editable){
5580 this.config[col].editable = editable;
5585 * Returns true if the column is hidden.
5586 * @param {Number} colIndex The column index
5589 isHidden : function(colIndex){
5590 return this.config[colIndex].hidden;
5595 * Returns true if the column width cannot be changed
5597 isFixed : function(colIndex){
5598 return this.config[colIndex].fixed;
5602 * Returns true if the column can be resized
5605 isResizable : function(colIndex){
5606 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5609 * Sets if a column is hidden.
5610 * @param {Number} colIndex The column index
5611 * @param {Boolean} hidden True if the column is hidden
5613 setHidden : function(colIndex, hidden){
5614 this.config[colIndex].hidden = hidden;
5615 this.totalWidth = null;
5616 this.fireEvent("hiddenchange", this, colIndex, hidden);
5620 * Sets the editor for a column.
5621 * @param {Number} col The column index
5622 * @param {Object} editor The editor object
5624 setEditor : function(col, editor){
5625 this.config[col].editor = editor;
5629 Roo.grid.ColumnModel.defaultRenderer = function(value)
5631 if(typeof value == "object") {
5634 if(typeof value == "string" && value.length < 1){
5638 return String.format("{0}", value);
5641 // Alias for backwards compatibility
5642 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5645 * Ext JS Library 1.1.1
5646 * Copyright(c) 2006-2007, Ext JS, LLC.
5648 * Originally Released Under LGPL - original licence link has changed is not relivant.
5651 * <script type="text/javascript">
5655 * @class Roo.LoadMask
5656 * A simple utility class for generically masking elements while loading data. If the element being masked has
5657 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5658 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5659 * element's UpdateManager load indicator and will be destroyed after the initial load.
5661 * Create a new LoadMask
5662 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5663 * @param {Object} config The config object
5665 Roo.LoadMask = function(el, config){
5666 this.el = Roo.get(el);
5667 Roo.apply(this, config);
5669 this.store.on('beforeload', this.onBeforeLoad, this);
5670 this.store.on('load', this.onLoad, this);
5671 this.store.on('loadexception', this.onLoadException, this);
5672 this.removeMask = false;
5674 var um = this.el.getUpdateManager();
5675 um.showLoadIndicator = false; // disable the default indicator
5676 um.on('beforeupdate', this.onBeforeLoad, this);
5677 um.on('update', this.onLoad, this);
5678 um.on('failure', this.onLoad, this);
5679 this.removeMask = true;
5683 Roo.LoadMask.prototype = {
5685 * @cfg {Boolean} removeMask
5686 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5687 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5691 * The text to display in a centered loading message box (defaults to 'Loading...')
5695 * @cfg {String} msgCls
5696 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5698 msgCls : 'x-mask-loading',
5701 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5707 * Disables the mask to prevent it from being displayed
5709 disable : function(){
5710 this.disabled = true;
5714 * Enables the mask so that it can be displayed
5716 enable : function(){
5717 this.disabled = false;
5720 onLoadException : function()
5724 if (typeof(arguments[3]) != 'undefined') {
5725 Roo.MessageBox.alert("Error loading",arguments[3]);
5729 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5730 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5737 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5742 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5746 onBeforeLoad : function(){
5748 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5753 destroy : function(){
5755 this.store.un('beforeload', this.onBeforeLoad, this);
5756 this.store.un('load', this.onLoad, this);
5757 this.store.un('loadexception', this.onLoadException, this);
5759 var um = this.el.getUpdateManager();
5760 um.un('beforeupdate', this.onBeforeLoad, this);
5761 um.un('update', this.onLoad, this);
5762 um.un('failure', this.onLoad, this);
5773 * @class Roo.bootstrap.Table
5774 * @extends Roo.bootstrap.Component
5775 * Bootstrap Table class
5776 * @cfg {String} cls table class
5777 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5778 * @cfg {String} bgcolor Specifies the background color for a table
5779 * @cfg {Number} border Specifies whether the table cells should have borders or not
5780 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5781 * @cfg {Number} cellspacing Specifies the space between cells
5782 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5783 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5784 * @cfg {String} sortable Specifies that the table should be sortable
5785 * @cfg {String} summary Specifies a summary of the content of a table
5786 * @cfg {Number} width Specifies the width of a table
5787 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5789 * @cfg {boolean} striped Should the rows be alternative striped
5790 * @cfg {boolean} bordered Add borders to the table
5791 * @cfg {boolean} hover Add hover highlighting
5792 * @cfg {boolean} condensed Format condensed
5793 * @cfg {boolean} responsive Format condensed
5794 * @cfg {Boolean} loadMask (true|false) default false
5795 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5796 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5797 * @cfg {Boolean} rowSelection (true|false) default false
5798 * @cfg {Boolean} cellSelection (true|false) default false
5799 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5800 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5801 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5805 * Create a new Table
5806 * @param {Object} config The config object
5809 Roo.bootstrap.Table = function(config){
5810 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5815 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5816 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5817 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5818 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5820 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5822 this.sm.grid = this;
5823 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5824 this.sm = this.selModel;
5825 this.sm.xmodule = this.xmodule || false;
5828 if (this.cm && typeof(this.cm.config) == 'undefined') {
5829 this.colModel = new Roo.grid.ColumnModel(this.cm);
5830 this.cm = this.colModel;
5831 this.cm.xmodule = this.xmodule || false;
5834 this.store= Roo.factory(this.store, Roo.data);
5835 this.ds = this.store;
5836 this.ds.xmodule = this.xmodule || false;
5839 if (this.footer && this.store) {
5840 this.footer.dataSource = this.ds;
5841 this.footer = Roo.factory(this.footer);
5848 * Fires when a cell is clicked
5849 * @param {Roo.bootstrap.Table} this
5850 * @param {Roo.Element} el
5851 * @param {Number} rowIndex
5852 * @param {Number} columnIndex
5853 * @param {Roo.EventObject} e
5857 * @event celldblclick
5858 * Fires when a cell is double clicked
5859 * @param {Roo.bootstrap.Table} this
5860 * @param {Roo.Element} el
5861 * @param {Number} rowIndex
5862 * @param {Number} columnIndex
5863 * @param {Roo.EventObject} e
5865 "celldblclick" : true,
5868 * Fires when a row is clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Roo.Element} el
5871 * @param {Number} rowIndex
5872 * @param {Roo.EventObject} e
5876 * @event rowdblclick
5877 * Fires when a row is double clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Roo.Element} el
5880 * @param {Number} rowIndex
5881 * @param {Roo.EventObject} e
5883 "rowdblclick" : true,
5886 * Fires when a mouseover occur
5887 * @param {Roo.bootstrap.Table} this
5888 * @param {Roo.Element} el
5889 * @param {Number} rowIndex
5890 * @param {Number} columnIndex
5891 * @param {Roo.EventObject} e
5896 * Fires when a mouseout occur
5897 * @param {Roo.bootstrap.Table} this
5898 * @param {Roo.Element} el
5899 * @param {Number} rowIndex
5900 * @param {Number} columnIndex
5901 * @param {Roo.EventObject} e
5906 * Fires when a row is rendered, so you can change add a style to it.
5907 * @param {Roo.bootstrap.Table} this
5908 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5912 * @event rowsrendered
5913 * Fires when all the rows have been rendered
5914 * @param {Roo.bootstrap.Table} this
5916 'rowsrendered' : true,
5918 * @event contextmenu
5919 * The raw contextmenu event for the entire grid.
5920 * @param {Roo.EventObject} e
5922 "contextmenu" : true,
5924 * @event rowcontextmenu
5925 * Fires when a row is right clicked
5926 * @param {Roo.bootstrap.Table} this
5927 * @param {Number} rowIndex
5928 * @param {Roo.EventObject} e
5930 "rowcontextmenu" : true,
5932 * @event cellcontextmenu
5933 * Fires when a cell is right clicked
5934 * @param {Roo.bootstrap.Table} this
5935 * @param {Number} rowIndex
5936 * @param {Number} cellIndex
5937 * @param {Roo.EventObject} e
5939 "cellcontextmenu" : true,
5941 * @event headercontextmenu
5942 * Fires when a header is right clicked
5943 * @param {Roo.bootstrap.Table} this
5944 * @param {Number} columnIndex
5945 * @param {Roo.EventObject} e
5947 "headercontextmenu" : true
5951 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5977 rowSelection : false,
5978 cellSelection : false,
5981 // Roo.Element - the tbody
5983 // Roo.Element - thead element
5986 container: false, // used by gridpanel...
5990 getAutoCreate : function()
5992 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5999 if (this.scrollBody) {
6000 cfg.cls += ' table-body-fixed';
6003 cfg.cls += ' table-striped';
6007 cfg.cls += ' table-hover';
6009 if (this.bordered) {
6010 cfg.cls += ' table-bordered';
6012 if (this.condensed) {
6013 cfg.cls += ' table-condensed';
6015 if (this.responsive) {
6016 cfg.cls += ' table-responsive';
6020 cfg.cls+= ' ' +this.cls;
6023 // this lot should be simplifed...
6026 cfg.align=this.align;
6029 cfg.bgcolor=this.bgcolor;
6032 cfg.border=this.border;
6034 if (this.cellpadding) {
6035 cfg.cellpadding=this.cellpadding;
6037 if (this.cellspacing) {
6038 cfg.cellspacing=this.cellspacing;
6041 cfg.frame=this.frame;
6044 cfg.rules=this.rules;
6046 if (this.sortable) {
6047 cfg.sortable=this.sortable;
6050 cfg.summary=this.summary;
6053 cfg.width=this.width;
6056 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6059 if(this.store || this.cm){
6060 if(this.headerShow){
6061 cfg.cn.push(this.renderHeader());
6064 cfg.cn.push(this.renderBody());
6066 if(this.footerShow){
6067 cfg.cn.push(this.renderFooter());
6069 // where does this come from?
6070 //cfg.cls+= ' TableGrid';
6073 return { cn : [ cfg ] };
6076 initEvents : function()
6078 if(!this.store || !this.cm){
6081 if (this.selModel) {
6082 this.selModel.initEvents();
6086 //Roo.log('initEvents with ds!!!!');
6088 this.mainBody = this.el.select('tbody', true).first();
6089 this.mainHead = this.el.select('thead', true).first();
6096 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6097 e.on('click', _this.sort, _this);
6100 this.mainBody.on("click", this.onClick, this);
6101 this.mainBody.on("dblclick", this.onDblClick, this);
6103 // why is this done????? = it breaks dialogs??
6104 //this.parent().el.setStyle('position', 'relative');
6108 this.footer.parentId = this.id;
6109 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6112 this.el.select('tfoot tr td').first().addClass('hide');
6116 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6118 this.store.on('load', this.onLoad, this);
6119 this.store.on('beforeload', this.onBeforeLoad, this);
6120 this.store.on('update', this.onUpdate, this);
6121 this.store.on('add', this.onAdd, this);
6122 this.store.on("clear", this.clear, this);
6124 this.el.on("contextmenu", this.onContextMenu, this);
6126 this.mainBody.on('scroll', this.onBodyScroll, this);
6131 onContextMenu : function(e, t)
6133 this.processEvent("contextmenu", e);
6136 processEvent : function(name, e)
6138 if (name != 'touchstart' ) {
6139 this.fireEvent(name, e);
6142 var t = e.getTarget();
6144 var cell = Roo.get(t);
6150 if(cell.findParent('tfoot', false, true)){
6154 if(cell.findParent('thead', false, true)){
6156 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6157 cell = Roo.get(t).findParent('th', false, true);
6159 Roo.log("failed to find th in thead?");
6160 Roo.log(e.getTarget());
6165 var cellIndex = cell.dom.cellIndex;
6167 var ename = name == 'touchstart' ? 'click' : name;
6168 this.fireEvent("header" + ename, this, cellIndex, e);
6173 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6174 cell = Roo.get(t).findParent('td', false, true);
6176 Roo.log("failed to find th in tbody?");
6177 Roo.log(e.getTarget());
6182 var row = cell.findParent('tr', false, true);
6183 var cellIndex = cell.dom.cellIndex;
6184 var rowIndex = row.dom.rowIndex - 1;
6188 this.fireEvent("row" + name, this, rowIndex, e);
6192 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6198 onMouseover : function(e, el)
6200 var cell = Roo.get(el);
6206 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6207 cell = cell.findParent('td', false, true);
6210 var row = cell.findParent('tr', false, true);
6211 var cellIndex = cell.dom.cellIndex;
6212 var rowIndex = row.dom.rowIndex - 1; // start from 0
6214 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6218 onMouseout : function(e, el)
6220 var cell = Roo.get(el);
6226 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6227 cell = cell.findParent('td', false, true);
6230 var row = cell.findParent('tr', false, true);
6231 var cellIndex = cell.dom.cellIndex;
6232 var rowIndex = row.dom.rowIndex - 1; // start from 0
6234 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6238 onClick : function(e, el)
6240 var cell = Roo.get(el);
6242 if(!cell || (!this.cellSelection && !this.rowSelection)){
6246 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6247 cell = cell.findParent('td', false, true);
6250 if(!cell || typeof(cell) == 'undefined'){
6254 var row = cell.findParent('tr', false, true);
6256 if(!row || typeof(row) == 'undefined'){
6260 var cellIndex = cell.dom.cellIndex;
6261 var rowIndex = this.getRowIndex(row);
6263 // why??? - should these not be based on SelectionModel?
6264 if(this.cellSelection){
6265 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6268 if(this.rowSelection){
6269 this.fireEvent('rowclick', this, row, rowIndex, e);
6275 onDblClick : function(e,el)
6277 var cell = Roo.get(el);
6279 if(!cell || (!this.cellSelection && !this.rowSelection)){
6283 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6284 cell = cell.findParent('td', false, true);
6287 if(!cell || typeof(cell) == 'undefined'){
6291 var row = cell.findParent('tr', false, true);
6293 if(!row || typeof(row) == 'undefined'){
6297 var cellIndex = cell.dom.cellIndex;
6298 var rowIndex = this.getRowIndex(row);
6300 if(this.cellSelection){
6301 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6304 if(this.rowSelection){
6305 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6309 sort : function(e,el)
6311 var col = Roo.get(el);
6313 if(!col.hasClass('sortable')){
6317 var sort = col.attr('sort');
6320 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6324 this.store.sortInfo = {field : sort, direction : dir};
6327 Roo.log("calling footer first");
6328 this.footer.onClick('first');
6331 this.store.load({ params : { start : 0 } });
6335 renderHeader : function()
6343 this.totalWidth = 0;
6345 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6347 var config = cm.config[i];
6352 html: cm.getColumnHeader(i)
6357 if(typeof(config.sortable) != 'undefined' && config.sortable){
6359 c.html = '<i class="glyphicon"></i>' + c.html;
6362 if(typeof(config.lgHeader) != 'undefined'){
6363 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6366 if(typeof(config.mdHeader) != 'undefined'){
6367 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6370 if(typeof(config.smHeader) != 'undefined'){
6371 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6374 if(typeof(config.xsHeader) != 'undefined'){
6375 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6382 if(typeof(config.tooltip) != 'undefined'){
6383 c.tooltip = config.tooltip;
6386 if(typeof(config.colspan) != 'undefined'){
6387 c.colspan = config.colspan;
6390 if(typeof(config.hidden) != 'undefined' && config.hidden){
6391 c.style += ' display:none;';
6394 if(typeof(config.dataIndex) != 'undefined'){
6395 c.sort = config.dataIndex;
6400 if(typeof(config.align) != 'undefined' && config.align.length){
6401 c.style += ' text-align:' + config.align + ';';
6404 if(typeof(config.width) != 'undefined'){
6405 c.style += ' width:' + config.width + 'px;';
6406 this.totalWidth += config.width;
6408 this.totalWidth += 100; // assume minimum of 100 per column?
6411 if(typeof(config.cls) != 'undefined'){
6412 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6415 ['xs','sm','md','lg'].map(function(size){
6417 if(typeof(config[size]) == 'undefined'){
6421 if (!config[size]) { // 0 = hidden
6422 c.cls += ' hidden-' + size;
6426 c.cls += ' col-' + size + '-' + config[size];
6436 renderBody : function()
6446 colspan : this.cm.getColumnCount()
6456 renderFooter : function()
6466 colspan : this.cm.getColumnCount()
6480 // Roo.log('ds onload');
6485 var ds = this.store;
6487 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6488 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6489 if (_this.store.sortInfo) {
6491 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6492 e.select('i', true).addClass(['glyphicon-arrow-up']);
6495 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6496 e.select('i', true).addClass(['glyphicon-arrow-down']);
6501 var tbody = this.mainBody;
6503 if(ds.getCount() > 0){
6504 ds.data.each(function(d,rowIndex){
6505 var row = this.renderRow(cm, ds, rowIndex);
6507 tbody.createChild(row);
6511 if(row.cellObjects.length){
6512 Roo.each(row.cellObjects, function(r){
6513 _this.renderCellObject(r);
6520 Roo.each(this.el.select('tbody td', true).elements, function(e){
6521 e.on('mouseover', _this.onMouseover, _this);
6524 Roo.each(this.el.select('tbody td', true).elements, function(e){
6525 e.on('mouseout', _this.onMouseout, _this);
6527 this.fireEvent('rowsrendered', this);
6528 //if(this.loadMask){
6529 // this.maskEl.hide();
6536 onUpdate : function(ds,record)
6538 this.refreshRow(record);
6542 onRemove : function(ds, record, index, isUpdate){
6543 if(isUpdate !== true){
6544 this.fireEvent("beforerowremoved", this, index, record);
6546 var bt = this.mainBody.dom;
6548 var rows = this.el.select('tbody > tr', true).elements;
6550 if(typeof(rows[index]) != 'undefined'){
6551 bt.removeChild(rows[index].dom);
6554 // if(bt.rows[index]){
6555 // bt.removeChild(bt.rows[index]);
6558 if(isUpdate !== true){
6559 //this.stripeRows(index);
6560 //this.syncRowHeights(index, index);
6562 this.fireEvent("rowremoved", this, index, record);
6566 onAdd : function(ds, records, rowIndex)
6568 //Roo.log('on Add called');
6569 // - note this does not handle multiple adding very well..
6570 var bt = this.mainBody.dom;
6571 for (var i =0 ; i < records.length;i++) {
6572 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6573 //Roo.log(records[i]);
6574 //Roo.log(this.store.getAt(rowIndex+i));
6575 this.insertRow(this.store, rowIndex + i, false);
6582 refreshRow : function(record){
6583 var ds = this.store, index;
6584 if(typeof record == 'number'){
6586 record = ds.getAt(index);
6588 index = ds.indexOf(record);
6590 this.insertRow(ds, index, true);
6592 this.onRemove(ds, record, index+1, true);
6594 //this.syncRowHeights(index, index);
6596 this.fireEvent("rowupdated", this, index, record);
6599 insertRow : function(dm, rowIndex, isUpdate){
6602 this.fireEvent("beforerowsinserted", this, rowIndex);
6604 //var s = this.getScrollState();
6605 var row = this.renderRow(this.cm, this.store, rowIndex);
6606 // insert before rowIndex..
6607 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6611 if(row.cellObjects.length){
6612 Roo.each(row.cellObjects, function(r){
6613 _this.renderCellObject(r);
6618 this.fireEvent("rowsinserted", this, rowIndex);
6619 //this.syncRowHeights(firstRow, lastRow);
6620 //this.stripeRows(firstRow);
6627 getRowDom : function(rowIndex)
6629 var rows = this.el.select('tbody > tr', true).elements;
6631 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6634 // returns the object tree for a tr..
6637 renderRow : function(cm, ds, rowIndex)
6640 var d = ds.getAt(rowIndex);
6647 var cellObjects = [];
6649 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6650 var config = cm.config[i];
6652 var renderer = cm.getRenderer(i);
6656 if(typeof(renderer) !== 'undefined'){
6657 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6659 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6660 // and are rendered into the cells after the row is rendered - using the id for the element.
6662 if(typeof(value) === 'object'){
6672 rowIndex : rowIndex,
6677 this.fireEvent('rowclass', this, rowcfg);
6681 cls : rowcfg.rowClass,
6683 html: (typeof(value) === 'object') ? '' : value
6690 if(typeof(config.colspan) != 'undefined'){
6691 td.colspan = config.colspan;
6694 if(typeof(config.hidden) != 'undefined' && config.hidden){
6695 td.style += ' display:none;';
6698 if(typeof(config.align) != 'undefined' && config.align.length){
6699 td.style += ' text-align:' + config.align + ';';
6702 if(typeof(config.width) != 'undefined'){
6703 td.style += ' width:' + config.width + 'px;';
6706 if(typeof(config.cursor) != 'undefined'){
6707 td.style += ' cursor:' + config.cursor + ';';
6710 if(typeof(config.cls) != 'undefined'){
6711 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6714 ['xs','sm','md','lg'].map(function(size){
6716 if(typeof(config[size]) == 'undefined'){
6720 if (!config[size]) { // 0 = hidden
6721 td.cls += ' hidden-' + size;
6725 td.cls += ' col-' + size + '-' + config[size];
6733 row.cellObjects = cellObjects;
6741 onBeforeLoad : function()
6743 //Roo.log('ds onBeforeLoad');
6747 //if(this.loadMask){
6748 // this.maskEl.show();
6756 this.el.select('tbody', true).first().dom.innerHTML = '';
6759 * Show or hide a row.
6760 * @param {Number} rowIndex to show or hide
6761 * @param {Boolean} state hide
6763 setRowVisibility : function(rowIndex, state)
6765 var bt = this.mainBody.dom;
6767 var rows = this.el.select('tbody > tr', true).elements;
6769 if(typeof(rows[rowIndex]) == 'undefined'){
6772 rows[rowIndex].dom.style.display = state ? '' : 'none';
6776 getSelectionModel : function(){
6778 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6780 return this.selModel;
6783 * Render the Roo.bootstrap object from renderder
6785 renderCellObject : function(r)
6789 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6791 var t = r.cfg.render(r.container);
6794 Roo.each(r.cfg.cn, function(c){
6796 container: t.getChildContainer(),
6799 _this.renderCellObject(child);
6804 getRowIndex : function(row)
6808 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6819 * Returns the grid's underlying element = used by panel.Grid
6820 * @return {Element} The element
6822 getGridEl : function(){
6826 * Forces a resize - used by panel.Grid
6827 * @return {Element} The element
6829 autoSize : function()
6831 //var ctr = Roo.get(this.container.dom.parentElement);
6832 var ctr = Roo.get(this.el.dom);
6834 var thd = this.getGridEl().select('thead',true).first();
6835 var tbd = this.getGridEl().select('tbody', true).first();
6836 var tfd = this.getGridEl().select('tfoot', true).first();
6838 var cw = ctr.getWidth();
6842 tbd.setSize(ctr.getWidth(),
6843 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6845 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6848 cw = Math.max(cw, this.totalWidth);
6849 this.getGridEl().select('tr',true).setWidth(cw);
6850 // resize 'expandable coloumn?
6852 return; // we doe not have a view in this design..
6855 onBodyScroll: function()
6857 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6858 this.mainHead.setStyle({
6859 'position' : 'relative',
6860 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6865 var scrollHeight = this.mainBody.dom.scrollHeight;
6867 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6869 var height = this.mainBody.getHeight();
6871 if(scrollHeight - height == scrollTop) {
6873 var total = this.ds.getTotalCount();
6875 if(this.footer.cursor + this.footer.pageSize < total){
6877 this.footer.ds.load({
6879 start : this.footer.cursor + this.footer.pageSize,
6880 limit : this.footer.pageSize
6901 * @class Roo.bootstrap.TableCell
6902 * @extends Roo.bootstrap.Component
6903 * Bootstrap TableCell class
6904 * @cfg {String} html cell contain text
6905 * @cfg {String} cls cell class
6906 * @cfg {String} tag cell tag (td|th) default td
6907 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6908 * @cfg {String} align Aligns the content in a cell
6909 * @cfg {String} axis Categorizes cells
6910 * @cfg {String} bgcolor Specifies the background color of a cell
6911 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6912 * @cfg {Number} colspan Specifies the number of columns a cell should span
6913 * @cfg {String} headers Specifies one or more header cells a cell is related to
6914 * @cfg {Number} height Sets the height of a cell
6915 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6916 * @cfg {Number} rowspan Sets the number of rows a cell should span
6917 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6918 * @cfg {String} valign Vertical aligns the content in a cell
6919 * @cfg {Number} width Specifies the width of a cell
6922 * Create a new TableCell
6923 * @param {Object} config The config object
6926 Roo.bootstrap.TableCell = function(config){
6927 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6930 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6950 getAutoCreate : function(){
6951 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6971 cfg.align=this.align
6977 cfg.bgcolor=this.bgcolor
6980 cfg.charoff=this.charoff
6983 cfg.colspan=this.colspan
6986 cfg.headers=this.headers
6989 cfg.height=this.height
6992 cfg.nowrap=this.nowrap
6995 cfg.rowspan=this.rowspan
6998 cfg.scope=this.scope
7001 cfg.valign=this.valign
7004 cfg.width=this.width
7023 * @class Roo.bootstrap.TableRow
7024 * @extends Roo.bootstrap.Component
7025 * Bootstrap TableRow class
7026 * @cfg {String} cls row class
7027 * @cfg {String} align Aligns the content in a table row
7028 * @cfg {String} bgcolor Specifies a background color for a table row
7029 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7030 * @cfg {String} valign Vertical aligns the content in a table row
7033 * Create a new TableRow
7034 * @param {Object} config The config object
7037 Roo.bootstrap.TableRow = function(config){
7038 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7041 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7049 getAutoCreate : function(){
7050 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7060 cfg.align = this.align;
7063 cfg.bgcolor = this.bgcolor;
7066 cfg.charoff = this.charoff;
7069 cfg.valign = this.valign;
7087 * @class Roo.bootstrap.TableBody
7088 * @extends Roo.bootstrap.Component
7089 * Bootstrap TableBody class
7090 * @cfg {String} cls element class
7091 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7092 * @cfg {String} align Aligns the content inside the element
7093 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7094 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7097 * Create a new TableBody
7098 * @param {Object} config The config object
7101 Roo.bootstrap.TableBody = function(config){
7102 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7105 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7113 getAutoCreate : function(){
7114 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7128 cfg.align = this.align;
7131 cfg.charoff = this.charoff;
7134 cfg.valign = this.valign;
7141 // initEvents : function()
7148 // this.store = Roo.factory(this.store, Roo.data);
7149 // this.store.on('load', this.onLoad, this);
7151 // this.store.load();
7155 // onLoad: function ()
7157 // this.fireEvent('load', this);
7167 * Ext JS Library 1.1.1
7168 * Copyright(c) 2006-2007, Ext JS, LLC.
7170 * Originally Released Under LGPL - original licence link has changed is not relivant.
7173 * <script type="text/javascript">
7176 // as we use this in bootstrap.
7177 Roo.namespace('Roo.form');
7179 * @class Roo.form.Action
7180 * Internal Class used to handle form actions
7182 * @param {Roo.form.BasicForm} el The form element or its id
7183 * @param {Object} config Configuration options
7188 // define the action interface
7189 Roo.form.Action = function(form, options){
7191 this.options = options || {};
7194 * Client Validation Failed
7197 Roo.form.Action.CLIENT_INVALID = 'client';
7199 * Server Validation Failed
7202 Roo.form.Action.SERVER_INVALID = 'server';
7204 * Connect to Server Failed
7207 Roo.form.Action.CONNECT_FAILURE = 'connect';
7209 * Reading Data from Server Failed
7212 Roo.form.Action.LOAD_FAILURE = 'load';
7214 Roo.form.Action.prototype = {
7216 failureType : undefined,
7217 response : undefined,
7221 run : function(options){
7226 success : function(response){
7231 handleResponse : function(response){
7235 // default connection failure
7236 failure : function(response){
7238 this.response = response;
7239 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7240 this.form.afterAction(this, false);
7243 processResponse : function(response){
7244 this.response = response;
7245 if(!response.responseText){
7248 this.result = this.handleResponse(response);
7252 // utility functions used internally
7253 getUrl : function(appendParams){
7254 var url = this.options.url || this.form.url || this.form.el.dom.action;
7256 var p = this.getParams();
7258 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7264 getMethod : function(){
7265 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7268 getParams : function(){
7269 var bp = this.form.baseParams;
7270 var p = this.options.params;
7272 if(typeof p == "object"){
7273 p = Roo.urlEncode(Roo.applyIf(p, bp));
7274 }else if(typeof p == 'string' && bp){
7275 p += '&' + Roo.urlEncode(bp);
7278 p = Roo.urlEncode(bp);
7283 createCallback : function(){
7285 success: this.success,
7286 failure: this.failure,
7288 timeout: (this.form.timeout*1000),
7289 upload: this.form.fileUpload ? this.success : undefined
7294 Roo.form.Action.Submit = function(form, options){
7295 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7298 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7301 haveProgress : false,
7302 uploadComplete : false,
7304 // uploadProgress indicator.
7305 uploadProgress : function()
7307 if (!this.form.progressUrl) {
7311 if (!this.haveProgress) {
7312 Roo.MessageBox.progress("Uploading", "Uploading");
7314 if (this.uploadComplete) {
7315 Roo.MessageBox.hide();
7319 this.haveProgress = true;
7321 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7323 var c = new Roo.data.Connection();
7325 url : this.form.progressUrl,
7330 success : function(req){
7331 //console.log(data);
7335 rdata = Roo.decode(req.responseText)
7337 Roo.log("Invalid data from server..");
7341 if (!rdata || !rdata.success) {
7343 Roo.MessageBox.alert(Roo.encode(rdata));
7346 var data = rdata.data;
7348 if (this.uploadComplete) {
7349 Roo.MessageBox.hide();
7354 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7355 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7358 this.uploadProgress.defer(2000,this);
7361 failure: function(data) {
7362 Roo.log('progress url failed ');
7373 // run get Values on the form, so it syncs any secondary forms.
7374 this.form.getValues();
7376 var o = this.options;
7377 var method = this.getMethod();
7378 var isPost = method == 'POST';
7379 if(o.clientValidation === false || this.form.isValid()){
7381 if (this.form.progressUrl) {
7382 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7383 (new Date() * 1) + '' + Math.random());
7388 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7389 form:this.form.el.dom,
7390 url:this.getUrl(!isPost),
7392 params:isPost ? this.getParams() : null,
7393 isUpload: this.form.fileUpload
7396 this.uploadProgress();
7398 }else if (o.clientValidation !== false){ // client validation failed
7399 this.failureType = Roo.form.Action.CLIENT_INVALID;
7400 this.form.afterAction(this, false);
7404 success : function(response)
7406 this.uploadComplete= true;
7407 if (this.haveProgress) {
7408 Roo.MessageBox.hide();
7412 var result = this.processResponse(response);
7413 if(result === true || result.success){
7414 this.form.afterAction(this, true);
7418 this.form.markInvalid(result.errors);
7419 this.failureType = Roo.form.Action.SERVER_INVALID;
7421 this.form.afterAction(this, false);
7423 failure : function(response)
7425 this.uploadComplete= true;
7426 if (this.haveProgress) {
7427 Roo.MessageBox.hide();
7430 this.response = response;
7431 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7432 this.form.afterAction(this, false);
7435 handleResponse : function(response){
7436 if(this.form.errorReader){
7437 var rs = this.form.errorReader.read(response);
7440 for(var i = 0, len = rs.records.length; i < len; i++) {
7441 var r = rs.records[i];
7445 if(errors.length < 1){
7449 success : rs.success,
7455 ret = Roo.decode(response.responseText);
7459 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7469 Roo.form.Action.Load = function(form, options){
7470 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7471 this.reader = this.form.reader;
7474 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7479 Roo.Ajax.request(Roo.apply(
7480 this.createCallback(), {
7481 method:this.getMethod(),
7482 url:this.getUrl(false),
7483 params:this.getParams()
7487 success : function(response){
7489 var result = this.processResponse(response);
7490 if(result === true || !result.success || !result.data){
7491 this.failureType = Roo.form.Action.LOAD_FAILURE;
7492 this.form.afterAction(this, false);
7495 this.form.clearInvalid();
7496 this.form.setValues(result.data);
7497 this.form.afterAction(this, true);
7500 handleResponse : function(response){
7501 if(this.form.reader){
7502 var rs = this.form.reader.read(response);
7503 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7505 success : rs.success,
7509 return Roo.decode(response.responseText);
7513 Roo.form.Action.ACTION_TYPES = {
7514 'load' : Roo.form.Action.Load,
7515 'submit' : Roo.form.Action.Submit
7524 * @class Roo.bootstrap.Form
7525 * @extends Roo.bootstrap.Component
7526 * Bootstrap Form class
7527 * @cfg {String} method GET | POST (default POST)
7528 * @cfg {String} labelAlign top | left (default top)
7529 * @cfg {String} align left | right - for navbars
7530 * @cfg {Boolean} loadMask load mask when submit (default true)
7535 * @param {Object} config The config object
7539 Roo.bootstrap.Form = function(config){
7540 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7542 Roo.bootstrap.Form.popover.apply();
7546 * @event clientvalidation
7547 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7548 * @param {Form} this
7549 * @param {Boolean} valid true if the form has passed client-side validation
7551 clientvalidation: true,
7553 * @event beforeaction
7554 * Fires before any action is performed. Return false to cancel the action.
7555 * @param {Form} this
7556 * @param {Action} action The action to be performed
7560 * @event actionfailed
7561 * Fires when an action fails.
7562 * @param {Form} this
7563 * @param {Action} action The action that failed
7565 actionfailed : true,
7567 * @event actioncomplete
7568 * Fires when an action is completed.
7569 * @param {Form} this
7570 * @param {Action} action The action that completed
7572 actioncomplete : true
7577 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7580 * @cfg {String} method
7581 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7586 * The URL to use for form actions if one isn't supplied in the action options.
7589 * @cfg {Boolean} fileUpload
7590 * Set to true if this form is a file upload.
7594 * @cfg {Object} baseParams
7595 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7599 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7603 * @cfg {Sting} align (left|right) for navbar forms
7608 activeAction : null,
7611 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7612 * element by passing it or its id or mask the form itself by passing in true.
7615 waitMsgTarget : false,
7620 * @cfg {Boolean} errorMask (true|false) default false
7625 * @cfg {Number} maskOffset Default 100
7630 * @cfg {Boolean} maskBody
7634 getAutoCreate : function(){
7638 method : this.method || 'POST',
7639 id : this.id || Roo.id(),
7642 if (this.parent().xtype.match(/^Nav/)) {
7643 cfg.cls = 'navbar-form navbar-' + this.align;
7647 if (this.labelAlign == 'left' ) {
7648 cfg.cls += ' form-horizontal';
7654 initEvents : function()
7656 this.el.on('submit', this.onSubmit, this);
7657 // this was added as random key presses on the form where triggering form submit.
7658 this.el.on('keypress', function(e) {
7659 if (e.getCharCode() != 13) {
7662 // we might need to allow it for textareas.. and some other items.
7663 // check e.getTarget().
7665 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7669 Roo.log("keypress blocked");
7677 onSubmit : function(e){
7682 * Returns true if client-side validation on the form is successful.
7685 isValid : function(){
7686 var items = this.getItems();
7690 items.each(function(f){
7696 if(!target && f.el.isVisible(true)){
7702 if(this.errorMask && !valid){
7703 Roo.bootstrap.Form.popover.mask(this, target);
7710 * Returns true if any fields in this form have changed since their original load.
7713 isDirty : function(){
7715 var items = this.getItems();
7716 items.each(function(f){
7726 * Performs a predefined action (submit or load) or custom actions you define on this form.
7727 * @param {String} actionName The name of the action type
7728 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7729 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7730 * accept other config options):
7732 Property Type Description
7733 ---------------- --------------- ----------------------------------------------------------------------------------
7734 url String The url for the action (defaults to the form's url)
7735 method String The form method to use (defaults to the form's method, or POST if not defined)
7736 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7737 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7738 validate the form on the client (defaults to false)
7740 * @return {BasicForm} this
7742 doAction : function(action, options){
7743 if(typeof action == 'string'){
7744 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7746 if(this.fireEvent('beforeaction', this, action) !== false){
7747 this.beforeAction(action);
7748 action.run.defer(100, action);
7754 beforeAction : function(action){
7755 var o = action.options;
7760 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7762 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7765 // not really supported yet.. ??
7767 //if(this.waitMsgTarget === true){
7768 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7769 //}else if(this.waitMsgTarget){
7770 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7771 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7773 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7779 afterAction : function(action, success){
7780 this.activeAction = null;
7781 var o = action.options;
7786 Roo.get(document.body).unmask();
7792 //if(this.waitMsgTarget === true){
7793 // this.el.unmask();
7794 //}else if(this.waitMsgTarget){
7795 // this.waitMsgTarget.unmask();
7797 // Roo.MessageBox.updateProgress(1);
7798 // Roo.MessageBox.hide();
7805 Roo.callback(o.success, o.scope, [this, action]);
7806 this.fireEvent('actioncomplete', this, action);
7810 // failure condition..
7811 // we have a scenario where updates need confirming.
7812 // eg. if a locking scenario exists..
7813 // we look for { errors : { needs_confirm : true }} in the response.
7815 (typeof(action.result) != 'undefined') &&
7816 (typeof(action.result.errors) != 'undefined') &&
7817 (typeof(action.result.errors.needs_confirm) != 'undefined')
7820 Roo.log("not supported yet");
7823 Roo.MessageBox.confirm(
7824 "Change requires confirmation",
7825 action.result.errorMsg,
7830 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7840 Roo.callback(o.failure, o.scope, [this, action]);
7841 // show an error message if no failed handler is set..
7842 if (!this.hasListener('actionfailed')) {
7843 Roo.log("need to add dialog support");
7845 Roo.MessageBox.alert("Error",
7846 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7847 action.result.errorMsg :
7848 "Saving Failed, please check your entries or try again"
7853 this.fireEvent('actionfailed', this, action);
7858 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7859 * @param {String} id The value to search for
7862 findField : function(id){
7863 var items = this.getItems();
7864 var field = items.get(id);
7866 items.each(function(f){
7867 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7874 return field || null;
7877 * Mark fields in this form invalid in bulk.
7878 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7879 * @return {BasicForm} this
7881 markInvalid : function(errors){
7882 if(errors instanceof Array){
7883 for(var i = 0, len = errors.length; i < len; i++){
7884 var fieldError = errors[i];
7885 var f = this.findField(fieldError.id);
7887 f.markInvalid(fieldError.msg);
7893 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7894 field.markInvalid(errors[id]);
7898 //Roo.each(this.childForms || [], function (f) {
7899 // f.markInvalid(errors);
7906 * Set values for fields in this form in bulk.
7907 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7908 * @return {BasicForm} this
7910 setValues : function(values){
7911 if(values instanceof Array){ // array of objects
7912 for(var i = 0, len = values.length; i < len; i++){
7914 var f = this.findField(v.id);
7916 f.setValue(v.value);
7917 if(this.trackResetOnLoad){
7918 f.originalValue = f.getValue();
7922 }else{ // object hash
7925 if(typeof values[id] != 'function' && (field = this.findField(id))){
7927 if (field.setFromData &&
7929 field.displayField &&
7930 // combos' with local stores can
7931 // be queried via setValue()
7932 // to set their value..
7933 (field.store && !field.store.isLocal)
7937 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7938 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7939 field.setFromData(sd);
7941 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
7943 field.setFromData(values);
7946 field.setValue(values[id]);
7950 if(this.trackResetOnLoad){
7951 field.originalValue = field.getValue();
7957 //Roo.each(this.childForms || [], function (f) {
7958 // f.setValues(values);
7965 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7966 * they are returned as an array.
7967 * @param {Boolean} asString
7970 getValues : function(asString){
7971 //if (this.childForms) {
7972 // copy values from the child forms
7973 // Roo.each(this.childForms, function (f) {
7974 // this.setValues(f.getValues());
7980 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7981 if(asString === true){
7984 return Roo.urlDecode(fs);
7988 * Returns the fields in this form as an object with key/value pairs.
7989 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7992 getFieldValues : function(with_hidden)
7994 var items = this.getItems();
7996 items.each(function(f){
8002 var v = f.getValue();
8004 if (f.inputType =='radio') {
8005 if (typeof(ret[f.getName()]) == 'undefined') {
8006 ret[f.getName()] = ''; // empty..
8009 if (!f.el.dom.checked) {
8017 if(f.xtype == 'MoneyField'){
8018 ret[f.currencyName] = f.getCurrency();
8021 // not sure if this supported any more..
8022 if ((typeof(v) == 'object') && f.getRawValue) {
8023 v = f.getRawValue() ; // dates..
8025 // combo boxes where name != hiddenName...
8026 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8027 ret[f.name] = f.getRawValue();
8029 ret[f.getName()] = v;
8036 * Clears all invalid messages in this form.
8037 * @return {BasicForm} this
8039 clearInvalid : function(){
8040 var items = this.getItems();
8042 items.each(function(f){
8053 * @return {BasicForm} this
8056 var items = this.getItems();
8057 items.each(function(f){
8061 Roo.each(this.childForms || [], function (f) {
8069 getItems : function()
8071 var r=new Roo.util.MixedCollection(false, function(o){
8072 return o.id || (o.id = Roo.id());
8074 var iter = function(el) {
8081 Roo.each(el.items,function(e) {
8095 Roo.apply(Roo.bootstrap.Form, {
8122 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8123 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8124 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8125 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8128 this.maskEl.top.enableDisplayMode("block");
8129 this.maskEl.left.enableDisplayMode("block");
8130 this.maskEl.bottom.enableDisplayMode("block");
8131 this.maskEl.right.enableDisplayMode("block");
8133 this.toolTip = new Roo.bootstrap.Tooltip({
8134 cls : 'roo-form-error-popover',
8136 'left' : ['r-l', [-2,0], 'right'],
8137 'right' : ['l-r', [2,0], 'left'],
8138 'bottom' : ['tl-bl', [0,2], 'top'],
8139 'top' : [ 'bl-tl', [0,-2], 'bottom']
8143 this.toolTip.render(Roo.get(document.body));
8145 this.toolTip.el.enableDisplayMode("block");
8147 Roo.get(document.body).on('click', function(){
8151 Roo.get(document.body).on('touchstart', function(){
8155 this.isApplied = true
8158 mask : function(form, target)
8162 this.target = target;
8164 if(!this.form.errorMask || !target.el){
8168 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8170 Roo.log(scrollable);
8172 var ot = this.target.el.calcOffsetsTo(scrollable);
8174 var scrollTo = ot[1] - this.form.maskOffset;
8176 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8178 scrollable.scrollTo('top', scrollTo);
8180 var box = this.target.el.getBox();
8182 var zIndex = Roo.bootstrap.Modal.zIndex++;
8185 this.maskEl.top.setStyle('position', 'absolute');
8186 this.maskEl.top.setStyle('z-index', zIndex);
8187 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8188 this.maskEl.top.setLeft(0);
8189 this.maskEl.top.setTop(0);
8190 this.maskEl.top.show();
8192 this.maskEl.left.setStyle('position', 'absolute');
8193 this.maskEl.left.setStyle('z-index', zIndex);
8194 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8195 this.maskEl.left.setLeft(0);
8196 this.maskEl.left.setTop(box.y - this.padding);
8197 this.maskEl.left.show();
8199 this.maskEl.bottom.setStyle('position', 'absolute');
8200 this.maskEl.bottom.setStyle('z-index', zIndex);
8201 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8202 this.maskEl.bottom.setLeft(0);
8203 this.maskEl.bottom.setTop(box.bottom + this.padding);
8204 this.maskEl.bottom.show();
8206 this.maskEl.right.setStyle('position', 'absolute');
8207 this.maskEl.right.setStyle('z-index', zIndex);
8208 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8209 this.maskEl.right.setLeft(box.right + this.padding);
8210 this.maskEl.right.setTop(box.y - this.padding);
8211 this.maskEl.right.show();
8213 this.toolTip.bindEl = this.target.el;
8215 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8217 var tip = this.target.blankText;
8219 if(this.target.getValue() !== '' ) {
8221 if (this.target.invalidText.length) {
8222 tip = this.target.invalidText;
8223 } else if (this.target.regexText.length){
8224 tip = this.target.regexText;
8228 this.toolTip.show(tip);
8230 this.intervalID = window.setInterval(function() {
8231 Roo.bootstrap.Form.popover.unmask();
8234 window.onwheel = function(){ return false;};
8236 (function(){ this.isMasked = true; }).defer(500, this);
8242 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8246 this.maskEl.top.setStyle('position', 'absolute');
8247 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8248 this.maskEl.top.hide();
8250 this.maskEl.left.setStyle('position', 'absolute');
8251 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8252 this.maskEl.left.hide();
8254 this.maskEl.bottom.setStyle('position', 'absolute');
8255 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8256 this.maskEl.bottom.hide();
8258 this.maskEl.right.setStyle('position', 'absolute');
8259 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8260 this.maskEl.right.hide();
8262 this.toolTip.hide();
8264 this.toolTip.el.hide();
8266 window.onwheel = function(){ return true;};
8268 if(this.intervalID){
8269 window.clearInterval(this.intervalID);
8270 this.intervalID = false;
8273 this.isMasked = false;
8283 * Ext JS Library 1.1.1
8284 * Copyright(c) 2006-2007, Ext JS, LLC.
8286 * Originally Released Under LGPL - original licence link has changed is not relivant.
8289 * <script type="text/javascript">
8292 * @class Roo.form.VTypes
8293 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8296 Roo.form.VTypes = function(){
8297 // closure these in so they are only created once.
8298 var alpha = /^[a-zA-Z_]+$/;
8299 var alphanum = /^[a-zA-Z0-9_]+$/;
8300 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8301 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8303 // All these messages and functions are configurable
8306 * The function used to validate email addresses
8307 * @param {String} value The email address
8309 'email' : function(v){
8310 return email.test(v);
8313 * The error text to display when the email validation function returns false
8316 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8318 * The keystroke filter mask to be applied on email input
8321 'emailMask' : /[a-z0-9_\.\-@]/i,
8324 * The function used to validate URLs
8325 * @param {String} value The URL
8327 'url' : function(v){
8331 * The error text to display when the url validation function returns false
8334 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8337 * The function used to validate alpha values
8338 * @param {String} value The value
8340 'alpha' : function(v){
8341 return alpha.test(v);
8344 * The error text to display when the alpha validation function returns false
8347 'alphaText' : 'This field should only contain letters and _',
8349 * The keystroke filter mask to be applied on alpha input
8352 'alphaMask' : /[a-z_]/i,
8355 * The function used to validate alphanumeric values
8356 * @param {String} value The value
8358 'alphanum' : function(v){
8359 return alphanum.test(v);
8362 * The error text to display when the alphanumeric validation function returns false
8365 'alphanumText' : 'This field should only contain letters, numbers and _',
8367 * The keystroke filter mask to be applied on alphanumeric input
8370 'alphanumMask' : /[a-z0-9_]/i
8380 * @class Roo.bootstrap.Input
8381 * @extends Roo.bootstrap.Component
8382 * Bootstrap Input class
8383 * @cfg {Boolean} disabled is it disabled
8384 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8385 * @cfg {String} name name of the input
8386 * @cfg {string} fieldLabel - the label associated
8387 * @cfg {string} placeholder - placeholder to put in text.
8388 * @cfg {string} before - input group add on before
8389 * @cfg {string} after - input group add on after
8390 * @cfg {string} size - (lg|sm) or leave empty..
8391 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8392 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8393 * @cfg {Number} md colspan out of 12 for computer-sized screens
8394 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8395 * @cfg {string} value default value of the input
8396 * @cfg {Number} labelWidth set the width of label
8397 * @cfg {Number} labellg set the width of label (1-12)
8398 * @cfg {Number} labelmd set the width of label (1-12)
8399 * @cfg {Number} labelsm set the width of label (1-12)
8400 * @cfg {Number} labelxs set the width of label (1-12)
8401 * @cfg {String} labelAlign (top|left)
8402 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8403 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8404 * @cfg {String} indicatorpos (left|right) default left
8406 * @cfg {String} align (left|center|right) Default left
8407 * @cfg {Boolean} forceFeedback (true|false) Default false
8413 * Create a new Input
8414 * @param {Object} config The config object
8417 Roo.bootstrap.Input = function(config){
8419 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8424 * Fires when this field receives input focus.
8425 * @param {Roo.form.Field} this
8430 * Fires when this field loses input focus.
8431 * @param {Roo.form.Field} this
8436 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8437 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8438 * @param {Roo.form.Field} this
8439 * @param {Roo.EventObject} e The event object
8444 * Fires just before the field blurs if the field value has changed.
8445 * @param {Roo.form.Field} this
8446 * @param {Mixed} newValue The new value
8447 * @param {Mixed} oldValue The original value
8452 * Fires after the field has been marked as invalid.
8453 * @param {Roo.form.Field} this
8454 * @param {String} msg The validation message
8459 * Fires after the field has been validated with no errors.
8460 * @param {Roo.form.Field} this
8465 * Fires after the key up
8466 * @param {Roo.form.Field} this
8467 * @param {Roo.EventObject} e The event Object
8473 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8475 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8476 automatic validation (defaults to "keyup").
8478 validationEvent : "keyup",
8480 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8482 validateOnBlur : true,
8484 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8486 validationDelay : 250,
8488 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8490 focusClass : "x-form-focus", // not needed???
8494 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8496 invalidClass : "has-warning",
8499 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8501 validClass : "has-success",
8504 * @cfg {Boolean} hasFeedback (true|false) default true
8509 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8511 invalidFeedbackClass : "glyphicon-warning-sign",
8514 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8516 validFeedbackClass : "glyphicon-ok",
8519 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8521 selectOnFocus : false,
8524 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8528 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8533 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8535 disableKeyFilter : false,
8538 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8542 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8546 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8548 blankText : "Please complete this mandatory field",
8551 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8555 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8557 maxLength : Number.MAX_VALUE,
8559 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8561 minLengthText : "The minimum length for this field is {0}",
8563 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8565 maxLengthText : "The maximum length for this field is {0}",
8569 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8570 * If available, this function will be called only after the basic validators all return true, and will be passed the
8571 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8575 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8576 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8577 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8581 * @cfg {String} regexText -- Depricated - use Invalid Text
8586 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8592 autocomplete: false,
8611 formatedValue : false,
8612 forceFeedback : false,
8614 indicatorpos : 'left',
8621 parentLabelAlign : function()
8624 while (parent.parent()) {
8625 parent = parent.parent();
8626 if (typeof(parent.labelAlign) !='undefined') {
8627 return parent.labelAlign;
8634 getAutoCreate : function()
8636 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8642 if(this.inputType != 'hidden'){
8643 cfg.cls = 'form-group' //input-group
8649 type : this.inputType,
8651 cls : 'form-control',
8652 placeholder : this.placeholder || '',
8653 autocomplete : this.autocomplete || 'new-password'
8657 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8660 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8661 input.maxLength = this.maxLength;
8664 if (this.disabled) {
8665 input.disabled=true;
8668 if (this.readOnly) {
8669 input.readonly=true;
8673 input.name = this.name;
8677 input.cls += ' input-' + this.size;
8681 ['xs','sm','md','lg'].map(function(size){
8682 if (settings[size]) {
8683 cfg.cls += ' col-' + size + '-' + settings[size];
8687 var inputblock = input;
8691 cls: 'glyphicon form-control-feedback'
8694 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8697 cls : 'has-feedback',
8705 if (this.before || this.after) {
8708 cls : 'input-group',
8712 if (this.before && typeof(this.before) == 'string') {
8714 inputblock.cn.push({
8716 cls : 'roo-input-before input-group-addon',
8720 if (this.before && typeof(this.before) == 'object') {
8721 this.before = Roo.factory(this.before);
8723 inputblock.cn.push({
8725 cls : 'roo-input-before input-group-' +
8726 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8730 inputblock.cn.push(input);
8732 if (this.after && typeof(this.after) == 'string') {
8733 inputblock.cn.push({
8735 cls : 'roo-input-after input-group-addon',
8739 if (this.after && typeof(this.after) == 'object') {
8740 this.after = Roo.factory(this.after);
8742 inputblock.cn.push({
8744 cls : 'roo-input-after input-group-' +
8745 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8749 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8750 inputblock.cls += ' has-feedback';
8751 inputblock.cn.push(feedback);
8755 if (align ==='left' && this.fieldLabel.length) {
8757 cfg.cls += ' roo-form-group-label-left';
8762 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8763 tooltip : 'This field is required'
8768 cls : 'control-label',
8769 html : this.fieldLabel
8780 var labelCfg = cfg.cn[1];
8781 var contentCfg = cfg.cn[2];
8783 if(this.indicatorpos == 'right'){
8788 cls : 'control-label',
8792 html : this.fieldLabel
8796 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8797 tooltip : 'This field is required'
8810 labelCfg = cfg.cn[0];
8811 contentCfg = cfg.cn[1];
8815 if(this.labelWidth > 12){
8816 labelCfg.style = "width: " + this.labelWidth + 'px';
8819 if(this.labelWidth < 13 && this.labelmd == 0){
8820 this.labelmd = this.labelWidth;
8823 if(this.labellg > 0){
8824 labelCfg.cls += ' col-lg-' + this.labellg;
8825 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8828 if(this.labelmd > 0){
8829 labelCfg.cls += ' col-md-' + this.labelmd;
8830 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8833 if(this.labelsm > 0){
8834 labelCfg.cls += ' col-sm-' + this.labelsm;
8835 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8838 if(this.labelxs > 0){
8839 labelCfg.cls += ' col-xs-' + this.labelxs;
8840 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8844 } else if ( this.fieldLabel.length) {
8849 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8850 tooltip : 'This field is required'
8854 //cls : 'input-group-addon',
8855 html : this.fieldLabel
8863 if(this.indicatorpos == 'right'){
8868 //cls : 'input-group-addon',
8869 html : this.fieldLabel
8874 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8875 tooltip : 'This field is required'
8895 if (this.parentType === 'Navbar' && this.parent().bar) {
8896 cfg.cls += ' navbar-form';
8899 if (this.parentType === 'NavGroup') {
8900 cfg.cls += ' navbar-form';
8908 * return the real input element.
8910 inputEl: function ()
8912 return this.el.select('input.form-control',true).first();
8915 tooltipEl : function()
8917 return this.inputEl();
8920 indicatorEl : function()
8922 var indicator = this.el.select('i.roo-required-indicator',true).first();
8932 setDisabled : function(v)
8934 var i = this.inputEl().dom;
8936 i.removeAttribute('disabled');
8940 i.setAttribute('disabled','true');
8942 initEvents : function()
8945 this.inputEl().on("keydown" , this.fireKey, this);
8946 this.inputEl().on("focus", this.onFocus, this);
8947 this.inputEl().on("blur", this.onBlur, this);
8949 this.inputEl().relayEvent('keyup', this);
8951 this.indicator = this.indicatorEl();
8954 this.indicator.addClass('invisible');
8958 // reference to original value for reset
8959 this.originalValue = this.getValue();
8960 //Roo.form.TextField.superclass.initEvents.call(this);
8961 if(this.validationEvent == 'keyup'){
8962 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8963 this.inputEl().on('keyup', this.filterValidation, this);
8965 else if(this.validationEvent !== false){
8966 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8969 if(this.selectOnFocus){
8970 this.on("focus", this.preFocus, this);
8973 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8974 this.inputEl().on("keypress", this.filterKeys, this);
8976 this.inputEl().relayEvent('keypress', this);
8979 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8980 this.el.on("click", this.autoSize, this);
8983 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8984 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8987 if (typeof(this.before) == 'object') {
8988 this.before.render(this.el.select('.roo-input-before',true).first());
8990 if (typeof(this.after) == 'object') {
8991 this.after.render(this.el.select('.roo-input-after',true).first());
8996 filterValidation : function(e){
8997 if(!e.isNavKeyPress()){
8998 this.validationTask.delay(this.validationDelay);
9002 * Validates the field value
9003 * @return {Boolean} True if the value is valid, else false
9005 validate : function(){
9006 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9007 if(this.disabled || this.validateValue(this.getRawValue())){
9018 * Validates a value according to the field's validation rules and marks the field as invalid
9019 * if the validation fails
9020 * @param {Mixed} value The value to validate
9021 * @return {Boolean} True if the value is valid, else false
9023 validateValue : function(value){
9024 if(value.length < 1) { // if it's blank
9025 if(this.allowBlank){
9028 return this.inputEl().hasClass('hide') ? true : false;
9031 if(value.length < this.minLength){
9034 if(value.length > this.maxLength){
9038 var vt = Roo.form.VTypes;
9039 if(!vt[this.vtype](value, this)){
9043 if(typeof this.validator == "function"){
9044 var msg = this.validator(value);
9048 if (typeof(msg) == 'string') {
9049 this.invalidText = msg;
9053 if(this.regex && !this.regex.test(value)){
9063 fireKey : function(e){
9064 //Roo.log('field ' + e.getKey());
9065 if(e.isNavKeyPress()){
9066 this.fireEvent("specialkey", this, e);
9069 focus : function (selectText){
9071 this.inputEl().focus();
9072 if(selectText === true){
9073 this.inputEl().dom.select();
9079 onFocus : function(){
9080 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9081 // this.el.addClass(this.focusClass);
9084 this.hasFocus = true;
9085 this.startValue = this.getValue();
9086 this.fireEvent("focus", this);
9090 beforeBlur : Roo.emptyFn,
9094 onBlur : function(){
9096 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9097 //this.el.removeClass(this.focusClass);
9099 this.hasFocus = false;
9100 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9103 var v = this.getValue();
9104 if(String(v) !== String(this.startValue)){
9105 this.fireEvent('change', this, v, this.startValue);
9107 this.fireEvent("blur", this);
9111 * Resets the current field value to the originally loaded value and clears any validation messages
9114 this.setValue(this.originalValue);
9118 * Returns the name of the field
9119 * @return {Mixed} name The name field
9121 getName: function(){
9125 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9126 * @return {Mixed} value The field value
9128 getValue : function(){
9130 var v = this.inputEl().getValue();
9135 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9136 * @return {Mixed} value The field value
9138 getRawValue : function(){
9139 var v = this.inputEl().getValue();
9145 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9146 * @param {Mixed} value The value to set
9148 setRawValue : function(v){
9149 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9152 selectText : function(start, end){
9153 var v = this.getRawValue();
9155 start = start === undefined ? 0 : start;
9156 end = end === undefined ? v.length : end;
9157 var d = this.inputEl().dom;
9158 if(d.setSelectionRange){
9159 d.setSelectionRange(start, end);
9160 }else if(d.createTextRange){
9161 var range = d.createTextRange();
9162 range.moveStart("character", start);
9163 range.moveEnd("character", v.length-end);
9170 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9171 * @param {Mixed} value The value to set
9173 setValue : function(v){
9176 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9182 processValue : function(value){
9183 if(this.stripCharsRe){
9184 var newValue = value.replace(this.stripCharsRe, '');
9185 if(newValue !== value){
9186 this.setRawValue(newValue);
9193 preFocus : function(){
9195 if(this.selectOnFocus){
9196 this.inputEl().dom.select();
9199 filterKeys : function(e){
9201 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9204 var c = e.getCharCode(), cc = String.fromCharCode(c);
9205 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9208 if(!this.maskRe.test(cc)){
9213 * Clear any invalid styles/messages for this field
9215 clearInvalid : function(){
9217 if(!this.el || this.preventMark){ // not rendered
9222 this.el.removeClass(this.invalidClass);
9224 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9226 var feedback = this.el.select('.form-control-feedback', true).first();
9229 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9234 this.fireEvent('valid', this);
9238 * Mark this field as valid
9240 markValid : function()
9242 if(!this.el || this.preventMark){ // not rendered...
9246 this.el.removeClass([this.invalidClass, this.validClass]);
9248 var feedback = this.el.select('.form-control-feedback', true).first();
9251 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9258 if(this.allowBlank && !this.getRawValue().length){
9263 this.indicator.removeClass('visible');
9264 this.indicator.addClass('invisible');
9267 this.el.addClass(this.validClass);
9269 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9271 var feedback = this.el.select('.form-control-feedback', true).first();
9274 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9275 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9280 this.fireEvent('valid', this);
9284 * Mark this field as invalid
9285 * @param {String} msg The validation message
9287 markInvalid : function(msg)
9289 if(!this.el || this.preventMark){ // not rendered
9293 this.el.removeClass([this.invalidClass, this.validClass]);
9295 var feedback = this.el.select('.form-control-feedback', true).first();
9298 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9305 if(this.allowBlank && !this.getRawValue().length){
9310 this.indicator.removeClass('invisible');
9311 this.indicator.addClass('visible');
9314 this.el.addClass(this.invalidClass);
9316 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9318 var feedback = this.el.select('.form-control-feedback', true).first();
9321 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9323 if(this.getValue().length || this.forceFeedback){
9324 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9331 this.fireEvent('invalid', this, msg);
9334 SafariOnKeyDown : function(event)
9336 // this is a workaround for a password hang bug on chrome/ webkit.
9337 if (this.inputEl().dom.type != 'password') {
9341 var isSelectAll = false;
9343 if(this.inputEl().dom.selectionEnd > 0){
9344 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9346 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9347 event.preventDefault();
9352 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9354 event.preventDefault();
9355 // this is very hacky as keydown always get's upper case.
9357 var cc = String.fromCharCode(event.getCharCode());
9358 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9362 adjustWidth : function(tag, w){
9363 tag = tag.toLowerCase();
9364 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9365 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9369 if(tag == 'textarea'){
9372 }else if(Roo.isOpera){
9376 if(tag == 'textarea'){
9384 setFieldLabel : function(v)
9390 this.fieldLabel = v;
9393 var ar = this.el.select('label > span',true);
9394 if (!ar.elements.length) {
9395 Roo.log("could not find label > span on element");
9399 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9403 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9416 * @class Roo.bootstrap.TextArea
9417 * @extends Roo.bootstrap.Input
9418 * Bootstrap TextArea class
9419 * @cfg {Number} cols Specifies the visible width of a text area
9420 * @cfg {Number} rows Specifies the visible number of lines in a text area
9421 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9422 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9423 * @cfg {string} html text
9426 * Create a new TextArea
9427 * @param {Object} config The config object
9430 Roo.bootstrap.TextArea = function(config){
9431 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9435 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9445 getAutoCreate : function(){
9447 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9453 if(this.inputType != 'hidden'){
9454 cfg.cls = 'form-group' //input-group
9462 value : this.value || '',
9463 html: this.html || '',
9464 cls : 'form-control',
9465 placeholder : this.placeholder || ''
9469 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9470 input.maxLength = this.maxLength;
9474 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9478 input.cols = this.cols;
9481 if (this.readOnly) {
9482 input.readonly = true;
9486 input.name = this.name;
9490 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9494 ['xs','sm','md','lg'].map(function(size){
9495 if (settings[size]) {
9496 cfg.cls += ' col-' + size + '-' + settings[size];
9500 var inputblock = input;
9502 if(this.hasFeedback && !this.allowBlank){
9506 cls: 'glyphicon form-control-feedback'
9510 cls : 'has-feedback',
9519 if (this.before || this.after) {
9522 cls : 'input-group',
9526 inputblock.cn.push({
9528 cls : 'input-group-addon',
9533 inputblock.cn.push(input);
9535 if(this.hasFeedback && !this.allowBlank){
9536 inputblock.cls += ' has-feedback';
9537 inputblock.cn.push(feedback);
9541 inputblock.cn.push({
9543 cls : 'input-group-addon',
9550 if (align ==='left' && this.fieldLabel.length) {
9555 cls : 'control-label',
9556 html : this.fieldLabel
9567 if(this.labelWidth > 12){
9568 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9571 if(this.labelWidth < 13 && this.labelmd == 0){
9572 this.labelmd = this.labelWidth;
9575 if(this.labellg > 0){
9576 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9577 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9580 if(this.labelmd > 0){
9581 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9582 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9585 if(this.labelsm > 0){
9586 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9587 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9590 if(this.labelxs > 0){
9591 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9592 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9595 } else if ( this.fieldLabel.length) {
9600 //cls : 'input-group-addon',
9601 html : this.fieldLabel
9619 if (this.disabled) {
9620 input.disabled=true;
9627 * return the real textarea element.
9629 inputEl: function ()
9631 return this.el.select('textarea.form-control',true).first();
9635 * Clear any invalid styles/messages for this field
9637 clearInvalid : function()
9640 if(!this.el || this.preventMark){ // not rendered
9644 var label = this.el.select('label', true).first();
9645 var icon = this.el.select('i.fa-star', true).first();
9651 this.el.removeClass(this.invalidClass);
9653 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9655 var feedback = this.el.select('.form-control-feedback', true).first();
9658 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9663 this.fireEvent('valid', this);
9667 * Mark this field as valid
9669 markValid : function()
9671 if(!this.el || this.preventMark){ // not rendered
9675 this.el.removeClass([this.invalidClass, this.validClass]);
9677 var feedback = this.el.select('.form-control-feedback', true).first();
9680 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9683 if(this.disabled || this.allowBlank){
9687 var label = this.el.select('label', true).first();
9688 var icon = this.el.select('i.fa-star', true).first();
9694 this.el.addClass(this.validClass);
9696 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9698 var feedback = this.el.select('.form-control-feedback', true).first();
9701 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9702 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9707 this.fireEvent('valid', this);
9711 * Mark this field as invalid
9712 * @param {String} msg The validation message
9714 markInvalid : function(msg)
9716 if(!this.el || this.preventMark){ // not rendered
9720 this.el.removeClass([this.invalidClass, this.validClass]);
9722 var feedback = this.el.select('.form-control-feedback', true).first();
9725 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9728 if(this.disabled || this.allowBlank){
9732 var label = this.el.select('label', true).first();
9733 var icon = this.el.select('i.fa-star', true).first();
9735 if(!this.getValue().length && label && !icon){
9736 this.el.createChild({
9738 cls : 'text-danger fa fa-lg fa-star',
9739 tooltip : 'This field is required',
9740 style : 'margin-right:5px;'
9744 this.el.addClass(this.invalidClass);
9746 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9748 var feedback = this.el.select('.form-control-feedback', true).first();
9751 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9753 if(this.getValue().length || this.forceFeedback){
9754 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9761 this.fireEvent('invalid', this, msg);
9769 * trigger field - base class for combo..
9774 * @class Roo.bootstrap.TriggerField
9775 * @extends Roo.bootstrap.Input
9776 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9777 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9778 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9779 * for which you can provide a custom implementation. For example:
9781 var trigger = new Roo.bootstrap.TriggerField();
9782 trigger.onTriggerClick = myTriggerFn;
9783 trigger.applyTo('my-field');
9786 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9787 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9788 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9789 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9790 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9793 * Create a new TriggerField.
9794 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9795 * to the base TextField)
9797 Roo.bootstrap.TriggerField = function(config){
9798 this.mimicing = false;
9799 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9802 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9804 * @cfg {String} triggerClass A CSS class to apply to the trigger
9807 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9812 * @cfg {Boolean} removable (true|false) special filter default false
9816 /** @cfg {Boolean} grow @hide */
9817 /** @cfg {Number} growMin @hide */
9818 /** @cfg {Number} growMax @hide */
9824 autoSize: Roo.emptyFn,
9831 actionMode : 'wrap',
9836 getAutoCreate : function(){
9838 var align = this.labelAlign || this.parentLabelAlign();
9843 cls: 'form-group' //input-group
9850 type : this.inputType,
9851 cls : 'form-control',
9852 autocomplete: 'new-password',
9853 placeholder : this.placeholder || ''
9857 input.name = this.name;
9860 input.cls += ' input-' + this.size;
9863 if (this.disabled) {
9864 input.disabled=true;
9867 var inputblock = input;
9869 if(this.hasFeedback && !this.allowBlank){
9873 cls: 'glyphicon form-control-feedback'
9876 if(this.removable && !this.editable && !this.tickable){
9878 cls : 'has-feedback',
9884 cls : 'roo-combo-removable-btn close'
9891 cls : 'has-feedback',
9900 if(this.removable && !this.editable && !this.tickable){
9902 cls : 'roo-removable',
9908 cls : 'roo-combo-removable-btn close'
9915 if (this.before || this.after) {
9918 cls : 'input-group',
9922 inputblock.cn.push({
9924 cls : 'input-group-addon',
9929 inputblock.cn.push(input);
9931 if(this.hasFeedback && !this.allowBlank){
9932 inputblock.cls += ' has-feedback';
9933 inputblock.cn.push(feedback);
9937 inputblock.cn.push({
9939 cls : 'input-group-addon',
9952 cls: 'form-hidden-field'
9966 cls: 'form-hidden-field'
9970 cls: 'roo-select2-choices',
9974 cls: 'roo-select2-search-field',
9987 cls: 'roo-select2-container input-group',
9992 // cls: 'typeahead typeahead-long dropdown-menu',
9993 // style: 'display:none'
9998 if(!this.multiple && this.showToggleBtn){
10004 if (this.caret != false) {
10007 cls: 'fa fa-' + this.caret
10014 cls : 'input-group-addon btn dropdown-toggle',
10019 cls: 'combobox-clear',
10033 combobox.cls += ' roo-select2-container-multi';
10036 if (align ==='left' && this.fieldLabel.length) {
10038 cfg.cls += ' roo-form-group-label-left';
10043 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10044 tooltip : 'This field is required'
10049 cls : 'control-label',
10050 html : this.fieldLabel
10062 var labelCfg = cfg.cn[1];
10063 var contentCfg = cfg.cn[2];
10065 if(this.indicatorpos == 'right'){
10070 cls : 'control-label',
10074 html : this.fieldLabel
10078 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10079 tooltip : 'This field is required'
10092 labelCfg = cfg.cn[0];
10093 contentCfg = cfg.cn[1];
10096 if(this.labelWidth > 12){
10097 labelCfg.style = "width: " + this.labelWidth + 'px';
10100 if(this.labelWidth < 13 && this.labelmd == 0){
10101 this.labelmd = this.labelWidth;
10104 if(this.labellg > 0){
10105 labelCfg.cls += ' col-lg-' + this.labellg;
10106 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10109 if(this.labelmd > 0){
10110 labelCfg.cls += ' col-md-' + this.labelmd;
10111 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10114 if(this.labelsm > 0){
10115 labelCfg.cls += ' col-sm-' + this.labelsm;
10116 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10119 if(this.labelxs > 0){
10120 labelCfg.cls += ' col-xs-' + this.labelxs;
10121 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10124 } else if ( this.fieldLabel.length) {
10125 // Roo.log(" label");
10129 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10130 tooltip : 'This field is required'
10134 //cls : 'input-group-addon',
10135 html : this.fieldLabel
10143 if(this.indicatorpos == 'right'){
10151 html : this.fieldLabel
10155 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10156 tooltip : 'This field is required'
10169 // Roo.log(" no label && no align");
10176 ['xs','sm','md','lg'].map(function(size){
10177 if (settings[size]) {
10178 cfg.cls += ' col-' + size + '-' + settings[size];
10189 onResize : function(w, h){
10190 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10191 // if(typeof w == 'number'){
10192 // var x = w - this.trigger.getWidth();
10193 // this.inputEl().setWidth(this.adjustWidth('input', x));
10194 // this.trigger.setStyle('left', x+'px');
10199 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10202 getResizeEl : function(){
10203 return this.inputEl();
10207 getPositionEl : function(){
10208 return this.inputEl();
10212 alignErrorIcon : function(){
10213 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10217 initEvents : function(){
10221 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10222 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10223 if(!this.multiple && this.showToggleBtn){
10224 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10225 if(this.hideTrigger){
10226 this.trigger.setDisplayed(false);
10228 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10232 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10235 if(this.removable && !this.editable && !this.tickable){
10236 var close = this.closeTriggerEl();
10239 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10240 close.on('click', this.removeBtnClick, this, close);
10244 //this.trigger.addClassOnOver('x-form-trigger-over');
10245 //this.trigger.addClassOnClick('x-form-trigger-click');
10248 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10252 closeTriggerEl : function()
10254 var close = this.el.select('.roo-combo-removable-btn', true).first();
10255 return close ? close : false;
10258 removeBtnClick : function(e, h, el)
10260 e.preventDefault();
10262 if(this.fireEvent("remove", this) !== false){
10264 this.fireEvent("afterremove", this)
10268 createList : function()
10270 this.list = Roo.get(document.body).createChild({
10272 cls: 'typeahead typeahead-long dropdown-menu',
10273 style: 'display:none'
10276 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10281 initTrigger : function(){
10286 onDestroy : function(){
10288 this.trigger.removeAllListeners();
10289 // this.trigger.remove();
10292 // this.wrap.remove();
10294 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10298 onFocus : function(){
10299 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10301 if(!this.mimicing){
10302 this.wrap.addClass('x-trigger-wrap-focus');
10303 this.mimicing = true;
10304 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10305 if(this.monitorTab){
10306 this.el.on("keydown", this.checkTab, this);
10313 checkTab : function(e){
10314 if(e.getKey() == e.TAB){
10315 this.triggerBlur();
10320 onBlur : function(){
10325 mimicBlur : function(e, t){
10327 if(!this.wrap.contains(t) && this.validateBlur()){
10328 this.triggerBlur();
10334 triggerBlur : function(){
10335 this.mimicing = false;
10336 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10337 if(this.monitorTab){
10338 this.el.un("keydown", this.checkTab, this);
10340 //this.wrap.removeClass('x-trigger-wrap-focus');
10341 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10345 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10346 validateBlur : function(e, t){
10351 onDisable : function(){
10352 this.inputEl().dom.disabled = true;
10353 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10355 // this.wrap.addClass('x-item-disabled');
10360 onEnable : function(){
10361 this.inputEl().dom.disabled = false;
10362 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10364 // this.el.removeClass('x-item-disabled');
10369 onShow : function(){
10370 var ae = this.getActionEl();
10373 ae.dom.style.display = '';
10374 ae.dom.style.visibility = 'visible';
10380 onHide : function(){
10381 var ae = this.getActionEl();
10382 ae.dom.style.display = 'none';
10386 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10387 * by an implementing function.
10389 * @param {EventObject} e
10391 onTriggerClick : Roo.emptyFn
10395 * Ext JS Library 1.1.1
10396 * Copyright(c) 2006-2007, Ext JS, LLC.
10398 * Originally Released Under LGPL - original licence link has changed is not relivant.
10401 * <script type="text/javascript">
10406 * @class Roo.data.SortTypes
10408 * Defines the default sorting (casting?) comparison functions used when sorting data.
10410 Roo.data.SortTypes = {
10412 * Default sort that does nothing
10413 * @param {Mixed} s The value being converted
10414 * @return {Mixed} The comparison value
10416 none : function(s){
10421 * The regular expression used to strip tags
10425 stripTagsRE : /<\/?[^>]+>/gi,
10428 * Strips all HTML tags to sort on text only
10429 * @param {Mixed} s The value being converted
10430 * @return {String} The comparison value
10432 asText : function(s){
10433 return String(s).replace(this.stripTagsRE, "");
10437 * Strips all HTML tags to sort on text only - Case insensitive
10438 * @param {Mixed} s The value being converted
10439 * @return {String} The comparison value
10441 asUCText : function(s){
10442 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10446 * Case insensitive string
10447 * @param {Mixed} s The value being converted
10448 * @return {String} The comparison value
10450 asUCString : function(s) {
10451 return String(s).toUpperCase();
10456 * @param {Mixed} s The value being converted
10457 * @return {Number} The comparison value
10459 asDate : function(s) {
10463 if(s instanceof Date){
10464 return s.getTime();
10466 return Date.parse(String(s));
10471 * @param {Mixed} s The value being converted
10472 * @return {Float} The comparison value
10474 asFloat : function(s) {
10475 var val = parseFloat(String(s).replace(/,/g, ""));
10484 * @param {Mixed} s The value being converted
10485 * @return {Number} The comparison value
10487 asInt : function(s) {
10488 var val = parseInt(String(s).replace(/,/g, ""));
10496 * Ext JS Library 1.1.1
10497 * Copyright(c) 2006-2007, Ext JS, LLC.
10499 * Originally Released Under LGPL - original licence link has changed is not relivant.
10502 * <script type="text/javascript">
10506 * @class Roo.data.Record
10507 * Instances of this class encapsulate both record <em>definition</em> information, and record
10508 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10509 * to access Records cached in an {@link Roo.data.Store} object.<br>
10511 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10512 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10515 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10517 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10518 * {@link #create}. The parameters are the same.
10519 * @param {Array} data An associative Array of data values keyed by the field name.
10520 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10521 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10522 * not specified an integer id is generated.
10524 Roo.data.Record = function(data, id){
10525 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10530 * Generate a constructor for a specific record layout.
10531 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10532 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10533 * Each field definition object may contain the following properties: <ul>
10534 * <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,
10535 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10536 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10537 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10538 * is being used, then this is a string containing the javascript expression to reference the data relative to
10539 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10540 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10541 * this may be omitted.</p></li>
10542 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10543 * <ul><li>auto (Default, implies no conversion)</li>
10548 * <li>date</li></ul></p></li>
10549 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10550 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10551 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10552 * by the Reader into an object that will be stored in the Record. It is passed the
10553 * following parameters:<ul>
10554 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10556 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10558 * <br>usage:<br><pre><code>
10559 var TopicRecord = Roo.data.Record.create(
10560 {name: 'title', mapping: 'topic_title'},
10561 {name: 'author', mapping: 'username'},
10562 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10563 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10564 {name: 'lastPoster', mapping: 'user2'},
10565 {name: 'excerpt', mapping: 'post_text'}
10568 var myNewRecord = new TopicRecord({
10569 title: 'Do my job please',
10572 lastPost: new Date(),
10573 lastPoster: 'Animal',
10574 excerpt: 'No way dude!'
10576 myStore.add(myNewRecord);
10581 Roo.data.Record.create = function(o){
10582 var f = function(){
10583 f.superclass.constructor.apply(this, arguments);
10585 Roo.extend(f, Roo.data.Record);
10586 var p = f.prototype;
10587 p.fields = new Roo.util.MixedCollection(false, function(field){
10590 for(var i = 0, len = o.length; i < len; i++){
10591 p.fields.add(new Roo.data.Field(o[i]));
10593 f.getField = function(name){
10594 return p.fields.get(name);
10599 Roo.data.Record.AUTO_ID = 1000;
10600 Roo.data.Record.EDIT = 'edit';
10601 Roo.data.Record.REJECT = 'reject';
10602 Roo.data.Record.COMMIT = 'commit';
10604 Roo.data.Record.prototype = {
10606 * Readonly flag - true if this record has been modified.
10615 join : function(store){
10616 this.store = store;
10620 * Set the named field to the specified value.
10621 * @param {String} name The name of the field to set.
10622 * @param {Object} value The value to set the field to.
10624 set : function(name, value){
10625 if(this.data[name] == value){
10629 if(!this.modified){
10630 this.modified = {};
10632 if(typeof this.modified[name] == 'undefined'){
10633 this.modified[name] = this.data[name];
10635 this.data[name] = value;
10636 if(!this.editing && this.store){
10637 this.store.afterEdit(this);
10642 * Get the value of the named field.
10643 * @param {String} name The name of the field to get the value of.
10644 * @return {Object} The value of the field.
10646 get : function(name){
10647 return this.data[name];
10651 beginEdit : function(){
10652 this.editing = true;
10653 this.modified = {};
10657 cancelEdit : function(){
10658 this.editing = false;
10659 delete this.modified;
10663 endEdit : function(){
10664 this.editing = false;
10665 if(this.dirty && this.store){
10666 this.store.afterEdit(this);
10671 * Usually called by the {@link Roo.data.Store} which owns the Record.
10672 * Rejects all changes made to the Record since either creation, or the last commit operation.
10673 * Modified fields are reverted to their original values.
10675 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10676 * of reject operations.
10678 reject : function(){
10679 var m = this.modified;
10681 if(typeof m[n] != "function"){
10682 this.data[n] = m[n];
10685 this.dirty = false;
10686 delete this.modified;
10687 this.editing = false;
10689 this.store.afterReject(this);
10694 * Usually called by the {@link Roo.data.Store} which owns the Record.
10695 * Commits all changes made to the Record since either creation, or the last commit operation.
10697 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10698 * of commit operations.
10700 commit : function(){
10701 this.dirty = false;
10702 delete this.modified;
10703 this.editing = false;
10705 this.store.afterCommit(this);
10710 hasError : function(){
10711 return this.error != null;
10715 clearError : function(){
10720 * Creates a copy of this record.
10721 * @param {String} id (optional) A new record id if you don't want to use this record's id
10724 copy : function(newId) {
10725 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10729 * Ext JS Library 1.1.1
10730 * Copyright(c) 2006-2007, Ext JS, LLC.
10732 * Originally Released Under LGPL - original licence link has changed is not relivant.
10735 * <script type="text/javascript">
10741 * @class Roo.data.Store
10742 * @extends Roo.util.Observable
10743 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10744 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10746 * 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
10747 * has no knowledge of the format of the data returned by the Proxy.<br>
10749 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10750 * instances from the data object. These records are cached and made available through accessor functions.
10752 * Creates a new Store.
10753 * @param {Object} config A config object containing the objects needed for the Store to access data,
10754 * and read the data into Records.
10756 Roo.data.Store = function(config){
10757 this.data = new Roo.util.MixedCollection(false);
10758 this.data.getKey = function(o){
10761 this.baseParams = {};
10763 this.paramNames = {
10768 "multisort" : "_multisort"
10771 if(config && config.data){
10772 this.inlineData = config.data;
10773 delete config.data;
10776 Roo.apply(this, config);
10778 if(this.reader){ // reader passed
10779 this.reader = Roo.factory(this.reader, Roo.data);
10780 this.reader.xmodule = this.xmodule || false;
10781 if(!this.recordType){
10782 this.recordType = this.reader.recordType;
10784 if(this.reader.onMetaChange){
10785 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10789 if(this.recordType){
10790 this.fields = this.recordType.prototype.fields;
10792 this.modified = [];
10796 * @event datachanged
10797 * Fires when the data cache has changed, and a widget which is using this Store
10798 * as a Record cache should refresh its view.
10799 * @param {Store} this
10801 datachanged : true,
10803 * @event metachange
10804 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10805 * @param {Store} this
10806 * @param {Object} meta The JSON metadata
10811 * Fires when Records have been added to the Store
10812 * @param {Store} this
10813 * @param {Roo.data.Record[]} records The array of Records added
10814 * @param {Number} index The index at which the record(s) were added
10819 * Fires when a Record has been removed from the Store
10820 * @param {Store} this
10821 * @param {Roo.data.Record} record The Record that was removed
10822 * @param {Number} index The index at which the record was removed
10827 * Fires when a Record has been updated
10828 * @param {Store} this
10829 * @param {Roo.data.Record} record The Record that was updated
10830 * @param {String} operation The update operation being performed. Value may be one of:
10832 Roo.data.Record.EDIT
10833 Roo.data.Record.REJECT
10834 Roo.data.Record.COMMIT
10840 * Fires when the data cache has been cleared.
10841 * @param {Store} this
10845 * @event beforeload
10846 * Fires before a request is made for a new data object. If the beforeload handler returns false
10847 * the load action will be canceled.
10848 * @param {Store} this
10849 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10853 * @event beforeloadadd
10854 * Fires after a new set of Records has been loaded.
10855 * @param {Store} this
10856 * @param {Roo.data.Record[]} records The Records that were loaded
10857 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10859 beforeloadadd : true,
10862 * Fires after a new set of Records has been loaded, before they are added to the store.
10863 * @param {Store} this
10864 * @param {Roo.data.Record[]} records The Records that were loaded
10865 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10866 * @params {Object} return from reader
10870 * @event loadexception
10871 * Fires if an exception occurs in the Proxy during loading.
10872 * Called with the signature of the Proxy's "loadexception" event.
10873 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10876 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10877 * @param {Object} load options
10878 * @param {Object} jsonData from your request (normally this contains the Exception)
10880 loadexception : true
10884 this.proxy = Roo.factory(this.proxy, Roo.data);
10885 this.proxy.xmodule = this.xmodule || false;
10886 this.relayEvents(this.proxy, ["loadexception"]);
10888 this.sortToggle = {};
10889 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10891 Roo.data.Store.superclass.constructor.call(this);
10893 if(this.inlineData){
10894 this.loadData(this.inlineData);
10895 delete this.inlineData;
10899 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10901 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10902 * without a remote query - used by combo/forms at present.
10906 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10909 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10912 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10913 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10916 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10917 * on any HTTP request
10920 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10923 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10927 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10928 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10930 remoteSort : false,
10933 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10934 * loaded or when a record is removed. (defaults to false).
10936 pruneModifiedRecords : false,
10939 lastOptions : null,
10942 * Add Records to the Store and fires the add event.
10943 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10945 add : function(records){
10946 records = [].concat(records);
10947 for(var i = 0, len = records.length; i < len; i++){
10948 records[i].join(this);
10950 var index = this.data.length;
10951 this.data.addAll(records);
10952 this.fireEvent("add", this, records, index);
10956 * Remove a Record from the Store and fires the remove event.
10957 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10959 remove : function(record){
10960 var index = this.data.indexOf(record);
10961 this.data.removeAt(index);
10962 if(this.pruneModifiedRecords){
10963 this.modified.remove(record);
10965 this.fireEvent("remove", this, record, index);
10969 * Remove all Records from the Store and fires the clear event.
10971 removeAll : function(){
10973 if(this.pruneModifiedRecords){
10974 this.modified = [];
10976 this.fireEvent("clear", this);
10980 * Inserts Records to the Store at the given index and fires the add event.
10981 * @param {Number} index The start index at which to insert the passed Records.
10982 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10984 insert : function(index, records){
10985 records = [].concat(records);
10986 for(var i = 0, len = records.length; i < len; i++){
10987 this.data.insert(index, records[i]);
10988 records[i].join(this);
10990 this.fireEvent("add", this, records, index);
10994 * Get the index within the cache of the passed Record.
10995 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10996 * @return {Number} The index of the passed Record. Returns -1 if not found.
10998 indexOf : function(record){
10999 return this.data.indexOf(record);
11003 * Get the index within the cache of the Record with the passed id.
11004 * @param {String} id The id of the Record to find.
11005 * @return {Number} The index of the Record. Returns -1 if not found.
11007 indexOfId : function(id){
11008 return this.data.indexOfKey(id);
11012 * Get the Record with the specified id.
11013 * @param {String} id The id of the Record to find.
11014 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11016 getById : function(id){
11017 return this.data.key(id);
11021 * Get the Record at the specified index.
11022 * @param {Number} index The index of the Record to find.
11023 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11025 getAt : function(index){
11026 return this.data.itemAt(index);
11030 * Returns a range of Records between specified indices.
11031 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11032 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11033 * @return {Roo.data.Record[]} An array of Records
11035 getRange : function(start, end){
11036 return this.data.getRange(start, end);
11040 storeOptions : function(o){
11041 o = Roo.apply({}, o);
11044 this.lastOptions = o;
11048 * Loads the Record cache from the configured Proxy using the configured Reader.
11050 * If using remote paging, then the first load call must specify the <em>start</em>
11051 * and <em>limit</em> properties in the options.params property to establish the initial
11052 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11054 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11055 * and this call will return before the new data has been loaded. Perform any post-processing
11056 * in a callback function, or in a "load" event handler.</strong>
11058 * @param {Object} options An object containing properties which control loading options:<ul>
11059 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11060 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11061 * passed the following arguments:<ul>
11062 * <li>r : Roo.data.Record[]</li>
11063 * <li>options: Options object from the load call</li>
11064 * <li>success: Boolean success indicator</li></ul></li>
11065 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11066 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11069 load : function(options){
11070 options = options || {};
11071 if(this.fireEvent("beforeload", this, options) !== false){
11072 this.storeOptions(options);
11073 var p = Roo.apply(options.params || {}, this.baseParams);
11074 // if meta was not loaded from remote source.. try requesting it.
11075 if (!this.reader.metaFromRemote) {
11076 p._requestMeta = 1;
11078 if(this.sortInfo && this.remoteSort){
11079 var pn = this.paramNames;
11080 p[pn["sort"]] = this.sortInfo.field;
11081 p[pn["dir"]] = this.sortInfo.direction;
11083 if (this.multiSort) {
11084 var pn = this.paramNames;
11085 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11088 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11093 * Reloads the Record cache from the configured Proxy using the configured Reader and
11094 * the options from the last load operation performed.
11095 * @param {Object} options (optional) An object containing properties which may override the options
11096 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11097 * the most recently used options are reused).
11099 reload : function(options){
11100 this.load(Roo.applyIf(options||{}, this.lastOptions));
11104 // Called as a callback by the Reader during a load operation.
11105 loadRecords : function(o, options, success){
11106 if(!o || success === false){
11107 if(success !== false){
11108 this.fireEvent("load", this, [], options, o);
11110 if(options.callback){
11111 options.callback.call(options.scope || this, [], options, false);
11115 // if data returned failure - throw an exception.
11116 if (o.success === false) {
11117 // show a message if no listener is registered.
11118 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11119 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11121 // loadmask wil be hooked into this..
11122 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11125 var r = o.records, t = o.totalRecords || r.length;
11127 this.fireEvent("beforeloadadd", this, r, options, o);
11129 if(!options || options.add !== true){
11130 if(this.pruneModifiedRecords){
11131 this.modified = [];
11133 for(var i = 0, len = r.length; i < len; i++){
11137 this.data = this.snapshot;
11138 delete this.snapshot;
11141 this.data.addAll(r);
11142 this.totalLength = t;
11144 this.fireEvent("datachanged", this);
11146 this.totalLength = Math.max(t, this.data.length+r.length);
11150 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11152 var e = new Roo.data.Record({});
11154 e.set(this.parent.displayField, this.parent.emptyTitle);
11155 e.set(this.parent.valueField, '');
11160 this.fireEvent("load", this, r, options, o);
11161 if(options.callback){
11162 options.callback.call(options.scope || this, r, options, true);
11168 * Loads data from a passed data block. A Reader which understands the format of the data
11169 * must have been configured in the constructor.
11170 * @param {Object} data The data block from which to read the Records. The format of the data expected
11171 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11172 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11174 loadData : function(o, append){
11175 var r = this.reader.readRecords(o);
11176 this.loadRecords(r, {add: append}, true);
11180 * Gets the number of cached records.
11182 * <em>If using paging, this may not be the total size of the dataset. If the data object
11183 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11184 * the data set size</em>
11186 getCount : function(){
11187 return this.data.length || 0;
11191 * Gets the total number of records in the dataset as returned by the server.
11193 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11194 * the dataset size</em>
11196 getTotalCount : function(){
11197 return this.totalLength || 0;
11201 * Returns the sort state of the Store as an object with two properties:
11203 field {String} The name of the field by which the Records are sorted
11204 direction {String} The sort order, "ASC" or "DESC"
11207 getSortState : function(){
11208 return this.sortInfo;
11212 applySort : function(){
11213 if(this.sortInfo && !this.remoteSort){
11214 var s = this.sortInfo, f = s.field;
11215 var st = this.fields.get(f).sortType;
11216 var fn = function(r1, r2){
11217 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11218 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11220 this.data.sort(s.direction, fn);
11221 if(this.snapshot && this.snapshot != this.data){
11222 this.snapshot.sort(s.direction, fn);
11228 * Sets the default sort column and order to be used by the next load operation.
11229 * @param {String} fieldName The name of the field to sort by.
11230 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11232 setDefaultSort : function(field, dir){
11233 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11237 * Sort the Records.
11238 * If remote sorting is used, the sort is performed on the server, and the cache is
11239 * reloaded. If local sorting is used, the cache is sorted internally.
11240 * @param {String} fieldName The name of the field to sort by.
11241 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11243 sort : function(fieldName, dir){
11244 var f = this.fields.get(fieldName);
11246 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11248 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11249 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11254 this.sortToggle[f.name] = dir;
11255 this.sortInfo = {field: f.name, direction: dir};
11256 if(!this.remoteSort){
11258 this.fireEvent("datachanged", this);
11260 this.load(this.lastOptions);
11265 * Calls the specified function for each of the Records in the cache.
11266 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11267 * Returning <em>false</em> aborts and exits the iteration.
11268 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11270 each : function(fn, scope){
11271 this.data.each(fn, scope);
11275 * Gets all records modified since the last commit. Modified records are persisted across load operations
11276 * (e.g., during paging).
11277 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11279 getModifiedRecords : function(){
11280 return this.modified;
11284 createFilterFn : function(property, value, anyMatch){
11285 if(!value.exec){ // not a regex
11286 value = String(value);
11287 if(value.length == 0){
11290 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11292 return function(r){
11293 return value.test(r.data[property]);
11298 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11299 * @param {String} property A field on your records
11300 * @param {Number} start The record index to start at (defaults to 0)
11301 * @param {Number} end The last record index to include (defaults to length - 1)
11302 * @return {Number} The sum
11304 sum : function(property, start, end){
11305 var rs = this.data.items, v = 0;
11306 start = start || 0;
11307 end = (end || end === 0) ? end : rs.length-1;
11309 for(var i = start; i <= end; i++){
11310 v += (rs[i].data[property] || 0);
11316 * Filter the records by a specified property.
11317 * @param {String} field A field on your records
11318 * @param {String/RegExp} value Either a string that the field
11319 * should start with or a RegExp to test against the field
11320 * @param {Boolean} anyMatch True to match any part not just the beginning
11322 filter : function(property, value, anyMatch){
11323 var fn = this.createFilterFn(property, value, anyMatch);
11324 return fn ? this.filterBy(fn) : this.clearFilter();
11328 * Filter by a function. The specified function will be called with each
11329 * record in this data source. If the function returns true the record is included,
11330 * otherwise it is filtered.
11331 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11332 * @param {Object} scope (optional) The scope of the function (defaults to this)
11334 filterBy : function(fn, scope){
11335 this.snapshot = this.snapshot || this.data;
11336 this.data = this.queryBy(fn, scope||this);
11337 this.fireEvent("datachanged", this);
11341 * Query the records by a specified property.
11342 * @param {String} field A field on your records
11343 * @param {String/RegExp} value Either a string that the field
11344 * should start with or a RegExp to test against the field
11345 * @param {Boolean} anyMatch True to match any part not just the beginning
11346 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11348 query : function(property, value, anyMatch){
11349 var fn = this.createFilterFn(property, value, anyMatch);
11350 return fn ? this.queryBy(fn) : this.data.clone();
11354 * Query by a function. The specified function will be called with each
11355 * record in this data source. If the function returns true the record is included
11357 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11358 * @param {Object} scope (optional) The scope of the function (defaults to this)
11359 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11361 queryBy : function(fn, scope){
11362 var data = this.snapshot || this.data;
11363 return data.filterBy(fn, scope||this);
11367 * Collects unique values for a particular dataIndex from this store.
11368 * @param {String} dataIndex The property to collect
11369 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11370 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11371 * @return {Array} An array of the unique values
11373 collect : function(dataIndex, allowNull, bypassFilter){
11374 var d = (bypassFilter === true && this.snapshot) ?
11375 this.snapshot.items : this.data.items;
11376 var v, sv, r = [], l = {};
11377 for(var i = 0, len = d.length; i < len; i++){
11378 v = d[i].data[dataIndex];
11380 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11389 * Revert to a view of the Record cache with no filtering applied.
11390 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11392 clearFilter : function(suppressEvent){
11393 if(this.snapshot && this.snapshot != this.data){
11394 this.data = this.snapshot;
11395 delete this.snapshot;
11396 if(suppressEvent !== true){
11397 this.fireEvent("datachanged", this);
11403 afterEdit : function(record){
11404 if(this.modified.indexOf(record) == -1){
11405 this.modified.push(record);
11407 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11411 afterReject : function(record){
11412 this.modified.remove(record);
11413 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11417 afterCommit : function(record){
11418 this.modified.remove(record);
11419 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11423 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11424 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11426 commitChanges : function(){
11427 var m = this.modified.slice(0);
11428 this.modified = [];
11429 for(var i = 0, len = m.length; i < len; i++){
11435 * Cancel outstanding changes on all changed records.
11437 rejectChanges : function(){
11438 var m = this.modified.slice(0);
11439 this.modified = [];
11440 for(var i = 0, len = m.length; i < len; i++){
11445 onMetaChange : function(meta, rtype, o){
11446 this.recordType = rtype;
11447 this.fields = rtype.prototype.fields;
11448 delete this.snapshot;
11449 this.sortInfo = meta.sortInfo || this.sortInfo;
11450 this.modified = [];
11451 this.fireEvent('metachange', this, this.reader.meta);
11454 moveIndex : function(data, type)
11456 var index = this.indexOf(data);
11458 var newIndex = index + type;
11462 this.insert(newIndex, data);
11467 * Ext JS Library 1.1.1
11468 * Copyright(c) 2006-2007, Ext JS, LLC.
11470 * Originally Released Under LGPL - original licence link has changed is not relivant.
11473 * <script type="text/javascript">
11477 * @class Roo.data.SimpleStore
11478 * @extends Roo.data.Store
11479 * Small helper class to make creating Stores from Array data easier.
11480 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11481 * @cfg {Array} fields An array of field definition objects, or field name strings.
11482 * @cfg {Array} data The multi-dimensional array of data
11484 * @param {Object} config
11486 Roo.data.SimpleStore = function(config){
11487 Roo.data.SimpleStore.superclass.constructor.call(this, {
11489 reader: new Roo.data.ArrayReader({
11492 Roo.data.Record.create(config.fields)
11494 proxy : new Roo.data.MemoryProxy(config.data)
11498 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11500 * Ext JS Library 1.1.1
11501 * Copyright(c) 2006-2007, Ext JS, LLC.
11503 * Originally Released Under LGPL - original licence link has changed is not relivant.
11506 * <script type="text/javascript">
11511 * @extends Roo.data.Store
11512 * @class Roo.data.JsonStore
11513 * Small helper class to make creating Stores for JSON data easier. <br/>
11515 var store = new Roo.data.JsonStore({
11516 url: 'get-images.php',
11518 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11521 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11522 * JsonReader and HttpProxy (unless inline data is provided).</b>
11523 * @cfg {Array} fields An array of field definition objects, or field name strings.
11525 * @param {Object} config
11527 Roo.data.JsonStore = function(c){
11528 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11529 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11530 reader: new Roo.data.JsonReader(c, c.fields)
11533 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11535 * Ext JS Library 1.1.1
11536 * Copyright(c) 2006-2007, Ext JS, LLC.
11538 * Originally Released Under LGPL - original licence link has changed is not relivant.
11541 * <script type="text/javascript">
11545 Roo.data.Field = function(config){
11546 if(typeof config == "string"){
11547 config = {name: config};
11549 Roo.apply(this, config);
11552 this.type = "auto";
11555 var st = Roo.data.SortTypes;
11556 // named sortTypes are supported, here we look them up
11557 if(typeof this.sortType == "string"){
11558 this.sortType = st[this.sortType];
11561 // set default sortType for strings and dates
11562 if(!this.sortType){
11565 this.sortType = st.asUCString;
11568 this.sortType = st.asDate;
11571 this.sortType = st.none;
11576 var stripRe = /[\$,%]/g;
11578 // prebuilt conversion function for this field, instead of
11579 // switching every time we're reading a value
11581 var cv, dateFormat = this.dateFormat;
11586 cv = function(v){ return v; };
11589 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11593 return v !== undefined && v !== null && v !== '' ?
11594 parseInt(String(v).replace(stripRe, ""), 10) : '';
11599 return v !== undefined && v !== null && v !== '' ?
11600 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11605 cv = function(v){ return v === true || v === "true" || v == 1; };
11612 if(v instanceof Date){
11616 if(dateFormat == "timestamp"){
11617 return new Date(v*1000);
11619 return Date.parseDate(v, dateFormat);
11621 var parsed = Date.parse(v);
11622 return parsed ? new Date(parsed) : null;
11631 Roo.data.Field.prototype = {
11639 * Ext JS Library 1.1.1
11640 * Copyright(c) 2006-2007, Ext JS, LLC.
11642 * Originally Released Under LGPL - original licence link has changed is not relivant.
11645 * <script type="text/javascript">
11648 // Base class for reading structured data from a data source. This class is intended to be
11649 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11652 * @class Roo.data.DataReader
11653 * Base class for reading structured data from a data source. This class is intended to be
11654 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11657 Roo.data.DataReader = function(meta, recordType){
11661 this.recordType = recordType instanceof Array ?
11662 Roo.data.Record.create(recordType) : recordType;
11665 Roo.data.DataReader.prototype = {
11667 * Create an empty record
11668 * @param {Object} data (optional) - overlay some values
11669 * @return {Roo.data.Record} record created.
11671 newRow : function(d) {
11673 this.recordType.prototype.fields.each(function(c) {
11675 case 'int' : da[c.name] = 0; break;
11676 case 'date' : da[c.name] = new Date(); break;
11677 case 'float' : da[c.name] = 0.0; break;
11678 case 'boolean' : da[c.name] = false; break;
11679 default : da[c.name] = ""; break;
11683 return new this.recordType(Roo.apply(da, d));
11688 * Ext JS Library 1.1.1
11689 * Copyright(c) 2006-2007, Ext JS, LLC.
11691 * Originally Released Under LGPL - original licence link has changed is not relivant.
11694 * <script type="text/javascript">
11698 * @class Roo.data.DataProxy
11699 * @extends Roo.data.Observable
11700 * This class is an abstract base class for implementations which provide retrieval of
11701 * unformatted data objects.<br>
11703 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11704 * (of the appropriate type which knows how to parse the data object) to provide a block of
11705 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11707 * Custom implementations must implement the load method as described in
11708 * {@link Roo.data.HttpProxy#load}.
11710 Roo.data.DataProxy = function(){
11713 * @event beforeload
11714 * Fires before a network request is made to retrieve a data object.
11715 * @param {Object} This DataProxy object.
11716 * @param {Object} params The params parameter to the load function.
11721 * Fires before the load method's callback is called.
11722 * @param {Object} This DataProxy object.
11723 * @param {Object} o The data object.
11724 * @param {Object} arg The callback argument object passed to the load function.
11728 * @event loadexception
11729 * Fires if an Exception occurs during data retrieval.
11730 * @param {Object} This DataProxy object.
11731 * @param {Object} o The data object.
11732 * @param {Object} arg The callback argument object passed to the load function.
11733 * @param {Object} e The Exception.
11735 loadexception : true
11737 Roo.data.DataProxy.superclass.constructor.call(this);
11740 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11743 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11747 * Ext JS Library 1.1.1
11748 * Copyright(c) 2006-2007, Ext JS, LLC.
11750 * Originally Released Under LGPL - original licence link has changed is not relivant.
11753 * <script type="text/javascript">
11756 * @class Roo.data.MemoryProxy
11757 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11758 * to the Reader when its load method is called.
11760 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11762 Roo.data.MemoryProxy = function(data){
11766 Roo.data.MemoryProxy.superclass.constructor.call(this);
11770 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11773 * Load data from the requested source (in this case an in-memory
11774 * data object passed to the constructor), read the data object into
11775 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11776 * process that block using the passed callback.
11777 * @param {Object} params This parameter is not used by the MemoryProxy class.
11778 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11779 * object into a block of Roo.data.Records.
11780 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11781 * The function must be passed <ul>
11782 * <li>The Record block object</li>
11783 * <li>The "arg" argument from the load function</li>
11784 * <li>A boolean success indicator</li>
11786 * @param {Object} scope The scope in which to call the callback
11787 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11789 load : function(params, reader, callback, scope, arg){
11790 params = params || {};
11793 result = reader.readRecords(this.data);
11795 this.fireEvent("loadexception", this, arg, null, e);
11796 callback.call(scope, null, arg, false);
11799 callback.call(scope, result, arg, true);
11803 update : function(params, records){
11808 * Ext JS Library 1.1.1
11809 * Copyright(c) 2006-2007, Ext JS, LLC.
11811 * Originally Released Under LGPL - original licence link has changed is not relivant.
11814 * <script type="text/javascript">
11817 * @class Roo.data.HttpProxy
11818 * @extends Roo.data.DataProxy
11819 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11820 * configured to reference a certain URL.<br><br>
11822 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11823 * from which the running page was served.<br><br>
11825 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11827 * Be aware that to enable the browser to parse an XML document, the server must set
11828 * the Content-Type header in the HTTP response to "text/xml".
11830 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11831 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11832 * will be used to make the request.
11834 Roo.data.HttpProxy = function(conn){
11835 Roo.data.HttpProxy.superclass.constructor.call(this);
11836 // is conn a conn config or a real conn?
11838 this.useAjax = !conn || !conn.events;
11842 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11843 // thse are take from connection...
11846 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11849 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11850 * extra parameters to each request made by this object. (defaults to undefined)
11853 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11854 * to each request made by this object. (defaults to undefined)
11857 * @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)
11860 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11863 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11869 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11873 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11874 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11875 * a finer-grained basis than the DataProxy events.
11877 getConnection : function(){
11878 return this.useAjax ? Roo.Ajax : this.conn;
11882 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11883 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11884 * process that block using the passed callback.
11885 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11886 * for the request to the remote server.
11887 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11888 * object into a block of Roo.data.Records.
11889 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11890 * The function must be passed <ul>
11891 * <li>The Record block object</li>
11892 * <li>The "arg" argument from the load function</li>
11893 * <li>A boolean success indicator</li>
11895 * @param {Object} scope The scope in which to call the callback
11896 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11898 load : function(params, reader, callback, scope, arg){
11899 if(this.fireEvent("beforeload", this, params) !== false){
11901 params : params || {},
11903 callback : callback,
11908 callback : this.loadResponse,
11912 Roo.applyIf(o, this.conn);
11913 if(this.activeRequest){
11914 Roo.Ajax.abort(this.activeRequest);
11916 this.activeRequest = Roo.Ajax.request(o);
11918 this.conn.request(o);
11921 callback.call(scope||this, null, arg, false);
11926 loadResponse : function(o, success, response){
11927 delete this.activeRequest;
11929 this.fireEvent("loadexception", this, o, response);
11930 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11935 result = o.reader.read(response);
11937 this.fireEvent("loadexception", this, o, response, e);
11938 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11942 this.fireEvent("load", this, o, o.request.arg);
11943 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11947 update : function(dataSet){
11952 updateResponse : function(dataSet){
11957 * Ext JS Library 1.1.1
11958 * Copyright(c) 2006-2007, Ext JS, LLC.
11960 * Originally Released Under LGPL - original licence link has changed is not relivant.
11963 * <script type="text/javascript">
11967 * @class Roo.data.ScriptTagProxy
11968 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11969 * other than the originating domain of the running page.<br><br>
11971 * <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
11972 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11974 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11975 * source code that is used as the source inside a <script> tag.<br><br>
11977 * In order for the browser to process the returned data, the server must wrap the data object
11978 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11979 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11980 * depending on whether the callback name was passed:
11983 boolean scriptTag = false;
11984 String cb = request.getParameter("callback");
11987 response.setContentType("text/javascript");
11989 response.setContentType("application/x-json");
11991 Writer out = response.getWriter();
11993 out.write(cb + "(");
11995 out.print(dataBlock.toJsonString());
12002 * @param {Object} config A configuration object.
12004 Roo.data.ScriptTagProxy = function(config){
12005 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12006 Roo.apply(this, config);
12007 this.head = document.getElementsByTagName("head")[0];
12010 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12012 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12014 * @cfg {String} url The URL from which to request the data object.
12017 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12021 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12022 * the server the name of the callback function set up by the load call to process the returned data object.
12023 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12024 * javascript output which calls this named function passing the data object as its only parameter.
12026 callbackParam : "callback",
12028 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12029 * name to the request.
12034 * Load data from the configured URL, read the data object into
12035 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12036 * process that block using the passed callback.
12037 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12038 * for the request to the remote server.
12039 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12040 * object into a block of Roo.data.Records.
12041 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12042 * The function must be passed <ul>
12043 * <li>The Record block object</li>
12044 * <li>The "arg" argument from the load function</li>
12045 * <li>A boolean success indicator</li>
12047 * @param {Object} scope The scope in which to call the callback
12048 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12050 load : function(params, reader, callback, scope, arg){
12051 if(this.fireEvent("beforeload", this, params) !== false){
12053 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12055 var url = this.url;
12056 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12058 url += "&_dc=" + (new Date().getTime());
12060 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12063 cb : "stcCallback"+transId,
12064 scriptId : "stcScript"+transId,
12068 callback : callback,
12074 window[trans.cb] = function(o){
12075 conn.handleResponse(o, trans);
12078 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12080 if(this.autoAbort !== false){
12084 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12086 var script = document.createElement("script");
12087 script.setAttribute("src", url);
12088 script.setAttribute("type", "text/javascript");
12089 script.setAttribute("id", trans.scriptId);
12090 this.head.appendChild(script);
12092 this.trans = trans;
12094 callback.call(scope||this, null, arg, false);
12099 isLoading : function(){
12100 return this.trans ? true : false;
12104 * Abort the current server request.
12106 abort : function(){
12107 if(this.isLoading()){
12108 this.destroyTrans(this.trans);
12113 destroyTrans : function(trans, isLoaded){
12114 this.head.removeChild(document.getElementById(trans.scriptId));
12115 clearTimeout(trans.timeoutId);
12117 window[trans.cb] = undefined;
12119 delete window[trans.cb];
12122 // if hasn't been loaded, wait for load to remove it to prevent script error
12123 window[trans.cb] = function(){
12124 window[trans.cb] = undefined;
12126 delete window[trans.cb];
12133 handleResponse : function(o, trans){
12134 this.trans = false;
12135 this.destroyTrans(trans, true);
12138 result = trans.reader.readRecords(o);
12140 this.fireEvent("loadexception", this, o, trans.arg, e);
12141 trans.callback.call(trans.scope||window, null, trans.arg, false);
12144 this.fireEvent("load", this, o, trans.arg);
12145 trans.callback.call(trans.scope||window, result, trans.arg, true);
12149 handleFailure : function(trans){
12150 this.trans = false;
12151 this.destroyTrans(trans, false);
12152 this.fireEvent("loadexception", this, null, trans.arg);
12153 trans.callback.call(trans.scope||window, null, trans.arg, false);
12157 * Ext JS Library 1.1.1
12158 * Copyright(c) 2006-2007, Ext JS, LLC.
12160 * Originally Released Under LGPL - original licence link has changed is not relivant.
12163 * <script type="text/javascript">
12167 * @class Roo.data.JsonReader
12168 * @extends Roo.data.DataReader
12169 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12170 * based on mappings in a provided Roo.data.Record constructor.
12172 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12173 * in the reply previously.
12178 var RecordDef = Roo.data.Record.create([
12179 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12180 {name: 'occupation'} // This field will use "occupation" as the mapping.
12182 var myReader = new Roo.data.JsonReader({
12183 totalProperty: "results", // The property which contains the total dataset size (optional)
12184 root: "rows", // The property which contains an Array of row objects
12185 id: "id" // The property within each row object that provides an ID for the record (optional)
12189 * This would consume a JSON file like this:
12191 { 'results': 2, 'rows': [
12192 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12193 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12196 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12197 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12198 * paged from the remote server.
12199 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12200 * @cfg {String} root name of the property which contains the Array of row objects.
12201 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12202 * @cfg {Array} fields Array of field definition objects
12204 * Create a new JsonReader
12205 * @param {Object} meta Metadata configuration options
12206 * @param {Object} recordType Either an Array of field definition objects,
12207 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12209 Roo.data.JsonReader = function(meta, recordType){
12212 // set some defaults:
12213 Roo.applyIf(meta, {
12214 totalProperty: 'total',
12215 successProperty : 'success',
12220 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12222 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12225 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12226 * Used by Store query builder to append _requestMeta to params.
12229 metaFromRemote : false,
12231 * This method is only used by a DataProxy which has retrieved data from a remote server.
12232 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12233 * @return {Object} data A data block which is used by an Roo.data.Store object as
12234 * a cache of Roo.data.Records.
12236 read : function(response){
12237 var json = response.responseText;
12239 var o = /* eval:var:o */ eval("("+json+")");
12241 throw {message: "JsonReader.read: Json object not found"};
12247 this.metaFromRemote = true;
12248 this.meta = o.metaData;
12249 this.recordType = Roo.data.Record.create(o.metaData.fields);
12250 this.onMetaChange(this.meta, this.recordType, o);
12252 return this.readRecords(o);
12255 // private function a store will implement
12256 onMetaChange : function(meta, recordType, o){
12263 simpleAccess: function(obj, subsc) {
12270 getJsonAccessor: function(){
12272 return function(expr) {
12274 return(re.test(expr))
12275 ? new Function("obj", "return obj." + expr)
12280 return Roo.emptyFn;
12285 * Create a data block containing Roo.data.Records from an XML document.
12286 * @param {Object} o An object which contains an Array of row objects in the property specified
12287 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12288 * which contains the total size of the dataset.
12289 * @return {Object} data A data block which is used by an Roo.data.Store object as
12290 * a cache of Roo.data.Records.
12292 readRecords : function(o){
12294 * After any data loads, the raw JSON data is available for further custom processing.
12298 var s = this.meta, Record = this.recordType,
12299 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12301 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12303 if(s.totalProperty) {
12304 this.getTotal = this.getJsonAccessor(s.totalProperty);
12306 if(s.successProperty) {
12307 this.getSuccess = this.getJsonAccessor(s.successProperty);
12309 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12311 var g = this.getJsonAccessor(s.id);
12312 this.getId = function(rec) {
12314 return (r === undefined || r === "") ? null : r;
12317 this.getId = function(){return null;};
12320 for(var jj = 0; jj < fl; jj++){
12322 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12323 this.ef[jj] = this.getJsonAccessor(map);
12327 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12328 if(s.totalProperty){
12329 var vt = parseInt(this.getTotal(o), 10);
12334 if(s.successProperty){
12335 var vs = this.getSuccess(o);
12336 if(vs === false || vs === 'false'){
12341 for(var i = 0; i < c; i++){
12344 var id = this.getId(n);
12345 for(var j = 0; j < fl; j++){
12347 var v = this.ef[j](n);
12349 Roo.log('missing convert for ' + f.name);
12353 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12355 var record = new Record(values, id);
12357 records[i] = record;
12363 totalRecords : totalRecords
12368 * Ext JS Library 1.1.1
12369 * Copyright(c) 2006-2007, Ext JS, LLC.
12371 * Originally Released Under LGPL - original licence link has changed is not relivant.
12374 * <script type="text/javascript">
12378 * @class Roo.data.ArrayReader
12379 * @extends Roo.data.DataReader
12380 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12381 * Each element of that Array represents a row of data fields. The
12382 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12383 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12387 var RecordDef = Roo.data.Record.create([
12388 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12389 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12391 var myReader = new Roo.data.ArrayReader({
12392 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12396 * This would consume an Array like this:
12398 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12400 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12402 * Create a new JsonReader
12403 * @param {Object} meta Metadata configuration options.
12404 * @param {Object} recordType Either an Array of field definition objects
12405 * as specified to {@link Roo.data.Record#create},
12406 * or an {@link Roo.data.Record} object
12407 * created using {@link Roo.data.Record#create}.
12409 Roo.data.ArrayReader = function(meta, recordType){
12410 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12413 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12415 * Create a data block containing Roo.data.Records from an XML document.
12416 * @param {Object} o An Array of row objects which represents the dataset.
12417 * @return {Object} data A data block which is used by an Roo.data.Store object as
12418 * a cache of Roo.data.Records.
12420 readRecords : function(o){
12421 var sid = this.meta ? this.meta.id : null;
12422 var recordType = this.recordType, fields = recordType.prototype.fields;
12425 for(var i = 0; i < root.length; i++){
12428 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12429 for(var j = 0, jlen = fields.length; j < jlen; j++){
12430 var f = fields.items[j];
12431 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12432 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12434 values[f.name] = v;
12436 var record = new recordType(values, id);
12438 records[records.length] = record;
12442 totalRecords : records.length
12451 * @class Roo.bootstrap.ComboBox
12452 * @extends Roo.bootstrap.TriggerField
12453 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12454 * @cfg {Boolean} append (true|false) default false
12455 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12456 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12457 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12458 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12459 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12460 * @cfg {Boolean} animate default true
12461 * @cfg {Boolean} emptyResultText only for touch device
12462 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12463 * @cfg {String} emptyTitle default ''
12465 * Create a new ComboBox.
12466 * @param {Object} config Configuration options
12468 Roo.bootstrap.ComboBox = function(config){
12469 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12473 * Fires when the dropdown list is expanded
12474 * @param {Roo.bootstrap.ComboBox} combo This combo box
12479 * Fires when the dropdown list is collapsed
12480 * @param {Roo.bootstrap.ComboBox} combo This combo box
12484 * @event beforeselect
12485 * Fires before a list item is selected. Return false to cancel the selection.
12486 * @param {Roo.bootstrap.ComboBox} combo This combo box
12487 * @param {Roo.data.Record} record The data record returned from the underlying store
12488 * @param {Number} index The index of the selected item in the dropdown list
12490 'beforeselect' : true,
12493 * Fires when a list item is selected
12494 * @param {Roo.bootstrap.ComboBox} combo This combo box
12495 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12496 * @param {Number} index The index of the selected item in the dropdown list
12500 * @event beforequery
12501 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12502 * The event object passed has these properties:
12503 * @param {Roo.bootstrap.ComboBox} combo This combo box
12504 * @param {String} query The query
12505 * @param {Boolean} forceAll true to force "all" query
12506 * @param {Boolean} cancel true to cancel the query
12507 * @param {Object} e The query event object
12509 'beforequery': true,
12512 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12513 * @param {Roo.bootstrap.ComboBox} combo This combo box
12518 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12519 * @param {Roo.bootstrap.ComboBox} combo This combo box
12520 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12525 * Fires when the remove value from the combobox array
12526 * @param {Roo.bootstrap.ComboBox} combo This combo box
12530 * @event afterremove
12531 * Fires when the remove value from the combobox array
12532 * @param {Roo.bootstrap.ComboBox} combo This combo box
12534 'afterremove' : true,
12536 * @event specialfilter
12537 * Fires when specialfilter
12538 * @param {Roo.bootstrap.ComboBox} combo This combo box
12540 'specialfilter' : true,
12543 * Fires when tick the element
12544 * @param {Roo.bootstrap.ComboBox} combo This combo box
12548 * @event touchviewdisplay
12549 * Fires when touch view require special display (default is using displayField)
12550 * @param {Roo.bootstrap.ComboBox} combo This combo box
12551 * @param {Object} cfg set html .
12553 'touchviewdisplay' : true
12558 this.tickItems = [];
12560 this.selectedIndex = -1;
12561 if(this.mode == 'local'){
12562 if(config.queryDelay === undefined){
12563 this.queryDelay = 10;
12565 if(config.minChars === undefined){
12571 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12574 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12575 * rendering into an Roo.Editor, defaults to false)
12578 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12579 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12582 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12585 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12586 * the dropdown list (defaults to undefined, with no header element)
12590 * @cfg {String/Roo.Template} tpl The template to use to render the output
12594 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12596 listWidth: undefined,
12598 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12599 * mode = 'remote' or 'text' if mode = 'local')
12601 displayField: undefined,
12604 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12605 * mode = 'remote' or 'value' if mode = 'local').
12606 * Note: use of a valueField requires the user make a selection
12607 * in order for a value to be mapped.
12609 valueField: undefined,
12611 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12616 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12617 * field's data value (defaults to the underlying DOM element's name)
12619 hiddenName: undefined,
12621 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12625 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12627 selectedClass: 'active',
12630 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12634 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12635 * anchor positions (defaults to 'tl-bl')
12637 listAlign: 'tl-bl?',
12639 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12643 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12644 * query specified by the allQuery config option (defaults to 'query')
12646 triggerAction: 'query',
12648 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12649 * (defaults to 4, does not apply if editable = false)
12653 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12654 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12658 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12659 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12663 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12664 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12668 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12669 * when editable = true (defaults to false)
12671 selectOnFocus:false,
12673 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12675 queryParam: 'query',
12677 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12678 * when mode = 'remote' (defaults to 'Loading...')
12680 loadingText: 'Loading...',
12682 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12686 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12690 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12691 * traditional select (defaults to true)
12695 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12699 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12703 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12704 * listWidth has a higher value)
12708 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12709 * allow the user to set arbitrary text into the field (defaults to false)
12711 forceSelection:false,
12713 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12714 * if typeAhead = true (defaults to 250)
12716 typeAheadDelay : 250,
12718 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12719 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12721 valueNotFoundText : undefined,
12723 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12725 blockFocus : false,
12728 * @cfg {Boolean} disableClear Disable showing of clear button.
12730 disableClear : false,
12732 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12734 alwaysQuery : false,
12737 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12742 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12744 invalidClass : "has-warning",
12747 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12749 validClass : "has-success",
12752 * @cfg {Boolean} specialFilter (true|false) special filter default false
12754 specialFilter : false,
12757 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12759 mobileTouchView : true,
12762 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12764 useNativeIOS : false,
12766 ios_options : false,
12778 btnPosition : 'right',
12779 triggerList : true,
12780 showToggleBtn : true,
12782 emptyResultText: 'Empty',
12783 triggerText : 'Select',
12786 // element that contains real text value.. (when hidden is used..)
12788 getAutoCreate : function()
12793 * Render classic select for iso
12796 if(Roo.isIOS && this.useNativeIOS){
12797 cfg = this.getAutoCreateNativeIOS();
12805 if(Roo.isTouch && this.mobileTouchView){
12806 cfg = this.getAutoCreateTouchView();
12813 if(!this.tickable){
12814 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12819 * ComboBox with tickable selections
12822 var align = this.labelAlign || this.parentLabelAlign();
12825 cls : 'form-group roo-combobox-tickable' //input-group
12828 var btn_text_select = '';
12829 var btn_text_done = '';
12830 var btn_text_cancel = '';
12832 if (this.btn_text_show) {
12833 btn_text_select = 'Select';
12834 btn_text_done = 'Done';
12835 btn_text_cancel = 'Cancel';
12840 cls : 'tickable-buttons',
12845 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12846 //html : this.triggerText
12847 html: btn_text_select
12853 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12855 html: btn_text_done
12861 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12863 html: btn_text_cancel
12869 buttons.cn.unshift({
12871 cls: 'roo-select2-search-field-input'
12877 Roo.each(buttons.cn, function(c){
12879 c.cls += ' btn-' + _this.size;
12882 if (_this.disabled) {
12893 cls: 'form-hidden-field'
12897 cls: 'roo-select2-choices',
12901 cls: 'roo-select2-search-field',
12912 cls: 'roo-select2-container input-group roo-select2-container-multi',
12917 // cls: 'typeahead typeahead-long dropdown-menu',
12918 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12923 if(this.hasFeedback && !this.allowBlank){
12927 cls: 'glyphicon form-control-feedback'
12930 combobox.cn.push(feedback);
12934 if (align ==='left' && this.fieldLabel.length) {
12936 cfg.cls += ' roo-form-group-label-left';
12941 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12942 tooltip : 'This field is required'
12947 cls : 'control-label',
12948 html : this.fieldLabel
12960 var labelCfg = cfg.cn[1];
12961 var contentCfg = cfg.cn[2];
12964 if(this.indicatorpos == 'right'){
12970 cls : 'control-label',
12974 html : this.fieldLabel
12978 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12979 tooltip : 'This field is required'
12994 labelCfg = cfg.cn[0];
12995 contentCfg = cfg.cn[1];
12999 if(this.labelWidth > 12){
13000 labelCfg.style = "width: " + this.labelWidth + 'px';
13003 if(this.labelWidth < 13 && this.labelmd == 0){
13004 this.labelmd = this.labelWidth;
13007 if(this.labellg > 0){
13008 labelCfg.cls += ' col-lg-' + this.labellg;
13009 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13012 if(this.labelmd > 0){
13013 labelCfg.cls += ' col-md-' + this.labelmd;
13014 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13017 if(this.labelsm > 0){
13018 labelCfg.cls += ' col-sm-' + this.labelsm;
13019 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13022 if(this.labelxs > 0){
13023 labelCfg.cls += ' col-xs-' + this.labelxs;
13024 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13028 } else if ( this.fieldLabel.length) {
13029 // Roo.log(" label");
13033 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13034 tooltip : 'This field is required'
13038 //cls : 'input-group-addon',
13039 html : this.fieldLabel
13044 if(this.indicatorpos == 'right'){
13048 //cls : 'input-group-addon',
13049 html : this.fieldLabel
13053 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13054 tooltip : 'This field is required'
13063 // Roo.log(" no label && no align");
13070 ['xs','sm','md','lg'].map(function(size){
13071 if (settings[size]) {
13072 cfg.cls += ' col-' + size + '-' + settings[size];
13080 _initEventsCalled : false,
13083 initEvents: function()
13085 if (this._initEventsCalled) { // as we call render... prevent looping...
13088 this._initEventsCalled = true;
13091 throw "can not find store for combo";
13094 this.indicator = this.indicatorEl();
13096 this.store = Roo.factory(this.store, Roo.data);
13097 this.store.parent = this;
13099 // if we are building from html. then this element is so complex, that we can not really
13100 // use the rendered HTML.
13101 // so we have to trash and replace the previous code.
13102 if (Roo.XComponent.build_from_html) {
13103 // remove this element....
13104 var e = this.el.dom, k=0;
13105 while (e ) { e = e.previousSibling; ++k;}
13110 this.rendered = false;
13112 this.render(this.parent().getChildContainer(true), k);
13115 if(Roo.isIOS && this.useNativeIOS){
13116 this.initIOSView();
13124 if(Roo.isTouch && this.mobileTouchView){
13125 this.initTouchView();
13130 this.initTickableEvents();
13134 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13136 if(this.hiddenName){
13138 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13140 this.hiddenField.dom.value =
13141 this.hiddenValue !== undefined ? this.hiddenValue :
13142 this.value !== undefined ? this.value : '';
13144 // prevent input submission
13145 this.el.dom.removeAttribute('name');
13146 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13151 // this.el.dom.setAttribute('autocomplete', 'off');
13154 var cls = 'x-combo-list';
13156 //this.list = new Roo.Layer({
13157 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13163 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13164 _this.list.setWidth(lw);
13167 this.list.on('mouseover', this.onViewOver, this);
13168 this.list.on('mousemove', this.onViewMove, this);
13169 this.list.on('scroll', this.onViewScroll, this);
13172 this.list.swallowEvent('mousewheel');
13173 this.assetHeight = 0;
13176 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13177 this.assetHeight += this.header.getHeight();
13180 this.innerList = this.list.createChild({cls:cls+'-inner'});
13181 this.innerList.on('mouseover', this.onViewOver, this);
13182 this.innerList.on('mousemove', this.onViewMove, this);
13183 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13185 if(this.allowBlank && !this.pageSize && !this.disableClear){
13186 this.footer = this.list.createChild({cls:cls+'-ft'});
13187 this.pageTb = new Roo.Toolbar(this.footer);
13191 this.footer = this.list.createChild({cls:cls+'-ft'});
13192 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13193 {pageSize: this.pageSize});
13197 if (this.pageTb && this.allowBlank && !this.disableClear) {
13199 this.pageTb.add(new Roo.Toolbar.Fill(), {
13200 cls: 'x-btn-icon x-btn-clear',
13202 handler: function()
13205 _this.clearValue();
13206 _this.onSelect(false, -1);
13211 this.assetHeight += this.footer.getHeight();
13216 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13219 this.view = new Roo.View(this.list, this.tpl, {
13220 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13222 //this.view.wrapEl.setDisplayed(false);
13223 this.view.on('click', this.onViewClick, this);
13226 this.store.on('beforeload', this.onBeforeLoad, this);
13227 this.store.on('load', this.onLoad, this);
13228 this.store.on('loadexception', this.onLoadException, this);
13230 if(this.resizable){
13231 this.resizer = new Roo.Resizable(this.list, {
13232 pinned:true, handles:'se'
13234 this.resizer.on('resize', function(r, w, h){
13235 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13236 this.listWidth = w;
13237 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13238 this.restrictHeight();
13240 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13243 if(!this.editable){
13244 this.editable = true;
13245 this.setEditable(false);
13250 if (typeof(this.events.add.listeners) != 'undefined') {
13252 this.addicon = this.wrap.createChild(
13253 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13255 this.addicon.on('click', function(e) {
13256 this.fireEvent('add', this);
13259 if (typeof(this.events.edit.listeners) != 'undefined') {
13261 this.editicon = this.wrap.createChild(
13262 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13263 if (this.addicon) {
13264 this.editicon.setStyle('margin-left', '40px');
13266 this.editicon.on('click', function(e) {
13268 // we fire even if inothing is selected..
13269 this.fireEvent('edit', this, this.lastData );
13275 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13276 "up" : function(e){
13277 this.inKeyMode = true;
13281 "down" : function(e){
13282 if(!this.isExpanded()){
13283 this.onTriggerClick();
13285 this.inKeyMode = true;
13290 "enter" : function(e){
13291 // this.onViewClick();
13295 if(this.fireEvent("specialkey", this, e)){
13296 this.onViewClick(false);
13302 "esc" : function(e){
13306 "tab" : function(e){
13309 if(this.fireEvent("specialkey", this, e)){
13310 this.onViewClick(false);
13318 doRelay : function(foo, bar, hname){
13319 if(hname == 'down' || this.scope.isExpanded()){
13320 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13329 this.queryDelay = Math.max(this.queryDelay || 10,
13330 this.mode == 'local' ? 10 : 250);
13333 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13335 if(this.typeAhead){
13336 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13338 if(this.editable !== false){
13339 this.inputEl().on("keyup", this.onKeyUp, this);
13341 if(this.forceSelection){
13342 this.inputEl().on('blur', this.doForce, this);
13346 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13347 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13351 initTickableEvents: function()
13355 if(this.hiddenName){
13357 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13359 this.hiddenField.dom.value =
13360 this.hiddenValue !== undefined ? this.hiddenValue :
13361 this.value !== undefined ? this.value : '';
13363 // prevent input submission
13364 this.el.dom.removeAttribute('name');
13365 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13370 // this.list = this.el.select('ul.dropdown-menu',true).first();
13372 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13373 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13374 if(this.triggerList){
13375 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13378 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13379 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13381 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13382 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13384 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13385 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13387 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13388 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13389 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13392 this.cancelBtn.hide();
13397 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13398 _this.list.setWidth(lw);
13401 this.list.on('mouseover', this.onViewOver, this);
13402 this.list.on('mousemove', this.onViewMove, this);
13404 this.list.on('scroll', this.onViewScroll, this);
13407 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>';
13410 this.view = new Roo.View(this.list, this.tpl, {
13411 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13414 //this.view.wrapEl.setDisplayed(false);
13415 this.view.on('click', this.onViewClick, this);
13419 this.store.on('beforeload', this.onBeforeLoad, this);
13420 this.store.on('load', this.onLoad, this);
13421 this.store.on('loadexception', this.onLoadException, this);
13424 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13425 "up" : function(e){
13426 this.inKeyMode = true;
13430 "down" : function(e){
13431 this.inKeyMode = true;
13435 "enter" : function(e){
13436 if(this.fireEvent("specialkey", this, e)){
13437 this.onViewClick(false);
13443 "esc" : function(e){
13444 this.onTickableFooterButtonClick(e, false, false);
13447 "tab" : function(e){
13448 this.fireEvent("specialkey", this, e);
13450 this.onTickableFooterButtonClick(e, false, false);
13457 doRelay : function(e, fn, key){
13458 if(this.scope.isExpanded()){
13459 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13468 this.queryDelay = Math.max(this.queryDelay || 10,
13469 this.mode == 'local' ? 10 : 250);
13472 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13474 if(this.typeAhead){
13475 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13478 if(this.editable !== false){
13479 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13482 this.indicator = this.indicatorEl();
13484 if(this.indicator){
13485 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13486 this.indicator.hide();
13491 onDestroy : function(){
13493 this.view.setStore(null);
13494 this.view.el.removeAllListeners();
13495 this.view.el.remove();
13496 this.view.purgeListeners();
13499 this.list.dom.innerHTML = '';
13503 this.store.un('beforeload', this.onBeforeLoad, this);
13504 this.store.un('load', this.onLoad, this);
13505 this.store.un('loadexception', this.onLoadException, this);
13507 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13511 fireKey : function(e){
13512 if(e.isNavKeyPress() && !this.list.isVisible()){
13513 this.fireEvent("specialkey", this, e);
13518 onResize: function(w, h){
13519 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13521 // if(typeof w != 'number'){
13522 // // we do not handle it!?!?
13525 // var tw = this.trigger.getWidth();
13526 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13527 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13529 // this.inputEl().setWidth( this.adjustWidth('input', x));
13531 // //this.trigger.setStyle('left', x+'px');
13533 // if(this.list && this.listWidth === undefined){
13534 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13535 // this.list.setWidth(lw);
13536 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13544 * Allow or prevent the user from directly editing the field text. If false is passed,
13545 * the user will only be able to select from the items defined in the dropdown list. This method
13546 * is the runtime equivalent of setting the 'editable' config option at config time.
13547 * @param {Boolean} value True to allow the user to directly edit the field text
13549 setEditable : function(value){
13550 if(value == this.editable){
13553 this.editable = value;
13555 this.inputEl().dom.setAttribute('readOnly', true);
13556 this.inputEl().on('mousedown', this.onTriggerClick, this);
13557 this.inputEl().addClass('x-combo-noedit');
13559 this.inputEl().dom.setAttribute('readOnly', false);
13560 this.inputEl().un('mousedown', this.onTriggerClick, this);
13561 this.inputEl().removeClass('x-combo-noedit');
13567 onBeforeLoad : function(combo,opts){
13568 if(!this.hasFocus){
13572 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13574 this.restrictHeight();
13575 this.selectedIndex = -1;
13579 onLoad : function(){
13581 this.hasQuery = false;
13583 if(!this.hasFocus){
13587 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13588 this.loading.hide();
13591 if(this.store.getCount() > 0){
13594 this.restrictHeight();
13595 if(this.lastQuery == this.allQuery){
13596 if(this.editable && !this.tickable){
13597 this.inputEl().dom.select();
13601 !this.selectByValue(this.value, true) &&
13604 !this.store.lastOptions ||
13605 typeof(this.store.lastOptions.add) == 'undefined' ||
13606 this.store.lastOptions.add != true
13609 this.select(0, true);
13612 if(this.autoFocus){
13615 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13616 this.taTask.delay(this.typeAheadDelay);
13620 this.onEmptyResults();
13626 onLoadException : function()
13628 this.hasQuery = false;
13630 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13631 this.loading.hide();
13634 if(this.tickable && this.editable){
13639 // only causes errors at present
13640 //Roo.log(this.store.reader.jsonData);
13641 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13643 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13649 onTypeAhead : function(){
13650 if(this.store.getCount() > 0){
13651 var r = this.store.getAt(0);
13652 var newValue = r.data[this.displayField];
13653 var len = newValue.length;
13654 var selStart = this.getRawValue().length;
13656 if(selStart != len){
13657 this.setRawValue(newValue);
13658 this.selectText(selStart, newValue.length);
13664 onSelect : function(record, index){
13666 if(this.fireEvent('beforeselect', this, record, index) !== false){
13668 this.setFromData(index > -1 ? record.data : false);
13671 this.fireEvent('select', this, record, index);
13676 * Returns the currently selected field value or empty string if no value is set.
13677 * @return {String} value The selected value
13679 getValue : function()
13681 if(Roo.isIOS && this.useNativeIOS){
13682 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13686 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13689 if(this.valueField){
13690 return typeof this.value != 'undefined' ? this.value : '';
13692 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13696 getRawValue : function()
13698 if(Roo.isIOS && this.useNativeIOS){
13699 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13702 var v = this.inputEl().getValue();
13708 * Clears any text/value currently set in the field
13710 clearValue : function(){
13712 if(this.hiddenField){
13713 this.hiddenField.dom.value = '';
13716 this.setRawValue('');
13717 this.lastSelectionText = '';
13718 this.lastData = false;
13720 var close = this.closeTriggerEl();
13731 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13732 * will be displayed in the field. If the value does not match the data value of an existing item,
13733 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13734 * Otherwise the field will be blank (although the value will still be set).
13735 * @param {String} value The value to match
13737 setValue : function(v)
13739 if(Roo.isIOS && this.useNativeIOS){
13740 this.setIOSValue(v);
13750 if(this.valueField){
13751 var r = this.findRecord(this.valueField, v);
13753 text = r.data[this.displayField];
13754 }else if(this.valueNotFoundText !== undefined){
13755 text = this.valueNotFoundText;
13758 this.lastSelectionText = text;
13759 if(this.hiddenField){
13760 this.hiddenField.dom.value = v;
13762 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13765 var close = this.closeTriggerEl();
13768 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13774 * @property {Object} the last set data for the element
13779 * Sets the value of the field based on a object which is related to the record format for the store.
13780 * @param {Object} value the value to set as. or false on reset?
13782 setFromData : function(o){
13789 var dv = ''; // display value
13790 var vv = ''; // value value..
13792 if (this.displayField) {
13793 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13795 // this is an error condition!!!
13796 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13799 if(this.valueField){
13800 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13803 var close = this.closeTriggerEl();
13806 if(dv.length || vv * 1 > 0){
13808 this.blockFocus=true;
13814 if(this.hiddenField){
13815 this.hiddenField.dom.value = vv;
13817 this.lastSelectionText = dv;
13818 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13822 // no hidden field.. - we store the value in 'value', but still display
13823 // display field!!!!
13824 this.lastSelectionText = dv;
13825 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13832 reset : function(){
13833 // overridden so that last data is reset..
13840 this.setValue(this.originalValue);
13841 //this.clearInvalid();
13842 this.lastData = false;
13844 this.view.clearSelections();
13850 findRecord : function(prop, value){
13852 if(this.store.getCount() > 0){
13853 this.store.each(function(r){
13854 if(r.data[prop] == value){
13864 getName: function()
13866 // returns hidden if it's set..
13867 if (!this.rendered) {return ''};
13868 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13872 onViewMove : function(e, t){
13873 this.inKeyMode = false;
13877 onViewOver : function(e, t){
13878 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13881 var item = this.view.findItemFromChild(t);
13884 var index = this.view.indexOf(item);
13885 this.select(index, false);
13890 onViewClick : function(view, doFocus, el, e)
13892 var index = this.view.getSelectedIndexes()[0];
13894 var r = this.store.getAt(index);
13898 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13905 Roo.each(this.tickItems, function(v,k){
13907 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13909 _this.tickItems.splice(k, 1);
13911 if(typeof(e) == 'undefined' && view == false){
13912 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13924 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13925 this.tickItems.push(r.data);
13928 if(typeof(e) == 'undefined' && view == false){
13929 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13936 this.onSelect(r, index);
13938 if(doFocus !== false && !this.blockFocus){
13939 this.inputEl().focus();
13944 restrictHeight : function(){
13945 //this.innerList.dom.style.height = '';
13946 //var inner = this.innerList.dom;
13947 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13948 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13949 //this.list.beginUpdate();
13950 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13951 this.list.alignTo(this.inputEl(), this.listAlign);
13952 this.list.alignTo(this.inputEl(), this.listAlign);
13953 //this.list.endUpdate();
13957 onEmptyResults : function(){
13959 if(this.tickable && this.editable){
13960 this.restrictHeight();
13968 * Returns true if the dropdown list is expanded, else false.
13970 isExpanded : function(){
13971 return this.list.isVisible();
13975 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13976 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13977 * @param {String} value The data value of the item to select
13978 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13979 * selected item if it is not currently in view (defaults to true)
13980 * @return {Boolean} True if the value matched an item in the list, else false
13982 selectByValue : function(v, scrollIntoView){
13983 if(v !== undefined && v !== null){
13984 var r = this.findRecord(this.valueField || this.displayField, v);
13986 this.select(this.store.indexOf(r), scrollIntoView);
13994 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13995 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13996 * @param {Number} index The zero-based index of the list item to select
13997 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13998 * selected item if it is not currently in view (defaults to true)
14000 select : function(index, scrollIntoView){
14001 this.selectedIndex = index;
14002 this.view.select(index);
14003 if(scrollIntoView !== false){
14004 var el = this.view.getNode(index);
14006 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14009 this.list.scrollChildIntoView(el, false);
14015 selectNext : function(){
14016 var ct = this.store.getCount();
14018 if(this.selectedIndex == -1){
14020 }else if(this.selectedIndex < ct-1){
14021 this.select(this.selectedIndex+1);
14027 selectPrev : function(){
14028 var ct = this.store.getCount();
14030 if(this.selectedIndex == -1){
14032 }else if(this.selectedIndex != 0){
14033 this.select(this.selectedIndex-1);
14039 onKeyUp : function(e){
14040 if(this.editable !== false && !e.isSpecialKey()){
14041 this.lastKey = e.getKey();
14042 this.dqTask.delay(this.queryDelay);
14047 validateBlur : function(){
14048 return !this.list || !this.list.isVisible();
14052 initQuery : function(){
14054 var v = this.getRawValue();
14056 if(this.tickable && this.editable){
14057 v = this.tickableInputEl().getValue();
14064 doForce : function(){
14065 if(this.inputEl().dom.value.length > 0){
14066 this.inputEl().dom.value =
14067 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14073 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14074 * query allowing the query action to be canceled if needed.
14075 * @param {String} query The SQL query to execute
14076 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14077 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14078 * saved in the current store (defaults to false)
14080 doQuery : function(q, forceAll){
14082 if(q === undefined || q === null){
14087 forceAll: forceAll,
14091 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14096 forceAll = qe.forceAll;
14097 if(forceAll === true || (q.length >= this.minChars)){
14099 this.hasQuery = true;
14101 if(this.lastQuery != q || this.alwaysQuery){
14102 this.lastQuery = q;
14103 if(this.mode == 'local'){
14104 this.selectedIndex = -1;
14106 this.store.clearFilter();
14109 if(this.specialFilter){
14110 this.fireEvent('specialfilter', this);
14115 this.store.filter(this.displayField, q);
14118 this.store.fireEvent("datachanged", this.store);
14125 this.store.baseParams[this.queryParam] = q;
14127 var options = {params : this.getParams(q)};
14130 options.add = true;
14131 options.params.start = this.page * this.pageSize;
14134 this.store.load(options);
14137 * this code will make the page width larger, at the beginning, the list not align correctly,
14138 * we should expand the list on onLoad
14139 * so command out it
14144 this.selectedIndex = -1;
14149 this.loadNext = false;
14153 getParams : function(q){
14155 //p[this.queryParam] = q;
14159 p.limit = this.pageSize;
14165 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14167 collapse : function(){
14168 if(!this.isExpanded()){
14174 this.hasFocus = false;
14178 this.cancelBtn.hide();
14179 this.trigger.show();
14182 this.tickableInputEl().dom.value = '';
14183 this.tickableInputEl().blur();
14188 Roo.get(document).un('mousedown', this.collapseIf, this);
14189 Roo.get(document).un('mousewheel', this.collapseIf, this);
14190 if (!this.editable) {
14191 Roo.get(document).un('keydown', this.listKeyPress, this);
14193 this.fireEvent('collapse', this);
14199 collapseIf : function(e){
14200 var in_combo = e.within(this.el);
14201 var in_list = e.within(this.list);
14202 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14204 if (in_combo || in_list || is_list) {
14205 //e.stopPropagation();
14210 this.onTickableFooterButtonClick(e, false, false);
14218 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14220 expand : function(){
14222 if(this.isExpanded() || !this.hasFocus){
14226 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14227 this.list.setWidth(lw);
14233 this.restrictHeight();
14237 this.tickItems = Roo.apply([], this.item);
14240 this.cancelBtn.show();
14241 this.trigger.hide();
14244 this.tickableInputEl().focus();
14249 Roo.get(document).on('mousedown', this.collapseIf, this);
14250 Roo.get(document).on('mousewheel', this.collapseIf, this);
14251 if (!this.editable) {
14252 Roo.get(document).on('keydown', this.listKeyPress, this);
14255 this.fireEvent('expand', this);
14259 // Implements the default empty TriggerField.onTriggerClick function
14260 onTriggerClick : function(e)
14262 Roo.log('trigger click');
14264 if(this.disabled || !this.triggerList){
14269 this.loadNext = false;
14271 if(this.isExpanded()){
14273 if (!this.blockFocus) {
14274 this.inputEl().focus();
14278 this.hasFocus = true;
14279 if(this.triggerAction == 'all') {
14280 this.doQuery(this.allQuery, true);
14282 this.doQuery(this.getRawValue());
14284 if (!this.blockFocus) {
14285 this.inputEl().focus();
14290 onTickableTriggerClick : function(e)
14297 this.loadNext = false;
14298 this.hasFocus = true;
14300 if(this.triggerAction == 'all') {
14301 this.doQuery(this.allQuery, true);
14303 this.doQuery(this.getRawValue());
14307 onSearchFieldClick : function(e)
14309 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14310 this.onTickableFooterButtonClick(e, false, false);
14314 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14319 this.loadNext = false;
14320 this.hasFocus = true;
14322 if(this.triggerAction == 'all') {
14323 this.doQuery(this.allQuery, true);
14325 this.doQuery(this.getRawValue());
14329 listKeyPress : function(e)
14331 //Roo.log('listkeypress');
14332 // scroll to first matching element based on key pres..
14333 if (e.isSpecialKey()) {
14336 var k = String.fromCharCode(e.getKey()).toUpperCase();
14339 var csel = this.view.getSelectedNodes();
14340 var cselitem = false;
14342 var ix = this.view.indexOf(csel[0]);
14343 cselitem = this.store.getAt(ix);
14344 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14350 this.store.each(function(v) {
14352 // start at existing selection.
14353 if (cselitem.id == v.id) {
14359 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14360 match = this.store.indexOf(v);
14366 if (match === false) {
14367 return true; // no more action?
14370 this.view.select(match);
14371 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14372 sn.scrollIntoView(sn.dom.parentNode, false);
14375 onViewScroll : function(e, t){
14377 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){
14381 this.hasQuery = true;
14383 this.loading = this.list.select('.loading', true).first();
14385 if(this.loading === null){
14386 this.list.createChild({
14388 cls: 'loading roo-select2-more-results roo-select2-active',
14389 html: 'Loading more results...'
14392 this.loading = this.list.select('.loading', true).first();
14394 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14396 this.loading.hide();
14399 this.loading.show();
14404 this.loadNext = true;
14406 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14411 addItem : function(o)
14413 var dv = ''; // display value
14415 if (this.displayField) {
14416 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14418 // this is an error condition!!!
14419 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14426 var choice = this.choices.createChild({
14428 cls: 'roo-select2-search-choice',
14437 cls: 'roo-select2-search-choice-close fa fa-times',
14442 }, this.searchField);
14444 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14446 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14454 this.inputEl().dom.value = '';
14459 onRemoveItem : function(e, _self, o)
14461 e.preventDefault();
14463 this.lastItem = Roo.apply([], this.item);
14465 var index = this.item.indexOf(o.data) * 1;
14468 Roo.log('not this item?!');
14472 this.item.splice(index, 1);
14477 this.fireEvent('remove', this, e);
14483 syncValue : function()
14485 if(!this.item.length){
14492 Roo.each(this.item, function(i){
14493 if(_this.valueField){
14494 value.push(i[_this.valueField]);
14501 this.value = value.join(',');
14503 if(this.hiddenField){
14504 this.hiddenField.dom.value = this.value;
14507 this.store.fireEvent("datachanged", this.store);
14512 clearItem : function()
14514 if(!this.multiple){
14520 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14528 if(this.tickable && !Roo.isTouch){
14529 this.view.refresh();
14533 inputEl: function ()
14535 if(Roo.isIOS && this.useNativeIOS){
14536 return this.el.select('select.roo-ios-select', true).first();
14539 if(Roo.isTouch && this.mobileTouchView){
14540 return this.el.select('input.form-control',true).first();
14544 return this.searchField;
14547 return this.el.select('input.form-control',true).first();
14550 onTickableFooterButtonClick : function(e, btn, el)
14552 e.preventDefault();
14554 this.lastItem = Roo.apply([], this.item);
14556 if(btn && btn.name == 'cancel'){
14557 this.tickItems = Roo.apply([], this.item);
14566 Roo.each(this.tickItems, function(o){
14574 validate : function()
14576 var v = this.getRawValue();
14579 v = this.getValue();
14582 if(this.disabled || this.allowBlank || v.length){
14587 this.markInvalid();
14591 tickableInputEl : function()
14593 if(!this.tickable || !this.editable){
14594 return this.inputEl();
14597 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14601 getAutoCreateTouchView : function()
14606 cls: 'form-group' //input-group
14612 type : this.inputType,
14613 cls : 'form-control x-combo-noedit',
14614 autocomplete: 'new-password',
14615 placeholder : this.placeholder || '',
14620 input.name = this.name;
14624 input.cls += ' input-' + this.size;
14627 if (this.disabled) {
14628 input.disabled = true;
14639 inputblock.cls += ' input-group';
14641 inputblock.cn.unshift({
14643 cls : 'input-group-addon',
14648 if(this.removable && !this.multiple){
14649 inputblock.cls += ' roo-removable';
14651 inputblock.cn.push({
14654 cls : 'roo-combo-removable-btn close'
14658 if(this.hasFeedback && !this.allowBlank){
14660 inputblock.cls += ' has-feedback';
14662 inputblock.cn.push({
14664 cls: 'glyphicon form-control-feedback'
14671 inputblock.cls += (this.before) ? '' : ' input-group';
14673 inputblock.cn.push({
14675 cls : 'input-group-addon',
14686 cls: 'form-hidden-field'
14700 cls: 'form-hidden-field'
14704 cls: 'roo-select2-choices',
14708 cls: 'roo-select2-search-field',
14721 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14727 if(!this.multiple && this.showToggleBtn){
14734 if (this.caret != false) {
14737 cls: 'fa fa-' + this.caret
14744 cls : 'input-group-addon btn dropdown-toggle',
14749 cls: 'combobox-clear',
14763 combobox.cls += ' roo-select2-container-multi';
14766 var align = this.labelAlign || this.parentLabelAlign();
14768 if (align ==='left' && this.fieldLabel.length) {
14773 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14774 tooltip : 'This field is required'
14778 cls : 'control-label',
14779 html : this.fieldLabel
14790 var labelCfg = cfg.cn[1];
14791 var contentCfg = cfg.cn[2];
14794 if(this.indicatorpos == 'right'){
14799 cls : 'control-label',
14803 html : this.fieldLabel
14807 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14808 tooltip : 'This field is required'
14821 labelCfg = cfg.cn[0];
14822 contentCfg = cfg.cn[1];
14827 if(this.labelWidth > 12){
14828 labelCfg.style = "width: " + this.labelWidth + 'px';
14831 if(this.labelWidth < 13 && this.labelmd == 0){
14832 this.labelmd = this.labelWidth;
14835 if(this.labellg > 0){
14836 labelCfg.cls += ' col-lg-' + this.labellg;
14837 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14840 if(this.labelmd > 0){
14841 labelCfg.cls += ' col-md-' + this.labelmd;
14842 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14845 if(this.labelsm > 0){
14846 labelCfg.cls += ' col-sm-' + this.labelsm;
14847 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14850 if(this.labelxs > 0){
14851 labelCfg.cls += ' col-xs-' + this.labelxs;
14852 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14856 } else if ( this.fieldLabel.length) {
14860 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14861 tooltip : 'This field is required'
14865 cls : 'control-label',
14866 html : this.fieldLabel
14877 if(this.indicatorpos == 'right'){
14881 cls : 'control-label',
14882 html : this.fieldLabel,
14886 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14887 tooltip : 'This field is required'
14904 var settings = this;
14906 ['xs','sm','md','lg'].map(function(size){
14907 if (settings[size]) {
14908 cfg.cls += ' col-' + size + '-' + settings[size];
14915 initTouchView : function()
14917 this.renderTouchView();
14919 this.touchViewEl.on('scroll', function(){
14920 this.el.dom.scrollTop = 0;
14923 this.originalValue = this.getValue();
14925 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14927 this.inputEl().on("click", this.showTouchView, this);
14928 if (this.triggerEl) {
14929 this.triggerEl.on("click", this.showTouchView, this);
14933 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14934 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14936 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14938 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14939 this.store.on('load', this.onTouchViewLoad, this);
14940 this.store.on('loadexception', this.onTouchViewLoadException, this);
14942 if(this.hiddenName){
14944 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14946 this.hiddenField.dom.value =
14947 this.hiddenValue !== undefined ? this.hiddenValue :
14948 this.value !== undefined ? this.value : '';
14950 this.el.dom.removeAttribute('name');
14951 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14955 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14956 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14959 if(this.removable && !this.multiple){
14960 var close = this.closeTriggerEl();
14962 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14963 close.on('click', this.removeBtnClick, this, close);
14967 * fix the bug in Safari iOS8
14969 this.inputEl().on("focus", function(e){
14970 document.activeElement.blur();
14978 renderTouchView : function()
14980 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14981 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14983 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14984 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14986 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14987 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14988 this.touchViewBodyEl.setStyle('overflow', 'auto');
14990 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14991 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14993 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14994 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14998 showTouchView : function()
15004 this.touchViewHeaderEl.hide();
15006 if(this.modalTitle.length){
15007 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15008 this.touchViewHeaderEl.show();
15011 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15012 this.touchViewEl.show();
15014 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15016 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15017 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15019 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15021 if(this.modalTitle.length){
15022 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15025 this.touchViewBodyEl.setHeight(bodyHeight);
15029 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15031 this.touchViewEl.addClass('in');
15034 this.doTouchViewQuery();
15038 hideTouchView : function()
15040 this.touchViewEl.removeClass('in');
15044 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15046 this.touchViewEl.setStyle('display', 'none');
15051 setTouchViewValue : function()
15058 Roo.each(this.tickItems, function(o){
15063 this.hideTouchView();
15066 doTouchViewQuery : function()
15075 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15079 if(!this.alwaysQuery || this.mode == 'local'){
15080 this.onTouchViewLoad();
15087 onTouchViewBeforeLoad : function(combo,opts)
15093 onTouchViewLoad : function()
15095 if(this.store.getCount() < 1){
15096 this.onTouchViewEmptyResults();
15100 this.clearTouchView();
15102 var rawValue = this.getRawValue();
15104 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15106 this.tickItems = [];
15108 this.store.data.each(function(d, rowIndex){
15109 var row = this.touchViewListGroup.createChild(template);
15111 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15112 row.addClass(d.data.cls);
15115 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15118 html : d.data[this.displayField]
15121 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15122 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15125 row.removeClass('selected');
15126 if(!this.multiple && this.valueField &&
15127 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15130 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15131 row.addClass('selected');
15134 if(this.multiple && this.valueField &&
15135 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15139 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15140 this.tickItems.push(d.data);
15143 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15147 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15149 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15151 if(this.modalTitle.length){
15152 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15155 var listHeight = this.touchViewListGroup.getHeight();
15159 if(firstChecked && listHeight > bodyHeight){
15160 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15165 onTouchViewLoadException : function()
15167 this.hideTouchView();
15170 onTouchViewEmptyResults : function()
15172 this.clearTouchView();
15174 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15176 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15180 clearTouchView : function()
15182 this.touchViewListGroup.dom.innerHTML = '';
15185 onTouchViewClick : function(e, el, o)
15187 e.preventDefault();
15190 var rowIndex = o.rowIndex;
15192 var r = this.store.getAt(rowIndex);
15194 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15196 if(!this.multiple){
15197 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15198 c.dom.removeAttribute('checked');
15201 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15203 this.setFromData(r.data);
15205 var close = this.closeTriggerEl();
15211 this.hideTouchView();
15213 this.fireEvent('select', this, r, rowIndex);
15218 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15219 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15220 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15224 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15225 this.addItem(r.data);
15226 this.tickItems.push(r.data);
15230 getAutoCreateNativeIOS : function()
15233 cls: 'form-group' //input-group,
15238 cls : 'roo-ios-select'
15242 combobox.name = this.name;
15245 if (this.disabled) {
15246 combobox.disabled = true;
15249 var settings = this;
15251 ['xs','sm','md','lg'].map(function(size){
15252 if (settings[size]) {
15253 cfg.cls += ' col-' + size + '-' + settings[size];
15263 initIOSView : function()
15265 this.store.on('load', this.onIOSViewLoad, this);
15270 onIOSViewLoad : function()
15272 if(this.store.getCount() < 1){
15276 this.clearIOSView();
15278 if(this.allowBlank) {
15280 var default_text = '-- SELECT --';
15282 if(this.placeholder.length){
15283 default_text = this.placeholder;
15286 if(this.emptyTitle.length){
15287 default_text += ' - ' + this.emptyTitle + ' -';
15290 var opt = this.inputEl().createChild({
15293 html : default_text
15297 o[this.valueField] = 0;
15298 o[this.displayField] = default_text;
15300 this.ios_options.push({
15307 this.store.data.each(function(d, rowIndex){
15311 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15312 html = d.data[this.displayField];
15317 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15318 value = d.data[this.valueField];
15327 if(this.value == d.data[this.valueField]){
15328 option['selected'] = true;
15331 var opt = this.inputEl().createChild(option);
15333 this.ios_options.push({
15340 this.inputEl().on('change', function(){
15341 this.fireEvent('select', this);
15346 clearIOSView: function()
15348 this.inputEl().dom.innerHTML = '';
15350 this.ios_options = [];
15353 setIOSValue: function(v)
15357 if(!this.ios_options){
15361 Roo.each(this.ios_options, function(opts){
15363 opts.el.dom.removeAttribute('selected');
15365 if(opts.data[this.valueField] != v){
15369 opts.el.dom.setAttribute('selected', true);
15375 * @cfg {Boolean} grow
15379 * @cfg {Number} growMin
15383 * @cfg {Number} growMax
15392 Roo.apply(Roo.bootstrap.ComboBox, {
15396 cls: 'modal-header',
15418 cls: 'list-group-item',
15422 cls: 'roo-combobox-list-group-item-value'
15426 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15440 listItemCheckbox : {
15442 cls: 'list-group-item',
15446 cls: 'roo-combobox-list-group-item-value'
15450 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15466 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15471 cls: 'modal-footer',
15479 cls: 'col-xs-6 text-left',
15482 cls: 'btn btn-danger roo-touch-view-cancel',
15488 cls: 'col-xs-6 text-right',
15491 cls: 'btn btn-success roo-touch-view-ok',
15502 Roo.apply(Roo.bootstrap.ComboBox, {
15504 touchViewTemplate : {
15506 cls: 'modal fade roo-combobox-touch-view',
15510 cls: 'modal-dialog',
15511 style : 'position:fixed', // we have to fix position....
15515 cls: 'modal-content',
15517 Roo.bootstrap.ComboBox.header,
15518 Roo.bootstrap.ComboBox.body,
15519 Roo.bootstrap.ComboBox.footer
15528 * Ext JS Library 1.1.1
15529 * Copyright(c) 2006-2007, Ext JS, LLC.
15531 * Originally Released Under LGPL - original licence link has changed is not relivant.
15534 * <script type="text/javascript">
15539 * @extends Roo.util.Observable
15540 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15541 * This class also supports single and multi selection modes. <br>
15542 * Create a data model bound view:
15544 var store = new Roo.data.Store(...);
15546 var view = new Roo.View({
15548 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15550 singleSelect: true,
15551 selectedClass: "ydataview-selected",
15555 // listen for node click?
15556 view.on("click", function(vw, index, node, e){
15557 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15561 dataModel.load("foobar.xml");
15563 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15565 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15566 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15568 * Note: old style constructor is still suported (container, template, config)
15571 * Create a new View
15572 * @param {Object} config The config object
15575 Roo.View = function(config, depreciated_tpl, depreciated_config){
15577 this.parent = false;
15579 if (typeof(depreciated_tpl) == 'undefined') {
15580 // new way.. - universal constructor.
15581 Roo.apply(this, config);
15582 this.el = Roo.get(this.el);
15585 this.el = Roo.get(config);
15586 this.tpl = depreciated_tpl;
15587 Roo.apply(this, depreciated_config);
15589 this.wrapEl = this.el.wrap().wrap();
15590 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15593 if(typeof(this.tpl) == "string"){
15594 this.tpl = new Roo.Template(this.tpl);
15596 // support xtype ctors..
15597 this.tpl = new Roo.factory(this.tpl, Roo);
15601 this.tpl.compile();
15606 * @event beforeclick
15607 * Fires before a click is processed. Returns false to cancel the default action.
15608 * @param {Roo.View} this
15609 * @param {Number} index The index of the target node
15610 * @param {HTMLElement} node The target node
15611 * @param {Roo.EventObject} e The raw event object
15613 "beforeclick" : true,
15616 * Fires when a template node is clicked.
15617 * @param {Roo.View} this
15618 * @param {Number} index The index of the target node
15619 * @param {HTMLElement} node The target node
15620 * @param {Roo.EventObject} e The raw event object
15625 * Fires when a template node is double clicked.
15626 * @param {Roo.View} this
15627 * @param {Number} index The index of the target node
15628 * @param {HTMLElement} node The target node
15629 * @param {Roo.EventObject} e The raw event object
15633 * @event contextmenu
15634 * Fires when a template node is right clicked.
15635 * @param {Roo.View} this
15636 * @param {Number} index The index of the target node
15637 * @param {HTMLElement} node The target node
15638 * @param {Roo.EventObject} e The raw event object
15640 "contextmenu" : true,
15642 * @event selectionchange
15643 * Fires when the selected nodes change.
15644 * @param {Roo.View} this
15645 * @param {Array} selections Array of the selected nodes
15647 "selectionchange" : true,
15650 * @event beforeselect
15651 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15652 * @param {Roo.View} this
15653 * @param {HTMLElement} node The node to be selected
15654 * @param {Array} selections Array of currently selected nodes
15656 "beforeselect" : true,
15658 * @event preparedata
15659 * Fires on every row to render, to allow you to change the data.
15660 * @param {Roo.View} this
15661 * @param {Object} data to be rendered (change this)
15663 "preparedata" : true
15671 "click": this.onClick,
15672 "dblclick": this.onDblClick,
15673 "contextmenu": this.onContextMenu,
15677 this.selections = [];
15679 this.cmp = new Roo.CompositeElementLite([]);
15681 this.store = Roo.factory(this.store, Roo.data);
15682 this.setStore(this.store, true);
15685 if ( this.footer && this.footer.xtype) {
15687 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15689 this.footer.dataSource = this.store;
15690 this.footer.container = fctr;
15691 this.footer = Roo.factory(this.footer, Roo);
15692 fctr.insertFirst(this.el);
15694 // this is a bit insane - as the paging toolbar seems to detach the el..
15695 // dom.parentNode.parentNode.parentNode
15696 // they get detached?
15700 Roo.View.superclass.constructor.call(this);
15705 Roo.extend(Roo.View, Roo.util.Observable, {
15708 * @cfg {Roo.data.Store} store Data store to load data from.
15713 * @cfg {String|Roo.Element} el The container element.
15718 * @cfg {String|Roo.Template} tpl The template used by this View
15722 * @cfg {String} dataName the named area of the template to use as the data area
15723 * Works with domtemplates roo-name="name"
15727 * @cfg {String} selectedClass The css class to add to selected nodes
15729 selectedClass : "x-view-selected",
15731 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15736 * @cfg {String} text to display on mask (default Loading)
15740 * @cfg {Boolean} multiSelect Allow multiple selection
15742 multiSelect : false,
15744 * @cfg {Boolean} singleSelect Allow single selection
15746 singleSelect: false,
15749 * @cfg {Boolean} toggleSelect - selecting
15751 toggleSelect : false,
15754 * @cfg {Boolean} tickable - selecting
15759 * Returns the element this view is bound to.
15760 * @return {Roo.Element}
15762 getEl : function(){
15763 return this.wrapEl;
15769 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15771 refresh : function(){
15772 //Roo.log('refresh');
15775 // if we are using something like 'domtemplate', then
15776 // the what gets used is:
15777 // t.applySubtemplate(NAME, data, wrapping data..)
15778 // the outer template then get' applied with
15779 // the store 'extra data'
15780 // and the body get's added to the
15781 // roo-name="data" node?
15782 // <span class='roo-tpl-{name}'></span> ?????
15786 this.clearSelections();
15787 this.el.update("");
15789 var records = this.store.getRange();
15790 if(records.length < 1) {
15792 // is this valid?? = should it render a template??
15794 this.el.update(this.emptyText);
15798 if (this.dataName) {
15799 this.el.update(t.apply(this.store.meta)); //????
15800 el = this.el.child('.roo-tpl-' + this.dataName);
15803 for(var i = 0, len = records.length; i < len; i++){
15804 var data = this.prepareData(records[i].data, i, records[i]);
15805 this.fireEvent("preparedata", this, data, i, records[i]);
15807 var d = Roo.apply({}, data);
15810 Roo.apply(d, {'roo-id' : Roo.id()});
15814 Roo.each(this.parent.item, function(item){
15815 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15818 Roo.apply(d, {'roo-data-checked' : 'checked'});
15822 html[html.length] = Roo.util.Format.trim(
15824 t.applySubtemplate(this.dataName, d, this.store.meta) :
15831 el.update(html.join(""));
15832 this.nodes = el.dom.childNodes;
15833 this.updateIndexes(0);
15838 * Function to override to reformat the data that is sent to
15839 * the template for each node.
15840 * DEPRICATED - use the preparedata event handler.
15841 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15842 * a JSON object for an UpdateManager bound view).
15844 prepareData : function(data, index, record)
15846 this.fireEvent("preparedata", this, data, index, record);
15850 onUpdate : function(ds, record){
15851 // Roo.log('on update');
15852 this.clearSelections();
15853 var index = this.store.indexOf(record);
15854 var n = this.nodes[index];
15855 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15856 n.parentNode.removeChild(n);
15857 this.updateIndexes(index, index);
15863 onAdd : function(ds, records, index)
15865 //Roo.log(['on Add', ds, records, index] );
15866 this.clearSelections();
15867 if(this.nodes.length == 0){
15871 var n = this.nodes[index];
15872 for(var i = 0, len = records.length; i < len; i++){
15873 var d = this.prepareData(records[i].data, i, records[i]);
15875 this.tpl.insertBefore(n, d);
15878 this.tpl.append(this.el, d);
15881 this.updateIndexes(index);
15884 onRemove : function(ds, record, index){
15885 // Roo.log('onRemove');
15886 this.clearSelections();
15887 var el = this.dataName ?
15888 this.el.child('.roo-tpl-' + this.dataName) :
15891 el.dom.removeChild(this.nodes[index]);
15892 this.updateIndexes(index);
15896 * Refresh an individual node.
15897 * @param {Number} index
15899 refreshNode : function(index){
15900 this.onUpdate(this.store, this.store.getAt(index));
15903 updateIndexes : function(startIndex, endIndex){
15904 var ns = this.nodes;
15905 startIndex = startIndex || 0;
15906 endIndex = endIndex || ns.length - 1;
15907 for(var i = startIndex; i <= endIndex; i++){
15908 ns[i].nodeIndex = i;
15913 * Changes the data store this view uses and refresh the view.
15914 * @param {Store} store
15916 setStore : function(store, initial){
15917 if(!initial && this.store){
15918 this.store.un("datachanged", this.refresh);
15919 this.store.un("add", this.onAdd);
15920 this.store.un("remove", this.onRemove);
15921 this.store.un("update", this.onUpdate);
15922 this.store.un("clear", this.refresh);
15923 this.store.un("beforeload", this.onBeforeLoad);
15924 this.store.un("load", this.onLoad);
15925 this.store.un("loadexception", this.onLoad);
15929 store.on("datachanged", this.refresh, this);
15930 store.on("add", this.onAdd, this);
15931 store.on("remove", this.onRemove, this);
15932 store.on("update", this.onUpdate, this);
15933 store.on("clear", this.refresh, this);
15934 store.on("beforeload", this.onBeforeLoad, this);
15935 store.on("load", this.onLoad, this);
15936 store.on("loadexception", this.onLoad, this);
15944 * onbeforeLoad - masks the loading area.
15947 onBeforeLoad : function(store,opts)
15949 //Roo.log('onBeforeLoad');
15951 this.el.update("");
15953 this.el.mask(this.mask ? this.mask : "Loading" );
15955 onLoad : function ()
15962 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15963 * @param {HTMLElement} node
15964 * @return {HTMLElement} The template node
15966 findItemFromChild : function(node){
15967 var el = this.dataName ?
15968 this.el.child('.roo-tpl-' + this.dataName,true) :
15971 if(!node || node.parentNode == el){
15974 var p = node.parentNode;
15975 while(p && p != el){
15976 if(p.parentNode == el){
15985 onClick : function(e){
15986 var item = this.findItemFromChild(e.getTarget());
15988 var index = this.indexOf(item);
15989 if(this.onItemClick(item, index, e) !== false){
15990 this.fireEvent("click", this, index, item, e);
15993 this.clearSelections();
15998 onContextMenu : function(e){
15999 var item = this.findItemFromChild(e.getTarget());
16001 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16006 onDblClick : function(e){
16007 var item = this.findItemFromChild(e.getTarget());
16009 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16013 onItemClick : function(item, index, e)
16015 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16018 if (this.toggleSelect) {
16019 var m = this.isSelected(item) ? 'unselect' : 'select';
16022 _t[m](item, true, false);
16025 if(this.multiSelect || this.singleSelect){
16026 if(this.multiSelect && e.shiftKey && this.lastSelection){
16027 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16029 this.select(item, this.multiSelect && e.ctrlKey);
16030 this.lastSelection = item;
16033 if(!this.tickable){
16034 e.preventDefault();
16042 * Get the number of selected nodes.
16045 getSelectionCount : function(){
16046 return this.selections.length;
16050 * Get the currently selected nodes.
16051 * @return {Array} An array of HTMLElements
16053 getSelectedNodes : function(){
16054 return this.selections;
16058 * Get the indexes of the selected nodes.
16061 getSelectedIndexes : function(){
16062 var indexes = [], s = this.selections;
16063 for(var i = 0, len = s.length; i < len; i++){
16064 indexes.push(s[i].nodeIndex);
16070 * Clear all selections
16071 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16073 clearSelections : function(suppressEvent){
16074 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16075 this.cmp.elements = this.selections;
16076 this.cmp.removeClass(this.selectedClass);
16077 this.selections = [];
16078 if(!suppressEvent){
16079 this.fireEvent("selectionchange", this, this.selections);
16085 * Returns true if the passed node is selected
16086 * @param {HTMLElement/Number} node The node or node index
16087 * @return {Boolean}
16089 isSelected : function(node){
16090 var s = this.selections;
16094 node = this.getNode(node);
16095 return s.indexOf(node) !== -1;
16100 * @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
16101 * @param {Boolean} keepExisting (optional) true to keep existing selections
16102 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16104 select : function(nodeInfo, keepExisting, suppressEvent){
16105 if(nodeInfo instanceof Array){
16107 this.clearSelections(true);
16109 for(var i = 0, len = nodeInfo.length; i < len; i++){
16110 this.select(nodeInfo[i], true, true);
16114 var node = this.getNode(nodeInfo);
16115 if(!node || this.isSelected(node)){
16116 return; // already selected.
16119 this.clearSelections(true);
16122 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16123 Roo.fly(node).addClass(this.selectedClass);
16124 this.selections.push(node);
16125 if(!suppressEvent){
16126 this.fireEvent("selectionchange", this, this.selections);
16134 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16135 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16136 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16138 unselect : function(nodeInfo, keepExisting, suppressEvent)
16140 if(nodeInfo instanceof Array){
16141 Roo.each(this.selections, function(s) {
16142 this.unselect(s, nodeInfo);
16146 var node = this.getNode(nodeInfo);
16147 if(!node || !this.isSelected(node)){
16148 //Roo.log("not selected");
16149 return; // not selected.
16153 Roo.each(this.selections, function(s) {
16155 Roo.fly(node).removeClass(this.selectedClass);
16162 this.selections= ns;
16163 this.fireEvent("selectionchange", this, this.selections);
16167 * Gets a template node.
16168 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16169 * @return {HTMLElement} The node or null if it wasn't found
16171 getNode : function(nodeInfo){
16172 if(typeof nodeInfo == "string"){
16173 return document.getElementById(nodeInfo);
16174 }else if(typeof nodeInfo == "number"){
16175 return this.nodes[nodeInfo];
16181 * Gets a range template nodes.
16182 * @param {Number} startIndex
16183 * @param {Number} endIndex
16184 * @return {Array} An array of nodes
16186 getNodes : function(start, end){
16187 var ns = this.nodes;
16188 start = start || 0;
16189 end = typeof end == "undefined" ? ns.length - 1 : end;
16192 for(var i = start; i <= end; i++){
16196 for(var i = start; i >= end; i--){
16204 * Finds the index of the passed node
16205 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16206 * @return {Number} The index of the node or -1
16208 indexOf : function(node){
16209 node = this.getNode(node);
16210 if(typeof node.nodeIndex == "number"){
16211 return node.nodeIndex;
16213 var ns = this.nodes;
16214 for(var i = 0, len = ns.length; i < len; i++){
16225 * based on jquery fullcalendar
16229 Roo.bootstrap = Roo.bootstrap || {};
16231 * @class Roo.bootstrap.Calendar
16232 * @extends Roo.bootstrap.Component
16233 * Bootstrap Calendar class
16234 * @cfg {Boolean} loadMask (true|false) default false
16235 * @cfg {Object} header generate the user specific header of the calendar, default false
16238 * Create a new Container
16239 * @param {Object} config The config object
16244 Roo.bootstrap.Calendar = function(config){
16245 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16249 * Fires when a date is selected
16250 * @param {DatePicker} this
16251 * @param {Date} date The selected date
16255 * @event monthchange
16256 * Fires when the displayed month changes
16257 * @param {DatePicker} this
16258 * @param {Date} date The selected month
16260 'monthchange': true,
16262 * @event evententer
16263 * Fires when mouse over an event
16264 * @param {Calendar} this
16265 * @param {event} Event
16267 'evententer': true,
16269 * @event eventleave
16270 * Fires when the mouse leaves an
16271 * @param {Calendar} this
16274 'eventleave': true,
16276 * @event eventclick
16277 * Fires when the mouse click an
16278 * @param {Calendar} this
16287 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16290 * @cfg {Number} startDay
16291 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16299 getAutoCreate : function(){
16302 var fc_button = function(name, corner, style, content ) {
16303 return Roo.apply({},{
16305 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16307 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16310 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16321 style : 'width:100%',
16328 cls : 'fc-header-left',
16330 fc_button('prev', 'left', 'arrow', '‹' ),
16331 fc_button('next', 'right', 'arrow', '›' ),
16332 { tag: 'span', cls: 'fc-header-space' },
16333 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16341 cls : 'fc-header-center',
16345 cls: 'fc-header-title',
16348 html : 'month / year'
16356 cls : 'fc-header-right',
16358 /* fc_button('month', 'left', '', 'month' ),
16359 fc_button('week', '', '', 'week' ),
16360 fc_button('day', 'right', '', 'day' )
16372 header = this.header;
16375 var cal_heads = function() {
16377 // fixme - handle this.
16379 for (var i =0; i < Date.dayNames.length; i++) {
16380 var d = Date.dayNames[i];
16383 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16384 html : d.substring(0,3)
16388 ret[0].cls += ' fc-first';
16389 ret[6].cls += ' fc-last';
16392 var cal_cell = function(n) {
16395 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16400 cls: 'fc-day-number',
16404 cls: 'fc-day-content',
16408 style: 'position: relative;' // height: 17px;
16420 var cal_rows = function() {
16423 for (var r = 0; r < 6; r++) {
16430 for (var i =0; i < Date.dayNames.length; i++) {
16431 var d = Date.dayNames[i];
16432 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16435 row.cn[0].cls+=' fc-first';
16436 row.cn[0].cn[0].style = 'min-height:90px';
16437 row.cn[6].cls+=' fc-last';
16441 ret[0].cls += ' fc-first';
16442 ret[4].cls += ' fc-prev-last';
16443 ret[5].cls += ' fc-last';
16450 cls: 'fc-border-separate',
16451 style : 'width:100%',
16459 cls : 'fc-first fc-last',
16477 cls : 'fc-content',
16478 style : "position: relative;",
16481 cls : 'fc-view fc-view-month fc-grid',
16482 style : 'position: relative',
16483 unselectable : 'on',
16486 cls : 'fc-event-container',
16487 style : 'position:absolute;z-index:8;top:0;left:0;'
16505 initEvents : function()
16508 throw "can not find store for calendar";
16514 style: "text-align:center",
16518 style: "background-color:white;width:50%;margin:250 auto",
16522 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16533 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16535 var size = this.el.select('.fc-content', true).first().getSize();
16536 this.maskEl.setSize(size.width, size.height);
16537 this.maskEl.enableDisplayMode("block");
16538 if(!this.loadMask){
16539 this.maskEl.hide();
16542 this.store = Roo.factory(this.store, Roo.data);
16543 this.store.on('load', this.onLoad, this);
16544 this.store.on('beforeload', this.onBeforeLoad, this);
16548 this.cells = this.el.select('.fc-day',true);
16549 //Roo.log(this.cells);
16550 this.textNodes = this.el.query('.fc-day-number');
16551 this.cells.addClassOnOver('fc-state-hover');
16553 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16554 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16555 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16556 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16558 this.on('monthchange', this.onMonthChange, this);
16560 this.update(new Date().clearTime());
16563 resize : function() {
16564 var sz = this.el.getSize();
16566 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16567 this.el.select('.fc-day-content div',true).setHeight(34);
16572 showPrevMonth : function(e){
16573 this.update(this.activeDate.add("mo", -1));
16575 showToday : function(e){
16576 this.update(new Date().clearTime());
16579 showNextMonth : function(e){
16580 this.update(this.activeDate.add("mo", 1));
16584 showPrevYear : function(){
16585 this.update(this.activeDate.add("y", -1));
16589 showNextYear : function(){
16590 this.update(this.activeDate.add("y", 1));
16595 update : function(date)
16597 var vd = this.activeDate;
16598 this.activeDate = date;
16599 // if(vd && this.el){
16600 // var t = date.getTime();
16601 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16602 // Roo.log('using add remove');
16604 // this.fireEvent('monthchange', this, date);
16606 // this.cells.removeClass("fc-state-highlight");
16607 // this.cells.each(function(c){
16608 // if(c.dateValue == t){
16609 // c.addClass("fc-state-highlight");
16610 // setTimeout(function(){
16611 // try{c.dom.firstChild.focus();}catch(e){}
16621 var days = date.getDaysInMonth();
16623 var firstOfMonth = date.getFirstDateOfMonth();
16624 var startingPos = firstOfMonth.getDay()-this.startDay;
16626 if(startingPos < this.startDay){
16630 var pm = date.add(Date.MONTH, -1);
16631 var prevStart = pm.getDaysInMonth()-startingPos;
16633 this.cells = this.el.select('.fc-day',true);
16634 this.textNodes = this.el.query('.fc-day-number');
16635 this.cells.addClassOnOver('fc-state-hover');
16637 var cells = this.cells.elements;
16638 var textEls = this.textNodes;
16640 Roo.each(cells, function(cell){
16641 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16644 days += startingPos;
16646 // convert everything to numbers so it's fast
16647 var day = 86400000;
16648 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16651 //Roo.log(prevStart);
16653 var today = new Date().clearTime().getTime();
16654 var sel = date.clearTime().getTime();
16655 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16656 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16657 var ddMatch = this.disabledDatesRE;
16658 var ddText = this.disabledDatesText;
16659 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16660 var ddaysText = this.disabledDaysText;
16661 var format = this.format;
16663 var setCellClass = function(cal, cell){
16667 //Roo.log('set Cell Class');
16669 var t = d.getTime();
16673 cell.dateValue = t;
16675 cell.className += " fc-today";
16676 cell.className += " fc-state-highlight";
16677 cell.title = cal.todayText;
16680 // disable highlight in other month..
16681 //cell.className += " fc-state-highlight";
16686 cell.className = " fc-state-disabled";
16687 cell.title = cal.minText;
16691 cell.className = " fc-state-disabled";
16692 cell.title = cal.maxText;
16696 if(ddays.indexOf(d.getDay()) != -1){
16697 cell.title = ddaysText;
16698 cell.className = " fc-state-disabled";
16701 if(ddMatch && format){
16702 var fvalue = d.dateFormat(format);
16703 if(ddMatch.test(fvalue)){
16704 cell.title = ddText.replace("%0", fvalue);
16705 cell.className = " fc-state-disabled";
16709 if (!cell.initialClassName) {
16710 cell.initialClassName = cell.dom.className;
16713 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16718 for(; i < startingPos; i++) {
16719 textEls[i].innerHTML = (++prevStart);
16720 d.setDate(d.getDate()+1);
16722 cells[i].className = "fc-past fc-other-month";
16723 setCellClass(this, cells[i]);
16728 for(; i < days; i++){
16729 intDay = i - startingPos + 1;
16730 textEls[i].innerHTML = (intDay);
16731 d.setDate(d.getDate()+1);
16733 cells[i].className = ''; // "x-date-active";
16734 setCellClass(this, cells[i]);
16738 for(; i < 42; i++) {
16739 textEls[i].innerHTML = (++extraDays);
16740 d.setDate(d.getDate()+1);
16742 cells[i].className = "fc-future fc-other-month";
16743 setCellClass(this, cells[i]);
16746 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16748 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16750 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16751 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16753 if(totalRows != 6){
16754 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16755 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16758 this.fireEvent('monthchange', this, date);
16762 if(!this.internalRender){
16763 var main = this.el.dom.firstChild;
16764 var w = main.offsetWidth;
16765 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16766 Roo.fly(main).setWidth(w);
16767 this.internalRender = true;
16768 // opera does not respect the auto grow header center column
16769 // then, after it gets a width opera refuses to recalculate
16770 // without a second pass
16771 if(Roo.isOpera && !this.secondPass){
16772 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16773 this.secondPass = true;
16774 this.update.defer(10, this, [date]);
16781 findCell : function(dt) {
16782 dt = dt.clearTime().getTime();
16784 this.cells.each(function(c){
16785 //Roo.log("check " +c.dateValue + '?=' + dt);
16786 if(c.dateValue == dt){
16796 findCells : function(ev) {
16797 var s = ev.start.clone().clearTime().getTime();
16799 var e= ev.end.clone().clearTime().getTime();
16802 this.cells.each(function(c){
16803 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16805 if(c.dateValue > e){
16808 if(c.dateValue < s){
16817 // findBestRow: function(cells)
16821 // for (var i =0 ; i < cells.length;i++) {
16822 // ret = Math.max(cells[i].rows || 0,ret);
16829 addItem : function(ev)
16831 // look for vertical location slot in
16832 var cells = this.findCells(ev);
16834 // ev.row = this.findBestRow(cells);
16836 // work out the location.
16840 for(var i =0; i < cells.length; i++) {
16842 cells[i].row = cells[0].row;
16845 cells[i].row = cells[i].row + 1;
16855 if (crow.start.getY() == cells[i].getY()) {
16857 crow.end = cells[i];
16874 cells[0].events.push(ev);
16876 this.calevents.push(ev);
16879 clearEvents: function() {
16881 if(!this.calevents){
16885 Roo.each(this.cells.elements, function(c){
16891 Roo.each(this.calevents, function(e) {
16892 Roo.each(e.els, function(el) {
16893 el.un('mouseenter' ,this.onEventEnter, this);
16894 el.un('mouseleave' ,this.onEventLeave, this);
16899 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16905 renderEvents: function()
16909 this.cells.each(function(c) {
16918 if(c.row != c.events.length){
16919 r = 4 - (4 - (c.row - c.events.length));
16922 c.events = ev.slice(0, r);
16923 c.more = ev.slice(r);
16925 if(c.more.length && c.more.length == 1){
16926 c.events.push(c.more.pop());
16929 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16933 this.cells.each(function(c) {
16935 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16938 for (var e = 0; e < c.events.length; e++){
16939 var ev = c.events[e];
16940 var rows = ev.rows;
16942 for(var i = 0; i < rows.length; i++) {
16944 // how many rows should it span..
16947 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16948 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16950 unselectable : "on",
16953 cls: 'fc-event-inner',
16957 // cls: 'fc-event-time',
16958 // html : cells.length > 1 ? '' : ev.time
16962 cls: 'fc-event-title',
16963 html : String.format('{0}', ev.title)
16970 cls: 'ui-resizable-handle ui-resizable-e',
16971 html : '  '
16978 cfg.cls += ' fc-event-start';
16980 if ((i+1) == rows.length) {
16981 cfg.cls += ' fc-event-end';
16984 var ctr = _this.el.select('.fc-event-container',true).first();
16985 var cg = ctr.createChild(cfg);
16987 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16988 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16990 var r = (c.more.length) ? 1 : 0;
16991 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16992 cg.setWidth(ebox.right - sbox.x -2);
16994 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16995 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16996 cg.on('click', _this.onEventClick, _this, ev);
17007 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17008 style : 'position: absolute',
17009 unselectable : "on",
17012 cls: 'fc-event-inner',
17016 cls: 'fc-event-title',
17024 cls: 'ui-resizable-handle ui-resizable-e',
17025 html : '  '
17031 var ctr = _this.el.select('.fc-event-container',true).first();
17032 var cg = ctr.createChild(cfg);
17034 var sbox = c.select('.fc-day-content',true).first().getBox();
17035 var ebox = c.select('.fc-day-content',true).first().getBox();
17037 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17038 cg.setWidth(ebox.right - sbox.x -2);
17040 cg.on('click', _this.onMoreEventClick, _this, c.more);
17050 onEventEnter: function (e, el,event,d) {
17051 this.fireEvent('evententer', this, el, event);
17054 onEventLeave: function (e, el,event,d) {
17055 this.fireEvent('eventleave', this, el, event);
17058 onEventClick: function (e, el,event,d) {
17059 this.fireEvent('eventclick', this, el, event);
17062 onMonthChange: function () {
17066 onMoreEventClick: function(e, el, more)
17070 this.calpopover.placement = 'right';
17071 this.calpopover.setTitle('More');
17073 this.calpopover.setContent('');
17075 var ctr = this.calpopover.el.select('.popover-content', true).first();
17077 Roo.each(more, function(m){
17079 cls : 'fc-event-hori fc-event-draggable',
17082 var cg = ctr.createChild(cfg);
17084 cg.on('click', _this.onEventClick, _this, m);
17087 this.calpopover.show(el);
17092 onLoad: function ()
17094 this.calevents = [];
17097 if(this.store.getCount() > 0){
17098 this.store.data.each(function(d){
17101 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17102 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17103 time : d.data.start_time,
17104 title : d.data.title,
17105 description : d.data.description,
17106 venue : d.data.venue
17111 this.renderEvents();
17113 if(this.calevents.length && this.loadMask){
17114 this.maskEl.hide();
17118 onBeforeLoad: function()
17120 this.clearEvents();
17122 this.maskEl.show();
17136 * @class Roo.bootstrap.Popover
17137 * @extends Roo.bootstrap.Component
17138 * Bootstrap Popover class
17139 * @cfg {String} html contents of the popover (or false to use children..)
17140 * @cfg {String} title of popover (or false to hide)
17141 * @cfg {String} placement how it is placed
17142 * @cfg {String} trigger click || hover (or false to trigger manually)
17143 * @cfg {String} over what (parent or false to trigger manually.)
17144 * @cfg {Number} delay - delay before showing
17147 * Create a new Popover
17148 * @param {Object} config The config object
17151 Roo.bootstrap.Popover = function(config){
17152 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17158 * After the popover show
17160 * @param {Roo.bootstrap.Popover} this
17165 * After the popover hide
17167 * @param {Roo.bootstrap.Popover} this
17173 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17175 title: 'Fill in a title',
17178 placement : 'right',
17179 trigger : 'hover', // hover
17185 can_build_overlaid : false,
17187 getChildContainer : function()
17189 return this.el.select('.popover-content',true).first();
17192 getAutoCreate : function(){
17195 cls : 'popover roo-dynamic',
17196 style: 'display:block',
17202 cls : 'popover-inner',
17206 cls: 'popover-title',
17210 cls : 'popover-content',
17221 setTitle: function(str)
17224 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17226 setContent: function(str)
17229 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17231 // as it get's added to the bottom of the page.
17232 onRender : function(ct, position)
17234 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17236 var cfg = Roo.apply({}, this.getAutoCreate());
17240 cfg.cls += ' ' + this.cls;
17243 cfg.style = this.style;
17245 //Roo.log("adding to ");
17246 this.el = Roo.get(document.body).createChild(cfg, position);
17247 // Roo.log(this.el);
17252 initEvents : function()
17254 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17255 this.el.enableDisplayMode('block');
17257 if (this.over === false) {
17260 if (this.triggers === false) {
17263 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17264 var triggers = this.trigger ? this.trigger.split(' ') : [];
17265 Roo.each(triggers, function(trigger) {
17267 if (trigger == 'click') {
17268 on_el.on('click', this.toggle, this);
17269 } else if (trigger != 'manual') {
17270 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17271 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17273 on_el.on(eventIn ,this.enter, this);
17274 on_el.on(eventOut, this.leave, this);
17285 toggle : function () {
17286 this.hoverState == 'in' ? this.leave() : this.enter();
17289 enter : function () {
17291 clearTimeout(this.timeout);
17293 this.hoverState = 'in';
17295 if (!this.delay || !this.delay.show) {
17300 this.timeout = setTimeout(function () {
17301 if (_t.hoverState == 'in') {
17304 }, this.delay.show)
17307 leave : function() {
17308 clearTimeout(this.timeout);
17310 this.hoverState = 'out';
17312 if (!this.delay || !this.delay.hide) {
17317 this.timeout = setTimeout(function () {
17318 if (_t.hoverState == 'out') {
17321 }, this.delay.hide)
17324 show : function (on_el)
17327 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17331 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17332 if (this.html !== false) {
17333 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17335 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17336 if (!this.title.length) {
17337 this.el.select('.popover-title',true).hide();
17340 var placement = typeof this.placement == 'function' ?
17341 this.placement.call(this, this.el, on_el) :
17344 var autoToken = /\s?auto?\s?/i;
17345 var autoPlace = autoToken.test(placement);
17347 placement = placement.replace(autoToken, '') || 'top';
17351 //this.el.setXY([0,0]);
17353 this.el.dom.style.display='block';
17354 this.el.addClass(placement);
17356 //this.el.appendTo(on_el);
17358 var p = this.getPosition();
17359 var box = this.el.getBox();
17364 var align = Roo.bootstrap.Popover.alignment[placement];
17367 this.el.alignTo(on_el, align[0],align[1]);
17368 //var arrow = this.el.select('.arrow',true).first();
17369 //arrow.set(align[2],
17371 this.el.addClass('in');
17374 if (this.el.hasClass('fade')) {
17378 this.hoverState = 'in';
17380 this.fireEvent('show', this);
17385 this.el.setXY([0,0]);
17386 this.el.removeClass('in');
17388 this.hoverState = null;
17390 this.fireEvent('hide', this);
17395 Roo.bootstrap.Popover.alignment = {
17396 'left' : ['r-l', [-10,0], 'right'],
17397 'right' : ['l-r', [10,0], 'left'],
17398 'bottom' : ['t-b', [0,10], 'top'],
17399 'top' : [ 'b-t', [0,-10], 'bottom']
17410 * @class Roo.bootstrap.Progress
17411 * @extends Roo.bootstrap.Component
17412 * Bootstrap Progress class
17413 * @cfg {Boolean} striped striped of the progress bar
17414 * @cfg {Boolean} active animated of the progress bar
17418 * Create a new Progress
17419 * @param {Object} config The config object
17422 Roo.bootstrap.Progress = function(config){
17423 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17426 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17431 getAutoCreate : function(){
17439 cfg.cls += ' progress-striped';
17443 cfg.cls += ' active';
17462 * @class Roo.bootstrap.ProgressBar
17463 * @extends Roo.bootstrap.Component
17464 * Bootstrap ProgressBar class
17465 * @cfg {Number} aria_valuenow aria-value now
17466 * @cfg {Number} aria_valuemin aria-value min
17467 * @cfg {Number} aria_valuemax aria-value max
17468 * @cfg {String} label label for the progress bar
17469 * @cfg {String} panel (success | info | warning | danger )
17470 * @cfg {String} role role of the progress bar
17471 * @cfg {String} sr_only text
17475 * Create a new ProgressBar
17476 * @param {Object} config The config object
17479 Roo.bootstrap.ProgressBar = function(config){
17480 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17483 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17487 aria_valuemax : 100,
17493 getAutoCreate : function()
17498 cls: 'progress-bar',
17499 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17511 cfg.role = this.role;
17514 if(this.aria_valuenow){
17515 cfg['aria-valuenow'] = this.aria_valuenow;
17518 if(this.aria_valuemin){
17519 cfg['aria-valuemin'] = this.aria_valuemin;
17522 if(this.aria_valuemax){
17523 cfg['aria-valuemax'] = this.aria_valuemax;
17526 if(this.label && !this.sr_only){
17527 cfg.html = this.label;
17531 cfg.cls += ' progress-bar-' + this.panel;
17537 update : function(aria_valuenow)
17539 this.aria_valuenow = aria_valuenow;
17541 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17556 * @class Roo.bootstrap.TabGroup
17557 * @extends Roo.bootstrap.Column
17558 * Bootstrap Column class
17559 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17560 * @cfg {Boolean} carousel true to make the group behave like a carousel
17561 * @cfg {Boolean} bullets show bullets for the panels
17562 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17563 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17564 * @cfg {Boolean} showarrow (true|false) show arrow default true
17567 * Create a new TabGroup
17568 * @param {Object} config The config object
17571 Roo.bootstrap.TabGroup = function(config){
17572 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17574 this.navId = Roo.id();
17577 Roo.bootstrap.TabGroup.register(this);
17581 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17584 transition : false,
17589 slideOnTouch : false,
17592 getAutoCreate : function()
17594 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17596 cfg.cls += ' tab-content';
17598 if (this.carousel) {
17599 cfg.cls += ' carousel slide';
17602 cls : 'carousel-inner',
17606 if(this.bullets && !Roo.isTouch){
17609 cls : 'carousel-bullets',
17613 if(this.bullets_cls){
17614 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17621 cfg.cn[0].cn.push(bullets);
17624 if(this.showarrow){
17625 cfg.cn[0].cn.push({
17627 class : 'carousel-arrow',
17631 class : 'carousel-prev',
17635 class : 'fa fa-chevron-left'
17641 class : 'carousel-next',
17645 class : 'fa fa-chevron-right'
17658 initEvents: function()
17660 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17661 // this.el.on("touchstart", this.onTouchStart, this);
17664 if(this.autoslide){
17667 this.slideFn = window.setInterval(function() {
17668 _this.showPanelNext();
17672 if(this.showarrow){
17673 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17674 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17680 // onTouchStart : function(e, el, o)
17682 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17686 // this.showPanelNext();
17690 getChildContainer : function()
17692 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17696 * register a Navigation item
17697 * @param {Roo.bootstrap.NavItem} the navitem to add
17699 register : function(item)
17701 this.tabs.push( item);
17702 item.navId = this.navId; // not really needed..
17707 getActivePanel : function()
17710 Roo.each(this.tabs, function(t) {
17720 getPanelByName : function(n)
17723 Roo.each(this.tabs, function(t) {
17724 if (t.tabId == n) {
17732 indexOfPanel : function(p)
17735 Roo.each(this.tabs, function(t,i) {
17736 if (t.tabId == p.tabId) {
17745 * show a specific panel
17746 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17747 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17749 showPanel : function (pan)
17751 if(this.transition || typeof(pan) == 'undefined'){
17752 Roo.log("waiting for the transitionend");
17756 if (typeof(pan) == 'number') {
17757 pan = this.tabs[pan];
17760 if (typeof(pan) == 'string') {
17761 pan = this.getPanelByName(pan);
17764 var cur = this.getActivePanel();
17767 Roo.log('pan or acitve pan is undefined');
17771 if (pan.tabId == this.getActivePanel().tabId) {
17775 if (false === cur.fireEvent('beforedeactivate')) {
17779 if(this.bullets > 0 && !Roo.isTouch){
17780 this.setActiveBullet(this.indexOfPanel(pan));
17783 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17785 this.transition = true;
17786 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17787 var lr = dir == 'next' ? 'left' : 'right';
17788 pan.el.addClass(dir); // or prev
17789 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17790 cur.el.addClass(lr); // or right
17791 pan.el.addClass(lr);
17794 cur.el.on('transitionend', function() {
17795 Roo.log("trans end?");
17797 pan.el.removeClass([lr,dir]);
17798 pan.setActive(true);
17800 cur.el.removeClass([lr]);
17801 cur.setActive(false);
17803 _this.transition = false;
17805 }, this, { single: true } );
17810 cur.setActive(false);
17811 pan.setActive(true);
17816 showPanelNext : function()
17818 var i = this.indexOfPanel(this.getActivePanel());
17820 if (i >= this.tabs.length - 1 && !this.autoslide) {
17824 if (i >= this.tabs.length - 1 && this.autoslide) {
17828 this.showPanel(this.tabs[i+1]);
17831 showPanelPrev : function()
17833 var i = this.indexOfPanel(this.getActivePanel());
17835 if (i < 1 && !this.autoslide) {
17839 if (i < 1 && this.autoslide) {
17840 i = this.tabs.length;
17843 this.showPanel(this.tabs[i-1]);
17847 addBullet: function()
17849 if(!this.bullets || Roo.isTouch){
17852 var ctr = this.el.select('.carousel-bullets',true).first();
17853 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17854 var bullet = ctr.createChild({
17855 cls : 'bullet bullet-' + i
17856 },ctr.dom.lastChild);
17861 bullet.on('click', (function(e, el, o, ii, t){
17863 e.preventDefault();
17865 this.showPanel(ii);
17867 if(this.autoslide && this.slideFn){
17868 clearInterval(this.slideFn);
17869 this.slideFn = window.setInterval(function() {
17870 _this.showPanelNext();
17874 }).createDelegate(this, [i, bullet], true));
17879 setActiveBullet : function(i)
17885 Roo.each(this.el.select('.bullet', true).elements, function(el){
17886 el.removeClass('selected');
17889 var bullet = this.el.select('.bullet-' + i, true).first();
17895 bullet.addClass('selected');
17906 Roo.apply(Roo.bootstrap.TabGroup, {
17910 * register a Navigation Group
17911 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17913 register : function(navgrp)
17915 this.groups[navgrp.navId] = navgrp;
17919 * fetch a Navigation Group based on the navigation ID
17920 * if one does not exist , it will get created.
17921 * @param {string} the navgroup to add
17922 * @returns {Roo.bootstrap.NavGroup} the navgroup
17924 get: function(navId) {
17925 if (typeof(this.groups[navId]) == 'undefined') {
17926 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17928 return this.groups[navId] ;
17943 * @class Roo.bootstrap.TabPanel
17944 * @extends Roo.bootstrap.Component
17945 * Bootstrap TabPanel class
17946 * @cfg {Boolean} active panel active
17947 * @cfg {String} html panel content
17948 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17949 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17950 * @cfg {String} href click to link..
17954 * Create a new TabPanel
17955 * @param {Object} config The config object
17958 Roo.bootstrap.TabPanel = function(config){
17959 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17963 * Fires when the active status changes
17964 * @param {Roo.bootstrap.TabPanel} this
17965 * @param {Boolean} state the new state
17970 * @event beforedeactivate
17971 * Fires before a tab is de-activated - can be used to do validation on a form.
17972 * @param {Roo.bootstrap.TabPanel} this
17973 * @return {Boolean} false if there is an error
17976 'beforedeactivate': true
17979 this.tabId = this.tabId || Roo.id();
17983 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17991 getAutoCreate : function(){
17994 // item is needed for carousel - not sure if it has any effect otherwise
17995 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17996 html: this.html || ''
18000 cfg.cls += ' active';
18004 cfg.tabId = this.tabId;
18011 initEvents: function()
18013 var p = this.parent();
18015 this.navId = this.navId || p.navId;
18017 if (typeof(this.navId) != 'undefined') {
18018 // not really needed.. but just in case.. parent should be a NavGroup.
18019 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18023 var i = tg.tabs.length - 1;
18025 if(this.active && tg.bullets > 0 && i < tg.bullets){
18026 tg.setActiveBullet(i);
18030 this.el.on('click', this.onClick, this);
18033 this.el.on("touchstart", this.onTouchStart, this);
18034 this.el.on("touchmove", this.onTouchMove, this);
18035 this.el.on("touchend", this.onTouchEnd, this);
18040 onRender : function(ct, position)
18042 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18045 setActive : function(state)
18047 Roo.log("panel - set active " + this.tabId + "=" + state);
18049 this.active = state;
18051 this.el.removeClass('active');
18053 } else if (!this.el.hasClass('active')) {
18054 this.el.addClass('active');
18057 this.fireEvent('changed', this, state);
18060 onClick : function(e)
18062 e.preventDefault();
18064 if(!this.href.length){
18068 window.location.href = this.href;
18077 onTouchStart : function(e)
18079 this.swiping = false;
18081 this.startX = e.browserEvent.touches[0].clientX;
18082 this.startY = e.browserEvent.touches[0].clientY;
18085 onTouchMove : function(e)
18087 this.swiping = true;
18089 this.endX = e.browserEvent.touches[0].clientX;
18090 this.endY = e.browserEvent.touches[0].clientY;
18093 onTouchEnd : function(e)
18100 var tabGroup = this.parent();
18102 if(this.endX > this.startX){ // swiping right
18103 tabGroup.showPanelPrev();
18107 if(this.startX > this.endX){ // swiping left
18108 tabGroup.showPanelNext();
18127 * @class Roo.bootstrap.DateField
18128 * @extends Roo.bootstrap.Input
18129 * Bootstrap DateField class
18130 * @cfg {Number} weekStart default 0
18131 * @cfg {String} viewMode default empty, (months|years)
18132 * @cfg {String} minViewMode default empty, (months|years)
18133 * @cfg {Number} startDate default -Infinity
18134 * @cfg {Number} endDate default Infinity
18135 * @cfg {Boolean} todayHighlight default false
18136 * @cfg {Boolean} todayBtn default false
18137 * @cfg {Boolean} calendarWeeks default false
18138 * @cfg {Object} daysOfWeekDisabled default empty
18139 * @cfg {Boolean} singleMode default false (true | false)
18141 * @cfg {Boolean} keyboardNavigation default true
18142 * @cfg {String} language default en
18145 * Create a new DateField
18146 * @param {Object} config The config object
18149 Roo.bootstrap.DateField = function(config){
18150 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18154 * Fires when this field show.
18155 * @param {Roo.bootstrap.DateField} this
18156 * @param {Mixed} date The date value
18161 * Fires when this field hide.
18162 * @param {Roo.bootstrap.DateField} this
18163 * @param {Mixed} date The date value
18168 * Fires when select a date.
18169 * @param {Roo.bootstrap.DateField} this
18170 * @param {Mixed} date The date value
18174 * @event beforeselect
18175 * Fires when before select a date.
18176 * @param {Roo.bootstrap.DateField} this
18177 * @param {Mixed} date The date value
18179 beforeselect : true
18183 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18186 * @cfg {String} format
18187 * The default date format string which can be overriden for localization support. The format must be
18188 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18192 * @cfg {String} altFormats
18193 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18194 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18196 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18204 todayHighlight : false,
18210 keyboardNavigation: true,
18212 calendarWeeks: false,
18214 startDate: -Infinity,
18218 daysOfWeekDisabled: [],
18222 singleMode : false,
18224 UTCDate: function()
18226 return new Date(Date.UTC.apply(Date, arguments));
18229 UTCToday: function()
18231 var today = new Date();
18232 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18235 getDate: function() {
18236 var d = this.getUTCDate();
18237 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18240 getUTCDate: function() {
18244 setDate: function(d) {
18245 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18248 setUTCDate: function(d) {
18250 this.setValue(this.formatDate(this.date));
18253 onRender: function(ct, position)
18256 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18258 this.language = this.language || 'en';
18259 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18260 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18262 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18263 this.format = this.format || 'm/d/y';
18264 this.isInline = false;
18265 this.isInput = true;
18266 this.component = this.el.select('.add-on', true).first() || false;
18267 this.component = (this.component && this.component.length === 0) ? false : this.component;
18268 this.hasInput = this.component && this.inputEl().length;
18270 if (typeof(this.minViewMode === 'string')) {
18271 switch (this.minViewMode) {
18273 this.minViewMode = 1;
18276 this.minViewMode = 2;
18279 this.minViewMode = 0;
18284 if (typeof(this.viewMode === 'string')) {
18285 switch (this.viewMode) {
18298 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18300 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18302 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18304 this.picker().on('mousedown', this.onMousedown, this);
18305 this.picker().on('click', this.onClick, this);
18307 this.picker().addClass('datepicker-dropdown');
18309 this.startViewMode = this.viewMode;
18311 if(this.singleMode){
18312 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18313 v.setVisibilityMode(Roo.Element.DISPLAY);
18317 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18318 v.setStyle('width', '189px');
18322 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18323 if(!this.calendarWeeks){
18328 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18329 v.attr('colspan', function(i, val){
18330 return parseInt(val) + 1;
18335 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18337 this.setStartDate(this.startDate);
18338 this.setEndDate(this.endDate);
18340 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18347 if(this.isInline) {
18352 picker : function()
18354 return this.pickerEl;
18355 // return this.el.select('.datepicker', true).first();
18358 fillDow: function()
18360 var dowCnt = this.weekStart;
18369 if(this.calendarWeeks){
18377 while (dowCnt < this.weekStart + 7) {
18381 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18385 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18388 fillMonths: function()
18391 var months = this.picker().select('>.datepicker-months td', true).first();
18393 months.dom.innerHTML = '';
18399 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18402 months.createChild(month);
18409 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;
18411 if (this.date < this.startDate) {
18412 this.viewDate = new Date(this.startDate);
18413 } else if (this.date > this.endDate) {
18414 this.viewDate = new Date(this.endDate);
18416 this.viewDate = new Date(this.date);
18424 var d = new Date(this.viewDate),
18425 year = d.getUTCFullYear(),
18426 month = d.getUTCMonth(),
18427 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18428 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18429 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18430 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18431 currentDate = this.date && this.date.valueOf(),
18432 today = this.UTCToday();
18434 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18436 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18438 // this.picker.select('>tfoot th.today').
18439 // .text(dates[this.language].today)
18440 // .toggle(this.todayBtn !== false);
18442 this.updateNavArrows();
18445 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18447 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18449 prevMonth.setUTCDate(day);
18451 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18453 var nextMonth = new Date(prevMonth);
18455 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18457 nextMonth = nextMonth.valueOf();
18459 var fillMonths = false;
18461 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18463 while(prevMonth.valueOf() < nextMonth) {
18466 if (prevMonth.getUTCDay() === this.weekStart) {
18468 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18476 if(this.calendarWeeks){
18477 // ISO 8601: First week contains first thursday.
18478 // ISO also states week starts on Monday, but we can be more abstract here.
18480 // Start of current week: based on weekstart/current date
18481 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18482 // Thursday of this week
18483 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18484 // First Thursday of year, year from thursday
18485 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18486 // Calendar week: ms between thursdays, div ms per day, div 7 days
18487 calWeek = (th - yth) / 864e5 / 7 + 1;
18489 fillMonths.cn.push({
18497 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18499 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18502 if (this.todayHighlight &&
18503 prevMonth.getUTCFullYear() == today.getFullYear() &&
18504 prevMonth.getUTCMonth() == today.getMonth() &&
18505 prevMonth.getUTCDate() == today.getDate()) {
18506 clsName += ' today';
18509 if (currentDate && prevMonth.valueOf() === currentDate) {
18510 clsName += ' active';
18513 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18514 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18515 clsName += ' disabled';
18518 fillMonths.cn.push({
18520 cls: 'day ' + clsName,
18521 html: prevMonth.getDate()
18524 prevMonth.setDate(prevMonth.getDate()+1);
18527 var currentYear = this.date && this.date.getUTCFullYear();
18528 var currentMonth = this.date && this.date.getUTCMonth();
18530 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18532 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18533 v.removeClass('active');
18535 if(currentYear === year && k === currentMonth){
18536 v.addClass('active');
18539 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18540 v.addClass('disabled');
18546 year = parseInt(year/10, 10) * 10;
18548 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18550 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18553 for (var i = -1; i < 11; i++) {
18554 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18556 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18564 showMode: function(dir)
18567 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18570 Roo.each(this.picker().select('>div',true).elements, function(v){
18571 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18574 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18579 if(this.isInline) {
18583 this.picker().removeClass(['bottom', 'top']);
18585 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18587 * place to the top of element!
18591 this.picker().addClass('top');
18592 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18597 this.picker().addClass('bottom');
18599 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18602 parseDate : function(value)
18604 if(!value || value instanceof Date){
18607 var v = Date.parseDate(value, this.format);
18608 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18609 v = Date.parseDate(value, 'Y-m-d');
18611 if(!v && this.altFormats){
18612 if(!this.altFormatsArray){
18613 this.altFormatsArray = this.altFormats.split("|");
18615 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18616 v = Date.parseDate(value, this.altFormatsArray[i]);
18622 formatDate : function(date, fmt)
18624 return (!date || !(date instanceof Date)) ?
18625 date : date.dateFormat(fmt || this.format);
18628 onFocus : function()
18630 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18634 onBlur : function()
18636 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18638 var d = this.inputEl().getValue();
18647 this.picker().show();
18651 this.fireEvent('show', this, this.date);
18656 if(this.isInline) {
18659 this.picker().hide();
18660 this.viewMode = this.startViewMode;
18663 this.fireEvent('hide', this, this.date);
18667 onMousedown: function(e)
18669 e.stopPropagation();
18670 e.preventDefault();
18675 Roo.bootstrap.DateField.superclass.keyup.call(this);
18679 setValue: function(v)
18681 if(this.fireEvent('beforeselect', this, v) !== false){
18682 var d = new Date(this.parseDate(v) ).clearTime();
18684 if(isNaN(d.getTime())){
18685 this.date = this.viewDate = '';
18686 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18690 v = this.formatDate(d);
18692 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18694 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18698 this.fireEvent('select', this, this.date);
18702 getValue: function()
18704 return this.formatDate(this.date);
18707 fireKey: function(e)
18709 if (!this.picker().isVisible()){
18710 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18716 var dateChanged = false,
18718 newDate, newViewDate;
18723 e.preventDefault();
18727 if (!this.keyboardNavigation) {
18730 dir = e.keyCode == 37 ? -1 : 1;
18733 newDate = this.moveYear(this.date, dir);
18734 newViewDate = this.moveYear(this.viewDate, dir);
18735 } else if (e.shiftKey){
18736 newDate = this.moveMonth(this.date, dir);
18737 newViewDate = this.moveMonth(this.viewDate, dir);
18739 newDate = new Date(this.date);
18740 newDate.setUTCDate(this.date.getUTCDate() + dir);
18741 newViewDate = new Date(this.viewDate);
18742 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18744 if (this.dateWithinRange(newDate)){
18745 this.date = newDate;
18746 this.viewDate = newViewDate;
18747 this.setValue(this.formatDate(this.date));
18749 e.preventDefault();
18750 dateChanged = true;
18755 if (!this.keyboardNavigation) {
18758 dir = e.keyCode == 38 ? -1 : 1;
18760 newDate = this.moveYear(this.date, dir);
18761 newViewDate = this.moveYear(this.viewDate, dir);
18762 } else if (e.shiftKey){
18763 newDate = this.moveMonth(this.date, dir);
18764 newViewDate = this.moveMonth(this.viewDate, dir);
18766 newDate = new Date(this.date);
18767 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18768 newViewDate = new Date(this.viewDate);
18769 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18771 if (this.dateWithinRange(newDate)){
18772 this.date = newDate;
18773 this.viewDate = newViewDate;
18774 this.setValue(this.formatDate(this.date));
18776 e.preventDefault();
18777 dateChanged = true;
18781 this.setValue(this.formatDate(this.date));
18783 e.preventDefault();
18786 this.setValue(this.formatDate(this.date));
18800 onClick: function(e)
18802 e.stopPropagation();
18803 e.preventDefault();
18805 var target = e.getTarget();
18807 if(target.nodeName.toLowerCase() === 'i'){
18808 target = Roo.get(target).dom.parentNode;
18811 var nodeName = target.nodeName;
18812 var className = target.className;
18813 var html = target.innerHTML;
18814 //Roo.log(nodeName);
18816 switch(nodeName.toLowerCase()) {
18818 switch(className) {
18824 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18825 switch(this.viewMode){
18827 this.viewDate = this.moveMonth(this.viewDate, dir);
18831 this.viewDate = this.moveYear(this.viewDate, dir);
18837 var date = new Date();
18838 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18840 this.setValue(this.formatDate(this.date));
18847 if (className.indexOf('disabled') < 0) {
18848 this.viewDate.setUTCDate(1);
18849 if (className.indexOf('month') > -1) {
18850 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18852 var year = parseInt(html, 10) || 0;
18853 this.viewDate.setUTCFullYear(year);
18857 if(this.singleMode){
18858 this.setValue(this.formatDate(this.viewDate));
18869 //Roo.log(className);
18870 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18871 var day = parseInt(html, 10) || 1;
18872 var year = this.viewDate.getUTCFullYear(),
18873 month = this.viewDate.getUTCMonth();
18875 if (className.indexOf('old') > -1) {
18882 } else if (className.indexOf('new') > -1) {
18890 //Roo.log([year,month,day]);
18891 this.date = this.UTCDate(year, month, day,0,0,0,0);
18892 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18894 //Roo.log(this.formatDate(this.date));
18895 this.setValue(this.formatDate(this.date));
18902 setStartDate: function(startDate)
18904 this.startDate = startDate || -Infinity;
18905 if (this.startDate !== -Infinity) {
18906 this.startDate = this.parseDate(this.startDate);
18909 this.updateNavArrows();
18912 setEndDate: function(endDate)
18914 this.endDate = endDate || Infinity;
18915 if (this.endDate !== Infinity) {
18916 this.endDate = this.parseDate(this.endDate);
18919 this.updateNavArrows();
18922 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18924 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18925 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18926 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18928 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18929 return parseInt(d, 10);
18932 this.updateNavArrows();
18935 updateNavArrows: function()
18937 if(this.singleMode){
18941 var d = new Date(this.viewDate),
18942 year = d.getUTCFullYear(),
18943 month = d.getUTCMonth();
18945 Roo.each(this.picker().select('.prev', true).elements, function(v){
18947 switch (this.viewMode) {
18950 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18956 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18963 Roo.each(this.picker().select('.next', true).elements, function(v){
18965 switch (this.viewMode) {
18968 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18974 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18982 moveMonth: function(date, dir)
18987 var new_date = new Date(date.valueOf()),
18988 day = new_date.getUTCDate(),
18989 month = new_date.getUTCMonth(),
18990 mag = Math.abs(dir),
18992 dir = dir > 0 ? 1 : -1;
18995 // If going back one month, make sure month is not current month
18996 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18998 return new_date.getUTCMonth() == month;
19000 // If going forward one month, make sure month is as expected
19001 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19003 return new_date.getUTCMonth() != new_month;
19005 new_month = month + dir;
19006 new_date.setUTCMonth(new_month);
19007 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19008 if (new_month < 0 || new_month > 11) {
19009 new_month = (new_month + 12) % 12;
19012 // For magnitudes >1, move one month at a time...
19013 for (var i=0; i<mag; i++) {
19014 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19015 new_date = this.moveMonth(new_date, dir);
19017 // ...then reset the day, keeping it in the new month
19018 new_month = new_date.getUTCMonth();
19019 new_date.setUTCDate(day);
19021 return new_month != new_date.getUTCMonth();
19024 // Common date-resetting loop -- if date is beyond end of month, make it
19027 new_date.setUTCDate(--day);
19028 new_date.setUTCMonth(new_month);
19033 moveYear: function(date, dir)
19035 return this.moveMonth(date, dir*12);
19038 dateWithinRange: function(date)
19040 return date >= this.startDate && date <= this.endDate;
19046 this.picker().remove();
19049 validateValue : function(value)
19051 if(value.length < 1) {
19052 if(this.allowBlank){
19058 if(value.length < this.minLength){
19061 if(value.length > this.maxLength){
19065 var vt = Roo.form.VTypes;
19066 if(!vt[this.vtype](value, this)){
19070 if(typeof this.validator == "function"){
19071 var msg = this.validator(value);
19077 if(this.regex && !this.regex.test(value)){
19081 if(typeof(this.parseDate(value)) == 'undefined'){
19085 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19089 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19099 Roo.apply(Roo.bootstrap.DateField, {
19110 html: '<i class="fa fa-arrow-left"/>'
19120 html: '<i class="fa fa-arrow-right"/>'
19162 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19163 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19164 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19165 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19166 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19179 navFnc: 'FullYear',
19184 navFnc: 'FullYear',
19189 Roo.apply(Roo.bootstrap.DateField, {
19193 cls: 'datepicker dropdown-menu roo-dynamic',
19197 cls: 'datepicker-days',
19201 cls: 'table-condensed',
19203 Roo.bootstrap.DateField.head,
19207 Roo.bootstrap.DateField.footer
19214 cls: 'datepicker-months',
19218 cls: 'table-condensed',
19220 Roo.bootstrap.DateField.head,
19221 Roo.bootstrap.DateField.content,
19222 Roo.bootstrap.DateField.footer
19229 cls: 'datepicker-years',
19233 cls: 'table-condensed',
19235 Roo.bootstrap.DateField.head,
19236 Roo.bootstrap.DateField.content,
19237 Roo.bootstrap.DateField.footer
19256 * @class Roo.bootstrap.TimeField
19257 * @extends Roo.bootstrap.Input
19258 * Bootstrap DateField class
19262 * Create a new TimeField
19263 * @param {Object} config The config object
19266 Roo.bootstrap.TimeField = function(config){
19267 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19271 * Fires when this field show.
19272 * @param {Roo.bootstrap.DateField} thisthis
19273 * @param {Mixed} date The date value
19278 * Fires when this field hide.
19279 * @param {Roo.bootstrap.DateField} this
19280 * @param {Mixed} date The date value
19285 * Fires when select a date.
19286 * @param {Roo.bootstrap.DateField} this
19287 * @param {Mixed} date The date value
19293 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19296 * @cfg {String} format
19297 * The default time format string which can be overriden for localization support. The format must be
19298 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19302 onRender: function(ct, position)
19305 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19307 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19309 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19311 this.pop = this.picker().select('>.datepicker-time',true).first();
19312 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19314 this.picker().on('mousedown', this.onMousedown, this);
19315 this.picker().on('click', this.onClick, this);
19317 this.picker().addClass('datepicker-dropdown');
19322 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19323 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19324 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19325 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19326 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19327 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19331 fireKey: function(e){
19332 if (!this.picker().isVisible()){
19333 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19339 e.preventDefault();
19347 this.onTogglePeriod();
19350 this.onIncrementMinutes();
19353 this.onDecrementMinutes();
19362 onClick: function(e) {
19363 e.stopPropagation();
19364 e.preventDefault();
19367 picker : function()
19369 return this.el.select('.datepicker', true).first();
19372 fillTime: function()
19374 var time = this.pop.select('tbody', true).first();
19376 time.dom.innerHTML = '';
19391 cls: 'hours-up glyphicon glyphicon-chevron-up'
19411 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19432 cls: 'timepicker-hour',
19447 cls: 'timepicker-minute',
19462 cls: 'btn btn-primary period',
19484 cls: 'hours-down glyphicon glyphicon-chevron-down'
19504 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19522 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19529 var hours = this.time.getHours();
19530 var minutes = this.time.getMinutes();
19543 hours = hours - 12;
19547 hours = '0' + hours;
19551 minutes = '0' + minutes;
19554 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19555 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19556 this.pop.select('button', true).first().dom.innerHTML = period;
19562 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19564 var cls = ['bottom'];
19566 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19573 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19578 this.picker().addClass(cls.join('-'));
19582 Roo.each(cls, function(c){
19584 _this.picker().setTop(_this.inputEl().getHeight());
19588 _this.picker().setTop(0 - _this.picker().getHeight());
19593 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19597 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19604 onFocus : function()
19606 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19610 onBlur : function()
19612 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19618 this.picker().show();
19623 this.fireEvent('show', this, this.date);
19628 this.picker().hide();
19631 this.fireEvent('hide', this, this.date);
19634 setTime : function()
19637 this.setValue(this.time.format(this.format));
19639 this.fireEvent('select', this, this.date);
19644 onMousedown: function(e){
19645 e.stopPropagation();
19646 e.preventDefault();
19649 onIncrementHours: function()
19651 Roo.log('onIncrementHours');
19652 this.time = this.time.add(Date.HOUR, 1);
19657 onDecrementHours: function()
19659 Roo.log('onDecrementHours');
19660 this.time = this.time.add(Date.HOUR, -1);
19664 onIncrementMinutes: function()
19666 Roo.log('onIncrementMinutes');
19667 this.time = this.time.add(Date.MINUTE, 1);
19671 onDecrementMinutes: function()
19673 Roo.log('onDecrementMinutes');
19674 this.time = this.time.add(Date.MINUTE, -1);
19678 onTogglePeriod: function()
19680 Roo.log('onTogglePeriod');
19681 this.time = this.time.add(Date.HOUR, 12);
19688 Roo.apply(Roo.bootstrap.TimeField, {
19718 cls: 'btn btn-info ok',
19730 Roo.apply(Roo.bootstrap.TimeField, {
19734 cls: 'datepicker dropdown-menu',
19738 cls: 'datepicker-time',
19742 cls: 'table-condensed',
19744 Roo.bootstrap.TimeField.content,
19745 Roo.bootstrap.TimeField.footer
19764 * @class Roo.bootstrap.MonthField
19765 * @extends Roo.bootstrap.Input
19766 * Bootstrap MonthField class
19768 * @cfg {String} language default en
19771 * Create a new MonthField
19772 * @param {Object} config The config object
19775 Roo.bootstrap.MonthField = function(config){
19776 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19781 * Fires when this field show.
19782 * @param {Roo.bootstrap.MonthField} this
19783 * @param {Mixed} date The date value
19788 * Fires when this field hide.
19789 * @param {Roo.bootstrap.MonthField} this
19790 * @param {Mixed} date The date value
19795 * Fires when select a date.
19796 * @param {Roo.bootstrap.MonthField} this
19797 * @param {String} oldvalue The old value
19798 * @param {String} newvalue The new value
19804 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19806 onRender: function(ct, position)
19809 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19811 this.language = this.language || 'en';
19812 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19813 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19815 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19816 this.isInline = false;
19817 this.isInput = true;
19818 this.component = this.el.select('.add-on', true).first() || false;
19819 this.component = (this.component && this.component.length === 0) ? false : this.component;
19820 this.hasInput = this.component && this.inputEL().length;
19822 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19824 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19826 this.picker().on('mousedown', this.onMousedown, this);
19827 this.picker().on('click', this.onClick, this);
19829 this.picker().addClass('datepicker-dropdown');
19831 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19832 v.setStyle('width', '189px');
19839 if(this.isInline) {
19845 setValue: function(v, suppressEvent)
19847 var o = this.getValue();
19849 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19853 if(suppressEvent !== true){
19854 this.fireEvent('select', this, o, v);
19859 getValue: function()
19864 onClick: function(e)
19866 e.stopPropagation();
19867 e.preventDefault();
19869 var target = e.getTarget();
19871 if(target.nodeName.toLowerCase() === 'i'){
19872 target = Roo.get(target).dom.parentNode;
19875 var nodeName = target.nodeName;
19876 var className = target.className;
19877 var html = target.innerHTML;
19879 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19883 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19885 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19891 picker : function()
19893 return this.pickerEl;
19896 fillMonths: function()
19899 var months = this.picker().select('>.datepicker-months td', true).first();
19901 months.dom.innerHTML = '';
19907 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19910 months.createChild(month);
19919 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19920 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19923 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19924 e.removeClass('active');
19926 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19927 e.addClass('active');
19934 if(this.isInline) {
19938 this.picker().removeClass(['bottom', 'top']);
19940 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19942 * place to the top of element!
19946 this.picker().addClass('top');
19947 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19952 this.picker().addClass('bottom');
19954 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19957 onFocus : function()
19959 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19963 onBlur : function()
19965 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19967 var d = this.inputEl().getValue();
19976 this.picker().show();
19977 this.picker().select('>.datepicker-months', true).first().show();
19981 this.fireEvent('show', this, this.date);
19986 if(this.isInline) {
19989 this.picker().hide();
19990 this.fireEvent('hide', this, this.date);
19994 onMousedown: function(e)
19996 e.stopPropagation();
19997 e.preventDefault();
20002 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20006 fireKey: function(e)
20008 if (!this.picker().isVisible()){
20009 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20020 e.preventDefault();
20024 dir = e.keyCode == 37 ? -1 : 1;
20026 this.vIndex = this.vIndex + dir;
20028 if(this.vIndex < 0){
20032 if(this.vIndex > 11){
20036 if(isNaN(this.vIndex)){
20040 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20046 dir = e.keyCode == 38 ? -1 : 1;
20048 this.vIndex = this.vIndex + dir * 4;
20050 if(this.vIndex < 0){
20054 if(this.vIndex > 11){
20058 if(isNaN(this.vIndex)){
20062 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20067 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20068 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20072 e.preventDefault();
20075 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20076 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20092 this.picker().remove();
20097 Roo.apply(Roo.bootstrap.MonthField, {
20116 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20117 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20122 Roo.apply(Roo.bootstrap.MonthField, {
20126 cls: 'datepicker dropdown-menu roo-dynamic',
20130 cls: 'datepicker-months',
20134 cls: 'table-condensed',
20136 Roo.bootstrap.DateField.content
20156 * @class Roo.bootstrap.CheckBox
20157 * @extends Roo.bootstrap.Input
20158 * Bootstrap CheckBox class
20160 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20161 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20162 * @cfg {String} boxLabel The text that appears beside the checkbox
20163 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20164 * @cfg {Boolean} checked initnal the element
20165 * @cfg {Boolean} inline inline the element (default false)
20166 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20167 * @cfg {String} tooltip label tooltip
20170 * Create a new CheckBox
20171 * @param {Object} config The config object
20174 Roo.bootstrap.CheckBox = function(config){
20175 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20180 * Fires when the element is checked or unchecked.
20181 * @param {Roo.bootstrap.CheckBox} this This input
20182 * @param {Boolean} checked The new checked value
20187 * Fires when the element is click.
20188 * @param {Roo.bootstrap.CheckBox} this This input
20195 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20197 inputType: 'checkbox',
20206 getAutoCreate : function()
20208 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20214 cfg.cls = 'form-group ' + this.inputType; //input-group
20217 cfg.cls += ' ' + this.inputType + '-inline';
20223 type : this.inputType,
20224 value : this.inputValue,
20225 cls : 'roo-' + this.inputType, //'form-box',
20226 placeholder : this.placeholder || ''
20230 if(this.inputType != 'radio'){
20234 cls : 'roo-hidden-value',
20235 value : this.checked ? this.inputValue : this.valueOff
20240 if (this.weight) { // Validity check?
20241 cfg.cls += " " + this.inputType + "-" + this.weight;
20244 if (this.disabled) {
20245 input.disabled=true;
20249 input.checked = this.checked;
20254 input.name = this.name;
20256 if(this.inputType != 'radio'){
20257 hidden.name = this.name;
20258 input.name = '_hidden_' + this.name;
20263 input.cls += ' input-' + this.size;
20268 ['xs','sm','md','lg'].map(function(size){
20269 if (settings[size]) {
20270 cfg.cls += ' col-' + size + '-' + settings[size];
20274 var inputblock = input;
20276 if (this.before || this.after) {
20279 cls : 'input-group',
20284 inputblock.cn.push({
20286 cls : 'input-group-addon',
20291 inputblock.cn.push(input);
20293 if(this.inputType != 'radio'){
20294 inputblock.cn.push(hidden);
20298 inputblock.cn.push({
20300 cls : 'input-group-addon',
20307 if (align ==='left' && this.fieldLabel.length) {
20308 // Roo.log("left and has label");
20313 cls : 'control-label',
20314 html : this.fieldLabel
20324 if(this.labelWidth > 12){
20325 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20328 if(this.labelWidth < 13 && this.labelmd == 0){
20329 this.labelmd = this.labelWidth;
20332 if(this.labellg > 0){
20333 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20334 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20337 if(this.labelmd > 0){
20338 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20339 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20342 if(this.labelsm > 0){
20343 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20344 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20347 if(this.labelxs > 0){
20348 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20349 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20352 } else if ( this.fieldLabel.length) {
20353 // Roo.log(" label");
20357 tag: this.boxLabel ? 'span' : 'label',
20359 cls: 'control-label box-input-label',
20360 //cls : 'input-group-addon',
20361 html : this.fieldLabel
20370 // Roo.log(" no label && no align");
20371 cfg.cn = [ inputblock ] ;
20377 var boxLabelCfg = {
20379 //'for': id, // box label is handled by onclick - so no for...
20381 html: this.boxLabel
20385 boxLabelCfg.tooltip = this.tooltip;
20388 cfg.cn.push(boxLabelCfg);
20391 if(this.inputType != 'radio'){
20392 cfg.cn.push(hidden);
20400 * return the real input element.
20402 inputEl: function ()
20404 return this.el.select('input.roo-' + this.inputType,true).first();
20406 hiddenEl: function ()
20408 return this.el.select('input.roo-hidden-value',true).first();
20411 labelEl: function()
20413 return this.el.select('label.control-label',true).first();
20415 /* depricated... */
20419 return this.labelEl();
20422 boxLabelEl: function()
20424 return this.el.select('label.box-label',true).first();
20427 initEvents : function()
20429 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20431 this.inputEl().on('click', this.onClick, this);
20433 if (this.boxLabel) {
20434 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20437 this.startValue = this.getValue();
20440 Roo.bootstrap.CheckBox.register(this);
20444 onClick : function(e)
20446 if(this.fireEvent('click', this, e) !== false){
20447 this.setChecked(!this.checked);
20452 setChecked : function(state,suppressEvent)
20454 this.startValue = this.getValue();
20456 if(this.inputType == 'radio'){
20458 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20459 e.dom.checked = false;
20462 this.inputEl().dom.checked = true;
20464 this.inputEl().dom.value = this.inputValue;
20466 if(suppressEvent !== true){
20467 this.fireEvent('check', this, true);
20475 this.checked = state;
20477 this.inputEl().dom.checked = state;
20480 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20482 if(suppressEvent !== true){
20483 this.fireEvent('check', this, state);
20489 getValue : function()
20491 if(this.inputType == 'radio'){
20492 return this.getGroupValue();
20495 return this.hiddenEl().dom.value;
20499 getGroupValue : function()
20501 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20505 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20508 setValue : function(v,suppressEvent)
20510 if(this.inputType == 'radio'){
20511 this.setGroupValue(v, suppressEvent);
20515 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20520 setGroupValue : function(v, suppressEvent)
20522 this.startValue = this.getValue();
20524 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20525 e.dom.checked = false;
20527 if(e.dom.value == v){
20528 e.dom.checked = true;
20532 if(suppressEvent !== true){
20533 this.fireEvent('check', this, true);
20541 validate : function()
20545 (this.inputType == 'radio' && this.validateRadio()) ||
20546 (this.inputType == 'checkbox' && this.validateCheckbox())
20552 this.markInvalid();
20556 validateRadio : function()
20558 if(this.allowBlank){
20564 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20565 if(!e.dom.checked){
20577 validateCheckbox : function()
20580 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20581 //return (this.getValue() == this.inputValue) ? true : false;
20584 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20592 for(var i in group){
20593 if(group[i].el.isVisible(true)){
20601 for(var i in group){
20606 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20613 * Mark this field as valid
20615 markValid : function()
20619 this.fireEvent('valid', this);
20621 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20624 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20631 if(this.inputType == 'radio'){
20632 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20633 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20634 e.findParent('.form-group', false, true).addClass(_this.validClass);
20641 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20642 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20646 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20652 for(var i in group){
20653 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20654 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20659 * Mark this field as invalid
20660 * @param {String} msg The validation message
20662 markInvalid : function(msg)
20664 if(this.allowBlank){
20670 this.fireEvent('invalid', this, msg);
20672 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20675 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20679 label.markInvalid();
20682 if(this.inputType == 'radio'){
20683 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20684 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20685 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20692 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20693 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20697 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20703 for(var i in group){
20704 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20705 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20710 clearInvalid : function()
20712 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20714 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20716 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20718 if (label && label.iconEl) {
20719 label.iconEl.removeClass(label.validClass);
20720 label.iconEl.removeClass(label.invalidClass);
20724 disable : function()
20726 if(this.inputType != 'radio'){
20727 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20734 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20735 _this.getActionEl().addClass(this.disabledClass);
20736 e.dom.disabled = true;
20740 this.disabled = true;
20741 this.fireEvent("disable", this);
20745 enable : function()
20747 if(this.inputType != 'radio'){
20748 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20755 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20756 _this.getActionEl().removeClass(this.disabledClass);
20757 e.dom.disabled = false;
20761 this.disabled = false;
20762 this.fireEvent("enable", this);
20766 setBoxLabel : function(v)
20771 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20777 Roo.apply(Roo.bootstrap.CheckBox, {
20782 * register a CheckBox Group
20783 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20785 register : function(checkbox)
20787 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20788 this.groups[checkbox.groupId] = {};
20791 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20795 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20799 * fetch a CheckBox Group based on the group ID
20800 * @param {string} the group ID
20801 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20803 get: function(groupId) {
20804 if (typeof(this.groups[groupId]) == 'undefined') {
20808 return this.groups[groupId] ;
20821 * @class Roo.bootstrap.Radio
20822 * @extends Roo.bootstrap.Component
20823 * Bootstrap Radio class
20824 * @cfg {String} boxLabel - the label associated
20825 * @cfg {String} value - the value of radio
20828 * Create a new Radio
20829 * @param {Object} config The config object
20831 Roo.bootstrap.Radio = function(config){
20832 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20836 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20842 getAutoCreate : function()
20846 cls : 'form-group radio',
20851 html : this.boxLabel
20859 initEvents : function()
20861 this.parent().register(this);
20863 this.el.on('click', this.onClick, this);
20867 onClick : function()
20869 this.setChecked(true);
20872 setChecked : function(state, suppressEvent)
20874 this.parent().setValue(this.value, suppressEvent);
20878 setBoxLabel : function(v)
20883 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20898 * @class Roo.bootstrap.SecurePass
20899 * @extends Roo.bootstrap.Input
20900 * Bootstrap SecurePass class
20904 * Create a new SecurePass
20905 * @param {Object} config The config object
20908 Roo.bootstrap.SecurePass = function (config) {
20909 // these go here, so the translation tool can replace them..
20911 PwdEmpty: "Please type a password, and then retype it to confirm.",
20912 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20913 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20914 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20915 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20916 FNInPwd: "Your password can't contain your first name. Please type a different password.",
20917 LNInPwd: "Your password can't contain your last name. Please type a different password.",
20918 TooWeak: "Your password is Too Weak."
20920 this.meterLabel = "Password strength:";
20921 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
20922 this.meterClass = [
20923 "roo-password-meter-tooweak",
20924 "roo-password-meter-weak",
20925 "roo-password-meter-medium",
20926 "roo-password-meter-strong",
20927 "roo-password-meter-grey"
20932 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
20935 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
20937 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
20939 * PwdEmpty: "Please type a password, and then retype it to confirm.",
20940 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
20941 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
20942 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
20943 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
20944 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
20945 * LNInPwd: "Your password can't contain your last name. Please type a different password."
20955 * @cfg {String/Object} Label for the strength meter (defaults to
20956 * 'Password strength:')
20961 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
20962 * ['Weak', 'Medium', 'Strong'])
20965 pwdStrengths: false,
20978 initEvents: function ()
20980 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
20982 if (this.el.is('input[type=password]') && Roo.isSafari) {
20983 this.el.on('keydown', this.SafariOnKeyDown, this);
20986 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
20989 onRender: function (ct, position)
20991 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
20992 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
20993 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
20995 this.trigger.createChild({
21000 cls: 'roo-password-meter-grey col-xs-12',
21003 //width: this.meterWidth + 'px'
21007 cls: 'roo-password-meter-text'
21013 if (this.hideTrigger) {
21014 this.trigger.setDisplayed(false);
21016 this.setSize(this.width || '', this.height || '');
21019 onDestroy: function ()
21021 if (this.trigger) {
21022 this.trigger.removeAllListeners();
21023 this.trigger.remove();
21026 this.wrap.remove();
21028 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21031 checkStrength: function ()
21033 var pwd = this.inputEl().getValue();
21034 if (pwd == this._lastPwd) {
21039 if (this.ClientSideStrongPassword(pwd)) {
21041 } else if (this.ClientSideMediumPassword(pwd)) {
21043 } else if (this.ClientSideWeakPassword(pwd)) {
21049 Roo.log('strength1: ' + strength);
21051 //var pm = this.trigger.child('div/div/div').dom;
21052 var pm = this.trigger.child('div/div');
21053 pm.removeClass(this.meterClass);
21054 pm.addClass(this.meterClass[strength]);
21057 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21059 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21061 this._lastPwd = pwd;
21065 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21067 this._lastPwd = '';
21069 var pm = this.trigger.child('div/div');
21070 pm.removeClass(this.meterClass);
21071 pm.addClass('roo-password-meter-grey');
21074 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21077 this.inputEl().dom.type='password';
21080 validateValue: function (value)
21083 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21086 if (value.length == 0) {
21087 if (this.allowBlank) {
21088 this.clearInvalid();
21092 this.markInvalid(this.errors.PwdEmpty);
21093 this.errorMsg = this.errors.PwdEmpty;
21101 if ('[\x21-\x7e]*'.match(value)) {
21102 this.markInvalid(this.errors.PwdBadChar);
21103 this.errorMsg = this.errors.PwdBadChar;
21106 if (value.length < 6) {
21107 this.markInvalid(this.errors.PwdShort);
21108 this.errorMsg = this.errors.PwdShort;
21111 if (value.length > 16) {
21112 this.markInvalid(this.errors.PwdLong);
21113 this.errorMsg = this.errors.PwdLong;
21117 if (this.ClientSideStrongPassword(value)) {
21119 } else if (this.ClientSideMediumPassword(value)) {
21121 } else if (this.ClientSideWeakPassword(value)) {
21128 if (strength < 2) {
21129 //this.markInvalid(this.errors.TooWeak);
21130 this.errorMsg = this.errors.TooWeak;
21135 console.log('strength2: ' + strength);
21137 //var pm = this.trigger.child('div/div/div').dom;
21139 var pm = this.trigger.child('div/div');
21140 pm.removeClass(this.meterClass);
21141 pm.addClass(this.meterClass[strength]);
21143 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21145 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21147 this.errorMsg = '';
21151 CharacterSetChecks: function (type)
21154 this.fResult = false;
21157 isctype: function (character, type)
21160 case this.kCapitalLetter:
21161 if (character >= 'A' && character <= 'Z') {
21166 case this.kSmallLetter:
21167 if (character >= 'a' && character <= 'z') {
21173 if (character >= '0' && character <= '9') {
21178 case this.kPunctuation:
21179 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21190 IsLongEnough: function (pwd, size)
21192 return !(pwd == null || isNaN(size) || pwd.length < size);
21195 SpansEnoughCharacterSets: function (word, nb)
21197 if (!this.IsLongEnough(word, nb))
21202 var characterSetChecks = new Array(
21203 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21204 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21207 for (var index = 0; index < word.length; ++index) {
21208 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21209 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21210 characterSetChecks[nCharSet].fResult = true;
21217 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21218 if (characterSetChecks[nCharSet].fResult) {
21223 if (nCharSets < nb) {
21229 ClientSideStrongPassword: function (pwd)
21231 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21234 ClientSideMediumPassword: function (pwd)
21236 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21239 ClientSideWeakPassword: function (pwd)
21241 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21244 })//<script type="text/javascript">
21247 * Based Ext JS Library 1.1.1
21248 * Copyright(c) 2006-2007, Ext JS, LLC.
21254 * @class Roo.HtmlEditorCore
21255 * @extends Roo.Component
21256 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21258 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21261 Roo.HtmlEditorCore = function(config){
21264 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21269 * @event initialize
21270 * Fires when the editor is fully initialized (including the iframe)
21271 * @param {Roo.HtmlEditorCore} this
21276 * Fires when the editor is first receives the focus. Any insertion must wait
21277 * until after this event.
21278 * @param {Roo.HtmlEditorCore} this
21282 * @event beforesync
21283 * Fires before the textarea is updated with content from the editor iframe. Return false
21284 * to cancel the sync.
21285 * @param {Roo.HtmlEditorCore} this
21286 * @param {String} html
21290 * @event beforepush
21291 * Fires before the iframe editor is updated with content from the textarea. Return false
21292 * to cancel the push.
21293 * @param {Roo.HtmlEditorCore} this
21294 * @param {String} html
21299 * Fires when the textarea is updated with content from the editor iframe.
21300 * @param {Roo.HtmlEditorCore} this
21301 * @param {String} html
21306 * Fires when the iframe editor is updated with content from the textarea.
21307 * @param {Roo.HtmlEditorCore} this
21308 * @param {String} html
21313 * @event editorevent
21314 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21315 * @param {Roo.HtmlEditorCore} this
21321 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21323 // defaults : white / black...
21324 this.applyBlacklists();
21331 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21335 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21341 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21346 * @cfg {Number} height (in pixels)
21350 * @cfg {Number} width (in pixels)
21355 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21358 stylesheets: false,
21363 // private properties
21364 validationEvent : false,
21366 initialized : false,
21368 sourceEditMode : false,
21369 onFocus : Roo.emptyFn,
21371 hideMode:'offsets',
21375 // blacklist + whitelisted elements..
21382 * Protected method that will not generally be called directly. It
21383 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21384 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21386 getDocMarkup : function(){
21390 // inherit styels from page...??
21391 if (this.stylesheets === false) {
21393 Roo.get(document.head).select('style').each(function(node) {
21394 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21397 Roo.get(document.head).select('link').each(function(node) {
21398 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21401 } else if (!this.stylesheets.length) {
21403 st = '<style type="text/css">' +
21404 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21407 st = '<style type="text/css">' +
21412 st += '<style type="text/css">' +
21413 'IMG { cursor: pointer } ' +
21416 var cls = 'roo-htmleditor-body';
21418 if(this.bodyCls.length){
21419 cls += ' ' + this.bodyCls;
21422 return '<html><head>' + st +
21423 //<style type="text/css">' +
21424 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21426 ' </head><body class="' + cls + '"></body></html>';
21430 onRender : function(ct, position)
21433 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21434 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21437 this.el.dom.style.border = '0 none';
21438 this.el.dom.setAttribute('tabIndex', -1);
21439 this.el.addClass('x-hidden hide');
21443 if(Roo.isIE){ // fix IE 1px bogus margin
21444 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21448 this.frameId = Roo.id();
21452 var iframe = this.owner.wrap.createChild({
21454 cls: 'form-control', // bootstrap..
21456 name: this.frameId,
21457 frameBorder : 'no',
21458 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21463 this.iframe = iframe.dom;
21465 this.assignDocWin();
21467 this.doc.designMode = 'on';
21470 this.doc.write(this.getDocMarkup());
21474 var task = { // must defer to wait for browser to be ready
21476 //console.log("run task?" + this.doc.readyState);
21477 this.assignDocWin();
21478 if(this.doc.body || this.doc.readyState == 'complete'){
21480 this.doc.designMode="on";
21484 Roo.TaskMgr.stop(task);
21485 this.initEditor.defer(10, this);
21492 Roo.TaskMgr.start(task);
21497 onResize : function(w, h)
21499 Roo.log('resize: ' +w + ',' + h );
21500 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21504 if(typeof w == 'number'){
21506 this.iframe.style.width = w + 'px';
21508 if(typeof h == 'number'){
21510 this.iframe.style.height = h + 'px';
21512 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21519 * Toggles the editor between standard and source edit mode.
21520 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21522 toggleSourceEdit : function(sourceEditMode){
21524 this.sourceEditMode = sourceEditMode === true;
21526 if(this.sourceEditMode){
21528 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21531 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21532 //this.iframe.className = '';
21535 //this.setSize(this.owner.wrap.getSize());
21536 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21543 * Protected method that will not generally be called directly. If you need/want
21544 * custom HTML cleanup, this is the method you should override.
21545 * @param {String} html The HTML to be cleaned
21546 * return {String} The cleaned HTML
21548 cleanHtml : function(html){
21549 html = String(html);
21550 if(html.length > 5){
21551 if(Roo.isSafari){ // strip safari nonsense
21552 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21555 if(html == ' '){
21562 * HTML Editor -> Textarea
21563 * Protected method that will not generally be called directly. Syncs the contents
21564 * of the editor iframe with the textarea.
21566 syncValue : function(){
21567 if(this.initialized){
21568 var bd = (this.doc.body || this.doc.documentElement);
21569 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21570 var html = bd.innerHTML;
21572 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21573 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21575 html = '<div style="'+m[0]+'">' + html + '</div>';
21578 html = this.cleanHtml(html);
21579 // fix up the special chars.. normaly like back quotes in word...
21580 // however we do not want to do this with chinese..
21581 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21582 var cc = b.charCodeAt();
21584 (cc >= 0x4E00 && cc < 0xA000 ) ||
21585 (cc >= 0x3400 && cc < 0x4E00 ) ||
21586 (cc >= 0xf900 && cc < 0xfb00 )
21592 if(this.owner.fireEvent('beforesync', this, html) !== false){
21593 this.el.dom.value = html;
21594 this.owner.fireEvent('sync', this, html);
21600 * Protected method that will not generally be called directly. Pushes the value of the textarea
21601 * into the iframe editor.
21603 pushValue : function(){
21604 if(this.initialized){
21605 var v = this.el.dom.value.trim();
21607 // if(v.length < 1){
21611 if(this.owner.fireEvent('beforepush', this, v) !== false){
21612 var d = (this.doc.body || this.doc.documentElement);
21614 this.cleanUpPaste();
21615 this.el.dom.value = d.innerHTML;
21616 this.owner.fireEvent('push', this, v);
21622 deferFocus : function(){
21623 this.focus.defer(10, this);
21627 focus : function(){
21628 if(this.win && !this.sourceEditMode){
21635 assignDocWin: function()
21637 var iframe = this.iframe;
21640 this.doc = iframe.contentWindow.document;
21641 this.win = iframe.contentWindow;
21643 // if (!Roo.get(this.frameId)) {
21646 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21647 // this.win = Roo.get(this.frameId).dom.contentWindow;
21649 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21653 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21654 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21659 initEditor : function(){
21660 //console.log("INIT EDITOR");
21661 this.assignDocWin();
21665 this.doc.designMode="on";
21667 this.doc.write(this.getDocMarkup());
21670 var dbody = (this.doc.body || this.doc.documentElement);
21671 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21672 // this copies styles from the containing element into thsi one..
21673 // not sure why we need all of this..
21674 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21676 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21677 //ss['background-attachment'] = 'fixed'; // w3c
21678 dbody.bgProperties = 'fixed'; // ie
21679 //Roo.DomHelper.applyStyles(dbody, ss);
21680 Roo.EventManager.on(this.doc, {
21681 //'mousedown': this.onEditorEvent,
21682 'mouseup': this.onEditorEvent,
21683 'dblclick': this.onEditorEvent,
21684 'click': this.onEditorEvent,
21685 'keyup': this.onEditorEvent,
21690 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21692 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21693 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21695 this.initialized = true;
21697 this.owner.fireEvent('initialize', this);
21702 onDestroy : function(){
21708 //for (var i =0; i < this.toolbars.length;i++) {
21709 // // fixme - ask toolbars for heights?
21710 // this.toolbars[i].onDestroy();
21713 //this.wrap.dom.innerHTML = '';
21714 //this.wrap.remove();
21719 onFirstFocus : function(){
21721 this.assignDocWin();
21724 this.activated = true;
21727 if(Roo.isGecko){ // prevent silly gecko errors
21729 var s = this.win.getSelection();
21730 if(!s.focusNode || s.focusNode.nodeType != 3){
21731 var r = s.getRangeAt(0);
21732 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21737 this.execCmd('useCSS', true);
21738 this.execCmd('styleWithCSS', false);
21741 this.owner.fireEvent('activate', this);
21745 adjustFont: function(btn){
21746 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21747 //if(Roo.isSafari){ // safari
21750 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21751 if(Roo.isSafari){ // safari
21752 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21753 v = (v < 10) ? 10 : v;
21754 v = (v > 48) ? 48 : v;
21755 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21760 v = Math.max(1, v+adjust);
21762 this.execCmd('FontSize', v );
21765 onEditorEvent : function(e)
21767 this.owner.fireEvent('editorevent', this, e);
21768 // this.updateToolbar();
21769 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21772 insertTag : function(tg)
21774 // could be a bit smarter... -> wrap the current selected tRoo..
21775 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21777 range = this.createRange(this.getSelection());
21778 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21779 wrappingNode.appendChild(range.extractContents());
21780 range.insertNode(wrappingNode);
21787 this.execCmd("formatblock", tg);
21791 insertText : function(txt)
21795 var range = this.createRange();
21796 range.deleteContents();
21797 //alert(Sender.getAttribute('label'));
21799 range.insertNode(this.doc.createTextNode(txt));
21805 * Executes a Midas editor command on the editor document and performs necessary focus and
21806 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21807 * @param {String} cmd The Midas command
21808 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21810 relayCmd : function(cmd, value){
21812 this.execCmd(cmd, value);
21813 this.owner.fireEvent('editorevent', this);
21814 //this.updateToolbar();
21815 this.owner.deferFocus();
21819 * Executes a Midas editor command directly on the editor document.
21820 * For visual commands, you should use {@link #relayCmd} instead.
21821 * <b>This should only be called after the editor is initialized.</b>
21822 * @param {String} cmd The Midas command
21823 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21825 execCmd : function(cmd, value){
21826 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21833 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21835 * @param {String} text | dom node..
21837 insertAtCursor : function(text)
21840 if(!this.activated){
21846 var r = this.doc.selection.createRange();
21857 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21861 // from jquery ui (MIT licenced)
21863 var win = this.win;
21865 if (win.getSelection && win.getSelection().getRangeAt) {
21866 range = win.getSelection().getRangeAt(0);
21867 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21868 range.insertNode(node);
21869 } else if (win.document.selection && win.document.selection.createRange) {
21870 // no firefox support
21871 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21872 win.document.selection.createRange().pasteHTML(txt);
21874 // no firefox support
21875 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21876 this.execCmd('InsertHTML', txt);
21885 mozKeyPress : function(e){
21887 var c = e.getCharCode(), cmd;
21890 c = String.fromCharCode(c).toLowerCase();
21904 this.cleanUpPaste.defer(100, this);
21912 e.preventDefault();
21920 fixKeys : function(){ // load time branching for fastest keydown performance
21922 return function(e){
21923 var k = e.getKey(), r;
21926 r = this.doc.selection.createRange();
21929 r.pasteHTML('    ');
21936 r = this.doc.selection.createRange();
21938 var target = r.parentElement();
21939 if(!target || target.tagName.toLowerCase() != 'li'){
21941 r.pasteHTML('<br />');
21947 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21948 this.cleanUpPaste.defer(100, this);
21954 }else if(Roo.isOpera){
21955 return function(e){
21956 var k = e.getKey();
21960 this.execCmd('InsertHTML','    ');
21963 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21964 this.cleanUpPaste.defer(100, this);
21969 }else if(Roo.isSafari){
21970 return function(e){
21971 var k = e.getKey();
21975 this.execCmd('InsertText','\t');
21979 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21980 this.cleanUpPaste.defer(100, this);
21988 getAllAncestors: function()
21990 var p = this.getSelectedNode();
21993 a.push(p); // push blank onto stack..
21994 p = this.getParentElement();
21998 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22002 a.push(this.doc.body);
22006 lastSelNode : false,
22009 getSelection : function()
22011 this.assignDocWin();
22012 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22015 getSelectedNode: function()
22017 // this may only work on Gecko!!!
22019 // should we cache this!!!!
22024 var range = this.createRange(this.getSelection()).cloneRange();
22027 var parent = range.parentElement();
22029 var testRange = range.duplicate();
22030 testRange.moveToElementText(parent);
22031 if (testRange.inRange(range)) {
22034 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22037 parent = parent.parentElement;
22042 // is ancestor a text element.
22043 var ac = range.commonAncestorContainer;
22044 if (ac.nodeType == 3) {
22045 ac = ac.parentNode;
22048 var ar = ac.childNodes;
22051 var other_nodes = [];
22052 var has_other_nodes = false;
22053 for (var i=0;i<ar.length;i++) {
22054 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22057 // fullly contained node.
22059 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22064 // probably selected..
22065 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22066 other_nodes.push(ar[i]);
22070 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22075 has_other_nodes = true;
22077 if (!nodes.length && other_nodes.length) {
22078 nodes= other_nodes;
22080 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22086 createRange: function(sel)
22088 // this has strange effects when using with
22089 // top toolbar - not sure if it's a great idea.
22090 //this.editor.contentWindow.focus();
22091 if (typeof sel != "undefined") {
22093 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22095 return this.doc.createRange();
22098 return this.doc.createRange();
22101 getParentElement: function()
22104 this.assignDocWin();
22105 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22107 var range = this.createRange(sel);
22110 var p = range.commonAncestorContainer;
22111 while (p.nodeType == 3) { // text node
22122 * Range intersection.. the hard stuff...
22126 * [ -- selected range --- ]
22130 * if end is before start or hits it. fail.
22131 * if start is after end or hits it fail.
22133 * if either hits (but other is outside. - then it's not
22139 // @see http://www.thismuchiknow.co.uk/?p=64.
22140 rangeIntersectsNode : function(range, node)
22142 var nodeRange = node.ownerDocument.createRange();
22144 nodeRange.selectNode(node);
22146 nodeRange.selectNodeContents(node);
22149 var rangeStartRange = range.cloneRange();
22150 rangeStartRange.collapse(true);
22152 var rangeEndRange = range.cloneRange();
22153 rangeEndRange.collapse(false);
22155 var nodeStartRange = nodeRange.cloneRange();
22156 nodeStartRange.collapse(true);
22158 var nodeEndRange = nodeRange.cloneRange();
22159 nodeEndRange.collapse(false);
22161 return rangeStartRange.compareBoundaryPoints(
22162 Range.START_TO_START, nodeEndRange) == -1 &&
22163 rangeEndRange.compareBoundaryPoints(
22164 Range.START_TO_START, nodeStartRange) == 1;
22168 rangeCompareNode : function(range, node)
22170 var nodeRange = node.ownerDocument.createRange();
22172 nodeRange.selectNode(node);
22174 nodeRange.selectNodeContents(node);
22178 range.collapse(true);
22180 nodeRange.collapse(true);
22182 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22183 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22185 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22187 var nodeIsBefore = ss == 1;
22188 var nodeIsAfter = ee == -1;
22190 if (nodeIsBefore && nodeIsAfter) {
22193 if (!nodeIsBefore && nodeIsAfter) {
22194 return 1; //right trailed.
22197 if (nodeIsBefore && !nodeIsAfter) {
22198 return 2; // left trailed.
22204 // private? - in a new class?
22205 cleanUpPaste : function()
22207 // cleans up the whole document..
22208 Roo.log('cleanuppaste');
22210 this.cleanUpChildren(this.doc.body);
22211 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22212 if (clean != this.doc.body.innerHTML) {
22213 this.doc.body.innerHTML = clean;
22218 cleanWordChars : function(input) {// change the chars to hex code
22219 var he = Roo.HtmlEditorCore;
22221 var output = input;
22222 Roo.each(he.swapCodes, function(sw) {
22223 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22225 output = output.replace(swapper, sw[1]);
22232 cleanUpChildren : function (n)
22234 if (!n.childNodes.length) {
22237 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22238 this.cleanUpChild(n.childNodes[i]);
22245 cleanUpChild : function (node)
22248 //console.log(node);
22249 if (node.nodeName == "#text") {
22250 // clean up silly Windows -- stuff?
22253 if (node.nodeName == "#comment") {
22254 node.parentNode.removeChild(node);
22255 // clean up silly Windows -- stuff?
22258 var lcname = node.tagName.toLowerCase();
22259 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22260 // whitelist of tags..
22262 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22264 node.parentNode.removeChild(node);
22269 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22271 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22272 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22274 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22275 // remove_keep_children = true;
22278 if (remove_keep_children) {
22279 this.cleanUpChildren(node);
22280 // inserts everything just before this node...
22281 while (node.childNodes.length) {
22282 var cn = node.childNodes[0];
22283 node.removeChild(cn);
22284 node.parentNode.insertBefore(cn, node);
22286 node.parentNode.removeChild(node);
22290 if (!node.attributes || !node.attributes.length) {
22291 this.cleanUpChildren(node);
22295 function cleanAttr(n,v)
22298 if (v.match(/^\./) || v.match(/^\//)) {
22301 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22304 if (v.match(/^#/)) {
22307 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22308 node.removeAttribute(n);
22312 var cwhite = this.cwhite;
22313 var cblack = this.cblack;
22315 function cleanStyle(n,v)
22317 if (v.match(/expression/)) { //XSS?? should we even bother..
22318 node.removeAttribute(n);
22322 var parts = v.split(/;/);
22325 Roo.each(parts, function(p) {
22326 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22330 var l = p.split(':').shift().replace(/\s+/g,'');
22331 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22333 if ( cwhite.length && cblack.indexOf(l) > -1) {
22334 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22335 //node.removeAttribute(n);
22339 // only allow 'c whitelisted system attributes'
22340 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22341 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22342 //node.removeAttribute(n);
22352 if (clean.length) {
22353 node.setAttribute(n, clean.join(';'));
22355 node.removeAttribute(n);
22361 for (var i = node.attributes.length-1; i > -1 ; i--) {
22362 var a = node.attributes[i];
22365 if (a.name.toLowerCase().substr(0,2)=='on') {
22366 node.removeAttribute(a.name);
22369 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22370 node.removeAttribute(a.name);
22373 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22374 cleanAttr(a.name,a.value); // fixme..
22377 if (a.name == 'style') {
22378 cleanStyle(a.name,a.value);
22381 /// clean up MS crap..
22382 // tecnically this should be a list of valid class'es..
22385 if (a.name == 'class') {
22386 if (a.value.match(/^Mso/)) {
22387 node.className = '';
22390 if (a.value.match(/^body$/)) {
22391 node.className = '';
22402 this.cleanUpChildren(node);
22408 * Clean up MS wordisms...
22410 cleanWord : function(node)
22415 this.cleanWord(this.doc.body);
22418 if (node.nodeName == "#text") {
22419 // clean up silly Windows -- stuff?
22422 if (node.nodeName == "#comment") {
22423 node.parentNode.removeChild(node);
22424 // clean up silly Windows -- stuff?
22428 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22429 node.parentNode.removeChild(node);
22433 // remove - but keep children..
22434 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22435 while (node.childNodes.length) {
22436 var cn = node.childNodes[0];
22437 node.removeChild(cn);
22438 node.parentNode.insertBefore(cn, node);
22440 node.parentNode.removeChild(node);
22441 this.iterateChildren(node, this.cleanWord);
22445 if (node.className.length) {
22447 var cn = node.className.split(/\W+/);
22449 Roo.each(cn, function(cls) {
22450 if (cls.match(/Mso[a-zA-Z]+/)) {
22455 node.className = cna.length ? cna.join(' ') : '';
22457 node.removeAttribute("class");
22461 if (node.hasAttribute("lang")) {
22462 node.removeAttribute("lang");
22465 if (node.hasAttribute("style")) {
22467 var styles = node.getAttribute("style").split(";");
22469 Roo.each(styles, function(s) {
22470 if (!s.match(/:/)) {
22473 var kv = s.split(":");
22474 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22477 // what ever is left... we allow.
22480 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22481 if (!nstyle.length) {
22482 node.removeAttribute('style');
22485 this.iterateChildren(node, this.cleanWord);
22491 * iterateChildren of a Node, calling fn each time, using this as the scole..
22492 * @param {DomNode} node node to iterate children of.
22493 * @param {Function} fn method of this class to call on each item.
22495 iterateChildren : function(node, fn)
22497 if (!node.childNodes.length) {
22500 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22501 fn.call(this, node.childNodes[i])
22507 * cleanTableWidths.
22509 * Quite often pasting from word etc.. results in tables with column and widths.
22510 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22513 cleanTableWidths : function(node)
22518 this.cleanTableWidths(this.doc.body);
22523 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22526 Roo.log(node.tagName);
22527 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22528 this.iterateChildren(node, this.cleanTableWidths);
22531 if (node.hasAttribute('width')) {
22532 node.removeAttribute('width');
22536 if (node.hasAttribute("style")) {
22539 var styles = node.getAttribute("style").split(";");
22541 Roo.each(styles, function(s) {
22542 if (!s.match(/:/)) {
22545 var kv = s.split(":");
22546 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22549 // what ever is left... we allow.
22552 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22553 if (!nstyle.length) {
22554 node.removeAttribute('style');
22558 this.iterateChildren(node, this.cleanTableWidths);
22566 domToHTML : function(currentElement, depth, nopadtext) {
22568 depth = depth || 0;
22569 nopadtext = nopadtext || false;
22571 if (!currentElement) {
22572 return this.domToHTML(this.doc.body);
22575 //Roo.log(currentElement);
22577 var allText = false;
22578 var nodeName = currentElement.nodeName;
22579 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22581 if (nodeName == '#text') {
22583 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22588 if (nodeName != 'BODY') {
22591 // Prints the node tagName, such as <A>, <IMG>, etc
22594 for(i = 0; i < currentElement.attributes.length;i++) {
22596 var aname = currentElement.attributes.item(i).name;
22597 if (!currentElement.attributes.item(i).value.length) {
22600 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22603 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22612 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22615 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22620 // Traverse the tree
22622 var currentElementChild = currentElement.childNodes.item(i);
22623 var allText = true;
22624 var innerHTML = '';
22626 while (currentElementChild) {
22627 // Formatting code (indent the tree so it looks nice on the screen)
22628 var nopad = nopadtext;
22629 if (lastnode == 'SPAN') {
22633 if (currentElementChild.nodeName == '#text') {
22634 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22635 toadd = nopadtext ? toadd : toadd.trim();
22636 if (!nopad && toadd.length > 80) {
22637 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22639 innerHTML += toadd;
22642 currentElementChild = currentElement.childNodes.item(i);
22648 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22650 // Recursively traverse the tree structure of the child node
22651 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22652 lastnode = currentElementChild.nodeName;
22654 currentElementChild=currentElement.childNodes.item(i);
22660 // The remaining code is mostly for formatting the tree
22661 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22666 ret+= "</"+tagName+">";
22672 applyBlacklists : function()
22674 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22675 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22679 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22680 if (b.indexOf(tag) > -1) {
22683 this.white.push(tag);
22687 Roo.each(w, function(tag) {
22688 if (b.indexOf(tag) > -1) {
22691 if (this.white.indexOf(tag) > -1) {
22694 this.white.push(tag);
22699 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22700 if (w.indexOf(tag) > -1) {
22703 this.black.push(tag);
22707 Roo.each(b, function(tag) {
22708 if (w.indexOf(tag) > -1) {
22711 if (this.black.indexOf(tag) > -1) {
22714 this.black.push(tag);
22719 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22720 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22724 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22725 if (b.indexOf(tag) > -1) {
22728 this.cwhite.push(tag);
22732 Roo.each(w, function(tag) {
22733 if (b.indexOf(tag) > -1) {
22736 if (this.cwhite.indexOf(tag) > -1) {
22739 this.cwhite.push(tag);
22744 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22745 if (w.indexOf(tag) > -1) {
22748 this.cblack.push(tag);
22752 Roo.each(b, function(tag) {
22753 if (w.indexOf(tag) > -1) {
22756 if (this.cblack.indexOf(tag) > -1) {
22759 this.cblack.push(tag);
22764 setStylesheets : function(stylesheets)
22766 if(typeof(stylesheets) == 'string'){
22767 Roo.get(this.iframe.contentDocument.head).createChild({
22769 rel : 'stylesheet',
22778 Roo.each(stylesheets, function(s) {
22783 Roo.get(_this.iframe.contentDocument.head).createChild({
22785 rel : 'stylesheet',
22794 removeStylesheets : function()
22798 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22803 setStyle : function(style)
22805 Roo.get(this.iframe.contentDocument.head).createChild({
22814 // hide stuff that is not compatible
22828 * @event specialkey
22832 * @cfg {String} fieldClass @hide
22835 * @cfg {String} focusClass @hide
22838 * @cfg {String} autoCreate @hide
22841 * @cfg {String} inputType @hide
22844 * @cfg {String} invalidClass @hide
22847 * @cfg {String} invalidText @hide
22850 * @cfg {String} msgFx @hide
22853 * @cfg {String} validateOnBlur @hide
22857 Roo.HtmlEditorCore.white = [
22858 'area', 'br', 'img', 'input', 'hr', 'wbr',
22860 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22861 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22862 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22863 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22864 'table', 'ul', 'xmp',
22866 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22869 'dir', 'menu', 'ol', 'ul', 'dl',
22875 Roo.HtmlEditorCore.black = [
22876 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22878 'base', 'basefont', 'bgsound', 'blink', 'body',
22879 'frame', 'frameset', 'head', 'html', 'ilayer',
22880 'iframe', 'layer', 'link', 'meta', 'object',
22881 'script', 'style' ,'title', 'xml' // clean later..
22883 Roo.HtmlEditorCore.clean = [
22884 'script', 'style', 'title', 'xml'
22886 Roo.HtmlEditorCore.remove = [
22891 Roo.HtmlEditorCore.ablack = [
22895 Roo.HtmlEditorCore.aclean = [
22896 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22900 Roo.HtmlEditorCore.pwhite= [
22901 'http', 'https', 'mailto'
22904 // white listed style attributes.
22905 Roo.HtmlEditorCore.cwhite= [
22906 // 'text-align', /// default is to allow most things..
22912 // black listed style attributes.
22913 Roo.HtmlEditorCore.cblack= [
22914 // 'font-size' -- this can be set by the project
22918 Roo.HtmlEditorCore.swapCodes =[
22937 * @class Roo.bootstrap.HtmlEditor
22938 * @extends Roo.bootstrap.TextArea
22939 * Bootstrap HtmlEditor class
22942 * Create a new HtmlEditor
22943 * @param {Object} config The config object
22946 Roo.bootstrap.HtmlEditor = function(config){
22947 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22948 if (!this.toolbars) {
22949 this.toolbars = [];
22952 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22955 * @event initialize
22956 * Fires when the editor is fully initialized (including the iframe)
22957 * @param {HtmlEditor} this
22962 * Fires when the editor is first receives the focus. Any insertion must wait
22963 * until after this event.
22964 * @param {HtmlEditor} this
22968 * @event beforesync
22969 * Fires before the textarea is updated with content from the editor iframe. Return false
22970 * to cancel the sync.
22971 * @param {HtmlEditor} this
22972 * @param {String} html
22976 * @event beforepush
22977 * Fires before the iframe editor is updated with content from the textarea. Return false
22978 * to cancel the push.
22979 * @param {HtmlEditor} this
22980 * @param {String} html
22985 * Fires when the textarea is updated with content from the editor iframe.
22986 * @param {HtmlEditor} this
22987 * @param {String} html
22992 * Fires when the iframe editor is updated with content from the textarea.
22993 * @param {HtmlEditor} this
22994 * @param {String} html
22998 * @event editmodechange
22999 * Fires when the editor switches edit modes
23000 * @param {HtmlEditor} this
23001 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23003 editmodechange: true,
23005 * @event editorevent
23006 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23007 * @param {HtmlEditor} this
23011 * @event firstfocus
23012 * Fires when on first focus - needed by toolbars..
23013 * @param {HtmlEditor} this
23018 * Auto save the htmlEditor value as a file into Events
23019 * @param {HtmlEditor} this
23023 * @event savedpreview
23024 * preview the saved version of htmlEditor
23025 * @param {HtmlEditor} this
23032 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23036 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23041 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23046 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23051 * @cfg {Number} height (in pixels)
23055 * @cfg {Number} width (in pixels)
23060 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23063 stylesheets: false,
23068 // private properties
23069 validationEvent : false,
23071 initialized : false,
23074 onFocus : Roo.emptyFn,
23076 hideMode:'offsets',
23078 tbContainer : false,
23082 toolbarContainer :function() {
23083 return this.wrap.select('.x-html-editor-tb',true).first();
23087 * Protected method that will not generally be called directly. It
23088 * is called when the editor creates its toolbar. Override this method if you need to
23089 * add custom toolbar buttons.
23090 * @param {HtmlEditor} editor
23092 createToolbar : function(){
23093 Roo.log('renewing');
23094 Roo.log("create toolbars");
23096 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23097 this.toolbars[0].render(this.toolbarContainer());
23101 // if (!editor.toolbars || !editor.toolbars.length) {
23102 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23105 // for (var i =0 ; i < editor.toolbars.length;i++) {
23106 // editor.toolbars[i] = Roo.factory(
23107 // typeof(editor.toolbars[i]) == 'string' ?
23108 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23109 // Roo.bootstrap.HtmlEditor);
23110 // editor.toolbars[i].init(editor);
23116 onRender : function(ct, position)
23118 // Roo.log("Call onRender: " + this.xtype);
23120 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23122 this.wrap = this.inputEl().wrap({
23123 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23126 this.editorcore.onRender(ct, position);
23128 if (this.resizable) {
23129 this.resizeEl = new Roo.Resizable(this.wrap, {
23133 minHeight : this.height,
23134 height: this.height,
23135 handles : this.resizable,
23138 resize : function(r, w, h) {
23139 _t.onResize(w,h); // -something
23145 this.createToolbar(this);
23148 if(!this.width && this.resizable){
23149 this.setSize(this.wrap.getSize());
23151 if (this.resizeEl) {
23152 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23153 // should trigger onReize..
23159 onResize : function(w, h)
23161 Roo.log('resize: ' +w + ',' + h );
23162 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23166 if(this.inputEl() ){
23167 if(typeof w == 'number'){
23168 var aw = w - this.wrap.getFrameWidth('lr');
23169 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23172 if(typeof h == 'number'){
23173 var tbh = -11; // fixme it needs to tool bar size!
23174 for (var i =0; i < this.toolbars.length;i++) {
23175 // fixme - ask toolbars for heights?
23176 tbh += this.toolbars[i].el.getHeight();
23177 //if (this.toolbars[i].footer) {
23178 // tbh += this.toolbars[i].footer.el.getHeight();
23186 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23187 ah -= 5; // knock a few pixes off for look..
23188 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23192 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23193 this.editorcore.onResize(ew,eh);
23198 * Toggles the editor between standard and source edit mode.
23199 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23201 toggleSourceEdit : function(sourceEditMode)
23203 this.editorcore.toggleSourceEdit(sourceEditMode);
23205 if(this.editorcore.sourceEditMode){
23206 Roo.log('editor - showing textarea');
23209 // Roo.log(this.syncValue());
23211 this.inputEl().removeClass(['hide', 'x-hidden']);
23212 this.inputEl().dom.removeAttribute('tabIndex');
23213 this.inputEl().focus();
23215 Roo.log('editor - hiding textarea');
23217 // Roo.log(this.pushValue());
23220 this.inputEl().addClass(['hide', 'x-hidden']);
23221 this.inputEl().dom.setAttribute('tabIndex', -1);
23222 //this.deferFocus();
23225 if(this.resizable){
23226 this.setSize(this.wrap.getSize());
23229 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23232 // private (for BoxComponent)
23233 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23235 // private (for BoxComponent)
23236 getResizeEl : function(){
23240 // private (for BoxComponent)
23241 getPositionEl : function(){
23246 initEvents : function(){
23247 this.originalValue = this.getValue();
23251 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23254 // markInvalid : Roo.emptyFn,
23256 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23259 // clearInvalid : Roo.emptyFn,
23261 setValue : function(v){
23262 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23263 this.editorcore.pushValue();
23268 deferFocus : function(){
23269 this.focus.defer(10, this);
23273 focus : function(){
23274 this.editorcore.focus();
23280 onDestroy : function(){
23286 for (var i =0; i < this.toolbars.length;i++) {
23287 // fixme - ask toolbars for heights?
23288 this.toolbars[i].onDestroy();
23291 this.wrap.dom.innerHTML = '';
23292 this.wrap.remove();
23297 onFirstFocus : function(){
23298 //Roo.log("onFirstFocus");
23299 this.editorcore.onFirstFocus();
23300 for (var i =0; i < this.toolbars.length;i++) {
23301 this.toolbars[i].onFirstFocus();
23307 syncValue : function()
23309 this.editorcore.syncValue();
23312 pushValue : function()
23314 this.editorcore.pushValue();
23318 // hide stuff that is not compatible
23332 * @event specialkey
23336 * @cfg {String} fieldClass @hide
23339 * @cfg {String} focusClass @hide
23342 * @cfg {String} autoCreate @hide
23345 * @cfg {String} inputType @hide
23348 * @cfg {String} invalidClass @hide
23351 * @cfg {String} invalidText @hide
23354 * @cfg {String} msgFx @hide
23357 * @cfg {String} validateOnBlur @hide
23366 Roo.namespace('Roo.bootstrap.htmleditor');
23368 * @class Roo.bootstrap.HtmlEditorToolbar1
23373 new Roo.bootstrap.HtmlEditor({
23376 new Roo.bootstrap.HtmlEditorToolbar1({
23377 disable : { fonts: 1 , format: 1, ..., ... , ...],
23383 * @cfg {Object} disable List of elements to disable..
23384 * @cfg {Array} btns List of additional buttons.
23388 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23391 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23394 Roo.apply(this, config);
23396 // default disabled, based on 'good practice'..
23397 this.disable = this.disable || {};
23398 Roo.applyIf(this.disable, {
23401 specialElements : true
23403 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23405 this.editor = config.editor;
23406 this.editorcore = config.editor.editorcore;
23408 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23410 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23411 // dont call parent... till later.
23413 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23418 editorcore : false,
23423 "h1","h2","h3","h4","h5","h6",
23425 "abbr", "acronym", "address", "cite", "samp", "var",
23429 onRender : function(ct, position)
23431 // Roo.log("Call onRender: " + this.xtype);
23433 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23435 this.el.dom.style.marginBottom = '0';
23437 var editorcore = this.editorcore;
23438 var editor= this.editor;
23441 var btn = function(id,cmd , toggle, handler, html){
23443 var event = toggle ? 'toggle' : 'click';
23448 xns: Roo.bootstrap,
23451 enableToggle:toggle !== false,
23453 pressed : toggle ? false : null,
23456 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23457 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23463 // var cb_box = function...
23468 xns: Roo.bootstrap,
23469 glyphicon : 'font',
23473 xns: Roo.bootstrap,
23477 Roo.each(this.formats, function(f) {
23478 style.menu.items.push({
23480 xns: Roo.bootstrap,
23481 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23486 editorcore.insertTag(this.tagname);
23493 children.push(style);
23495 btn('bold',false,true);
23496 btn('italic',false,true);
23497 btn('align-left', 'justifyleft',true);
23498 btn('align-center', 'justifycenter',true);
23499 btn('align-right' , 'justifyright',true);
23500 btn('link', false, false, function(btn) {
23501 //Roo.log("create link?");
23502 var url = prompt(this.createLinkText, this.defaultLinkValue);
23503 if(url && url != 'http:/'+'/'){
23504 this.editorcore.relayCmd('createlink', url);
23507 btn('list','insertunorderedlist',true);
23508 btn('pencil', false,true, function(btn){
23510 this.toggleSourceEdit(btn.pressed);
23513 if (this.editor.btns.length > 0) {
23514 for (var i = 0; i<this.editor.btns.length; i++) {
23515 children.push(this.editor.btns[i]);
23523 xns: Roo.bootstrap,
23528 xns: Roo.bootstrap,
23533 cog.menu.items.push({
23535 xns: Roo.bootstrap,
23536 html : Clean styles,
23541 editorcore.insertTag(this.tagname);
23550 this.xtype = 'NavSimplebar';
23552 for(var i=0;i< children.length;i++) {
23554 this.buttons.add(this.addxtypeChild(children[i]));
23558 editor.on('editorevent', this.updateToolbar, this);
23560 onBtnClick : function(id)
23562 this.editorcore.relayCmd(id);
23563 this.editorcore.focus();
23567 * Protected method that will not generally be called directly. It triggers
23568 * a toolbar update by reading the markup state of the current selection in the editor.
23570 updateToolbar: function(){
23572 if(!this.editorcore.activated){
23573 this.editor.onFirstFocus(); // is this neeed?
23577 var btns = this.buttons;
23578 var doc = this.editorcore.doc;
23579 btns.get('bold').setActive(doc.queryCommandState('bold'));
23580 btns.get('italic').setActive(doc.queryCommandState('italic'));
23581 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23583 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23584 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23585 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23587 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23588 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23591 var ans = this.editorcore.getAllAncestors();
23592 if (this.formatCombo) {
23595 var store = this.formatCombo.store;
23596 this.formatCombo.setValue("");
23597 for (var i =0; i < ans.length;i++) {
23598 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23600 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23608 // hides menus... - so this cant be on a menu...
23609 Roo.bootstrap.MenuMgr.hideAll();
23611 Roo.bootstrap.MenuMgr.hideAll();
23612 //this.editorsyncValue();
23614 onFirstFocus: function() {
23615 this.buttons.each(function(item){
23619 toggleSourceEdit : function(sourceEditMode){
23622 if(sourceEditMode){
23623 Roo.log("disabling buttons");
23624 this.buttons.each( function(item){
23625 if(item.cmd != 'pencil'){
23631 Roo.log("enabling buttons");
23632 if(this.editorcore.initialized){
23633 this.buttons.each( function(item){
23639 Roo.log("calling toggole on editor");
23640 // tell the editor that it's been pressed..
23641 this.editor.toggleSourceEdit(sourceEditMode);
23651 * @class Roo.bootstrap.Table.AbstractSelectionModel
23652 * @extends Roo.util.Observable
23653 * Abstract base class for grid SelectionModels. It provides the interface that should be
23654 * implemented by descendant classes. This class should not be directly instantiated.
23657 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23658 this.locked = false;
23659 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23663 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23664 /** @ignore Called by the grid automatically. Do not call directly. */
23665 init : function(grid){
23671 * Locks the selections.
23674 this.locked = true;
23678 * Unlocks the selections.
23680 unlock : function(){
23681 this.locked = false;
23685 * Returns true if the selections are locked.
23686 * @return {Boolean}
23688 isLocked : function(){
23689 return this.locked;
23693 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23694 * @class Roo.bootstrap.Table.RowSelectionModel
23695 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23696 * It supports multiple selections and keyboard selection/navigation.
23698 * @param {Object} config
23701 Roo.bootstrap.Table.RowSelectionModel = function(config){
23702 Roo.apply(this, config);
23703 this.selections = new Roo.util.MixedCollection(false, function(o){
23708 this.lastActive = false;
23712 * @event selectionchange
23713 * Fires when the selection changes
23714 * @param {SelectionModel} this
23716 "selectionchange" : true,
23718 * @event afterselectionchange
23719 * Fires after the selection changes (eg. by key press or clicking)
23720 * @param {SelectionModel} this
23722 "afterselectionchange" : true,
23724 * @event beforerowselect
23725 * Fires when a row is selected being selected, return false to cancel.
23726 * @param {SelectionModel} this
23727 * @param {Number} rowIndex The selected index
23728 * @param {Boolean} keepExisting False if other selections will be cleared
23730 "beforerowselect" : true,
23733 * Fires when a row is selected.
23734 * @param {SelectionModel} this
23735 * @param {Number} rowIndex The selected index
23736 * @param {Roo.data.Record} r The record
23738 "rowselect" : true,
23740 * @event rowdeselect
23741 * Fires when a row is deselected.
23742 * @param {SelectionModel} this
23743 * @param {Number} rowIndex The selected index
23745 "rowdeselect" : true
23747 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23748 this.locked = false;
23751 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23753 * @cfg {Boolean} singleSelect
23754 * True to allow selection of only one row at a time (defaults to false)
23756 singleSelect : false,
23759 initEvents : function()
23762 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23763 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23764 //}else{ // allow click to work like normal
23765 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23767 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23768 this.grid.on("rowclick", this.handleMouseDown, this);
23770 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23771 "up" : function(e){
23773 this.selectPrevious(e.shiftKey);
23774 }else if(this.last !== false && this.lastActive !== false){
23775 var last = this.last;
23776 this.selectRange(this.last, this.lastActive-1);
23777 this.grid.getView().focusRow(this.lastActive);
23778 if(last !== false){
23782 this.selectFirstRow();
23784 this.fireEvent("afterselectionchange", this);
23786 "down" : function(e){
23788 this.selectNext(e.shiftKey);
23789 }else if(this.last !== false && this.lastActive !== false){
23790 var last = this.last;
23791 this.selectRange(this.last, this.lastActive+1);
23792 this.grid.getView().focusRow(this.lastActive);
23793 if(last !== false){
23797 this.selectFirstRow();
23799 this.fireEvent("afterselectionchange", this);
23803 this.grid.store.on('load', function(){
23804 this.selections.clear();
23807 var view = this.grid.view;
23808 view.on("refresh", this.onRefresh, this);
23809 view.on("rowupdated", this.onRowUpdated, this);
23810 view.on("rowremoved", this.onRemove, this);
23815 onRefresh : function()
23817 var ds = this.grid.store, i, v = this.grid.view;
23818 var s = this.selections;
23819 s.each(function(r){
23820 if((i = ds.indexOfId(r.id)) != -1){
23829 onRemove : function(v, index, r){
23830 this.selections.remove(r);
23834 onRowUpdated : function(v, index, r){
23835 if(this.isSelected(r)){
23836 v.onRowSelect(index);
23842 * @param {Array} records The records to select
23843 * @param {Boolean} keepExisting (optional) True to keep existing selections
23845 selectRecords : function(records, keepExisting)
23848 this.clearSelections();
23850 var ds = this.grid.store;
23851 for(var i = 0, len = records.length; i < len; i++){
23852 this.selectRow(ds.indexOf(records[i]), true);
23857 * Gets the number of selected rows.
23860 getCount : function(){
23861 return this.selections.length;
23865 * Selects the first row in the grid.
23867 selectFirstRow : function(){
23872 * Select the last row.
23873 * @param {Boolean} keepExisting (optional) True to keep existing selections
23875 selectLastRow : function(keepExisting){
23876 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23877 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23881 * Selects the row immediately following the last selected row.
23882 * @param {Boolean} keepExisting (optional) True to keep existing selections
23884 selectNext : function(keepExisting)
23886 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23887 this.selectRow(this.last+1, keepExisting);
23888 this.grid.getView().focusRow(this.last);
23893 * Selects the row that precedes the last selected row.
23894 * @param {Boolean} keepExisting (optional) True to keep existing selections
23896 selectPrevious : function(keepExisting){
23898 this.selectRow(this.last-1, keepExisting);
23899 this.grid.getView().focusRow(this.last);
23904 * Returns the selected records
23905 * @return {Array} Array of selected records
23907 getSelections : function(){
23908 return [].concat(this.selections.items);
23912 * Returns the first selected record.
23915 getSelected : function(){
23916 return this.selections.itemAt(0);
23921 * Clears all selections.
23923 clearSelections : function(fast)
23929 var ds = this.grid.store;
23930 var s = this.selections;
23931 s.each(function(r){
23932 this.deselectRow(ds.indexOfId(r.id));
23936 this.selections.clear();
23943 * Selects all rows.
23945 selectAll : function(){
23949 this.selections.clear();
23950 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23951 this.selectRow(i, true);
23956 * Returns True if there is a selection.
23957 * @return {Boolean}
23959 hasSelection : function(){
23960 return this.selections.length > 0;
23964 * Returns True if the specified row is selected.
23965 * @param {Number/Record} record The record or index of the record to check
23966 * @return {Boolean}
23968 isSelected : function(index){
23969 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23970 return (r && this.selections.key(r.id) ? true : false);
23974 * Returns True if the specified record id is selected.
23975 * @param {String} id The id of record to check
23976 * @return {Boolean}
23978 isIdSelected : function(id){
23979 return (this.selections.key(id) ? true : false);
23984 handleMouseDBClick : function(e, t){
23988 handleMouseDown : function(e, t)
23990 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23991 if(this.isLocked() || rowIndex < 0 ){
23994 if(e.shiftKey && this.last !== false){
23995 var last = this.last;
23996 this.selectRange(last, rowIndex, e.ctrlKey);
23997 this.last = last; // reset the last
24001 var isSelected = this.isSelected(rowIndex);
24002 //Roo.log("select row:" + rowIndex);
24004 this.deselectRow(rowIndex);
24006 this.selectRow(rowIndex, true);
24010 if(e.button !== 0 && isSelected){
24011 alert('rowIndex 2: ' + rowIndex);
24012 view.focusRow(rowIndex);
24013 }else if(e.ctrlKey && isSelected){
24014 this.deselectRow(rowIndex);
24015 }else if(!isSelected){
24016 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24017 view.focusRow(rowIndex);
24021 this.fireEvent("afterselectionchange", this);
24024 handleDragableRowClick : function(grid, rowIndex, e)
24026 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24027 this.selectRow(rowIndex, false);
24028 grid.view.focusRow(rowIndex);
24029 this.fireEvent("afterselectionchange", this);
24034 * Selects multiple rows.
24035 * @param {Array} rows Array of the indexes of the row to select
24036 * @param {Boolean} keepExisting (optional) True to keep existing selections
24038 selectRows : function(rows, keepExisting){
24040 this.clearSelections();
24042 for(var i = 0, len = rows.length; i < len; i++){
24043 this.selectRow(rows[i], true);
24048 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24049 * @param {Number} startRow The index of the first row in the range
24050 * @param {Number} endRow The index of the last row in the range
24051 * @param {Boolean} keepExisting (optional) True to retain existing selections
24053 selectRange : function(startRow, endRow, keepExisting){
24058 this.clearSelections();
24060 if(startRow <= endRow){
24061 for(var i = startRow; i <= endRow; i++){
24062 this.selectRow(i, true);
24065 for(var i = startRow; i >= endRow; i--){
24066 this.selectRow(i, true);
24072 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24073 * @param {Number} startRow The index of the first row in the range
24074 * @param {Number} endRow The index of the last row in the range
24076 deselectRange : function(startRow, endRow, preventViewNotify){
24080 for(var i = startRow; i <= endRow; i++){
24081 this.deselectRow(i, preventViewNotify);
24087 * @param {Number} row The index of the row to select
24088 * @param {Boolean} keepExisting (optional) True to keep existing selections
24090 selectRow : function(index, keepExisting, preventViewNotify)
24092 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24095 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24096 if(!keepExisting || this.singleSelect){
24097 this.clearSelections();
24100 var r = this.grid.store.getAt(index);
24101 //console.log('selectRow - record id :' + r.id);
24103 this.selections.add(r);
24104 this.last = this.lastActive = index;
24105 if(!preventViewNotify){
24106 var proxy = new Roo.Element(
24107 this.grid.getRowDom(index)
24109 proxy.addClass('bg-info info');
24111 this.fireEvent("rowselect", this, index, r);
24112 this.fireEvent("selectionchange", this);
24118 * @param {Number} row The index of the row to deselect
24120 deselectRow : function(index, preventViewNotify)
24125 if(this.last == index){
24128 if(this.lastActive == index){
24129 this.lastActive = false;
24132 var r = this.grid.store.getAt(index);
24137 this.selections.remove(r);
24138 //.console.log('deselectRow - record id :' + r.id);
24139 if(!preventViewNotify){
24141 var proxy = new Roo.Element(
24142 this.grid.getRowDom(index)
24144 proxy.removeClass('bg-info info');
24146 this.fireEvent("rowdeselect", this, index);
24147 this.fireEvent("selectionchange", this);
24151 restoreLast : function(){
24153 this.last = this._last;
24158 acceptsNav : function(row, col, cm){
24159 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24163 onEditorKey : function(field, e){
24164 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24169 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24171 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24173 }else if(k == e.ENTER && !e.ctrlKey){
24177 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24179 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24181 }else if(k == e.ESC){
24185 g.startEditing(newCell[0], newCell[1]);
24191 * Ext JS Library 1.1.1
24192 * Copyright(c) 2006-2007, Ext JS, LLC.
24194 * Originally Released Under LGPL - original licence link has changed is not relivant.
24197 * <script type="text/javascript">
24201 * @class Roo.bootstrap.PagingToolbar
24202 * @extends Roo.bootstrap.NavSimplebar
24203 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24205 * Create a new PagingToolbar
24206 * @param {Object} config The config object
24207 * @param {Roo.data.Store} store
24209 Roo.bootstrap.PagingToolbar = function(config)
24211 // old args format still supported... - xtype is prefered..
24212 // created from xtype...
24214 this.ds = config.dataSource;
24216 if (config.store && !this.ds) {
24217 this.store= Roo.factory(config.store, Roo.data);
24218 this.ds = this.store;
24219 this.ds.xmodule = this.xmodule || false;
24222 this.toolbarItems = [];
24223 if (config.items) {
24224 this.toolbarItems = config.items;
24227 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24232 this.bind(this.ds);
24235 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24239 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24241 * @cfg {Roo.data.Store} dataSource
24242 * The underlying data store providing the paged data
24245 * @cfg {String/HTMLElement/Element} container
24246 * container The id or element that will contain the toolbar
24249 * @cfg {Boolean} displayInfo
24250 * True to display the displayMsg (defaults to false)
24253 * @cfg {Number} pageSize
24254 * The number of records to display per page (defaults to 20)
24258 * @cfg {String} displayMsg
24259 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24261 displayMsg : 'Displaying {0} - {1} of {2}',
24263 * @cfg {String} emptyMsg
24264 * The message to display when no records are found (defaults to "No data to display")
24266 emptyMsg : 'No data to display',
24268 * Customizable piece of the default paging text (defaults to "Page")
24271 beforePageText : "Page",
24273 * Customizable piece of the default paging text (defaults to "of %0")
24276 afterPageText : "of {0}",
24278 * Customizable piece of the default paging text (defaults to "First Page")
24281 firstText : "First Page",
24283 * Customizable piece of the default paging text (defaults to "Previous Page")
24286 prevText : "Previous Page",
24288 * Customizable piece of the default paging text (defaults to "Next Page")
24291 nextText : "Next Page",
24293 * Customizable piece of the default paging text (defaults to "Last Page")
24296 lastText : "Last Page",
24298 * Customizable piece of the default paging text (defaults to "Refresh")
24301 refreshText : "Refresh",
24305 onRender : function(ct, position)
24307 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24308 this.navgroup.parentId = this.id;
24309 this.navgroup.onRender(this.el, null);
24310 // add the buttons to the navgroup
24312 if(this.displayInfo){
24313 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24314 this.displayEl = this.el.select('.x-paging-info', true).first();
24315 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24316 // this.displayEl = navel.el.select('span',true).first();
24322 Roo.each(_this.buttons, function(e){ // this might need to use render????
24323 Roo.factory(e).onRender(_this.el, null);
24327 Roo.each(_this.toolbarItems, function(e) {
24328 _this.navgroup.addItem(e);
24332 this.first = this.navgroup.addItem({
24333 tooltip: this.firstText,
24335 icon : 'fa fa-backward',
24337 preventDefault: true,
24338 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24341 this.prev = this.navgroup.addItem({
24342 tooltip: this.prevText,
24344 icon : 'fa fa-step-backward',
24346 preventDefault: true,
24347 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24349 //this.addSeparator();
24352 var field = this.navgroup.addItem( {
24354 cls : 'x-paging-position',
24356 html : this.beforePageText +
24357 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24358 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24361 this.field = field.el.select('input', true).first();
24362 this.field.on("keydown", this.onPagingKeydown, this);
24363 this.field.on("focus", function(){this.dom.select();});
24366 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24367 //this.field.setHeight(18);
24368 //this.addSeparator();
24369 this.next = this.navgroup.addItem({
24370 tooltip: this.nextText,
24372 html : ' <i class="fa fa-step-forward">',
24374 preventDefault: true,
24375 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24377 this.last = this.navgroup.addItem({
24378 tooltip: this.lastText,
24379 icon : 'fa fa-forward',
24382 preventDefault: true,
24383 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24385 //this.addSeparator();
24386 this.loading = this.navgroup.addItem({
24387 tooltip: this.refreshText,
24388 icon: 'fa fa-refresh',
24389 preventDefault: true,
24390 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24396 updateInfo : function(){
24397 if(this.displayEl){
24398 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24399 var msg = count == 0 ?
24403 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24405 this.displayEl.update(msg);
24410 onLoad : function(ds, r, o)
24412 this.cursor = o.params ? o.params.start : 0;
24413 var d = this.getPageData(),
24418 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24419 this.field.dom.value = ap;
24420 this.first.setDisabled(ap == 1);
24421 this.prev.setDisabled(ap == 1);
24422 this.next.setDisabled(ap == ps);
24423 this.last.setDisabled(ap == ps);
24424 this.loading.enable();
24429 getPageData : function(){
24430 var total = this.ds.getTotalCount();
24433 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24434 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24439 onLoadError : function(){
24440 this.loading.enable();
24444 onPagingKeydown : function(e){
24445 var k = e.getKey();
24446 var d = this.getPageData();
24448 var v = this.field.dom.value, pageNum;
24449 if(!v || isNaN(pageNum = parseInt(v, 10))){
24450 this.field.dom.value = d.activePage;
24453 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24454 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24457 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))
24459 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24460 this.field.dom.value = pageNum;
24461 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24464 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24466 var v = this.field.dom.value, pageNum;
24467 var increment = (e.shiftKey) ? 10 : 1;
24468 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24471 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24472 this.field.dom.value = d.activePage;
24475 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24477 this.field.dom.value = parseInt(v, 10) + increment;
24478 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24479 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24486 beforeLoad : function(){
24488 this.loading.disable();
24493 onClick : function(which){
24502 ds.load({params:{start: 0, limit: this.pageSize}});
24505 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24508 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24511 var total = ds.getTotalCount();
24512 var extra = total % this.pageSize;
24513 var lastStart = extra ? (total - extra) : total-this.pageSize;
24514 ds.load({params:{start: lastStart, limit: this.pageSize}});
24517 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24523 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24524 * @param {Roo.data.Store} store The data store to unbind
24526 unbind : function(ds){
24527 ds.un("beforeload", this.beforeLoad, this);
24528 ds.un("load", this.onLoad, this);
24529 ds.un("loadexception", this.onLoadError, this);
24530 ds.un("remove", this.updateInfo, this);
24531 ds.un("add", this.updateInfo, this);
24532 this.ds = undefined;
24536 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24537 * @param {Roo.data.Store} store The data store to bind
24539 bind : function(ds){
24540 ds.on("beforeload", this.beforeLoad, this);
24541 ds.on("load", this.onLoad, this);
24542 ds.on("loadexception", this.onLoadError, this);
24543 ds.on("remove", this.updateInfo, this);
24544 ds.on("add", this.updateInfo, this);
24555 * @class Roo.bootstrap.MessageBar
24556 * @extends Roo.bootstrap.Component
24557 * Bootstrap MessageBar class
24558 * @cfg {String} html contents of the MessageBar
24559 * @cfg {String} weight (info | success | warning | danger) default info
24560 * @cfg {String} beforeClass insert the bar before the given class
24561 * @cfg {Boolean} closable (true | false) default false
24562 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24565 * Create a new Element
24566 * @param {Object} config The config object
24569 Roo.bootstrap.MessageBar = function(config){
24570 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24573 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24579 beforeClass: 'bootstrap-sticky-wrap',
24581 getAutoCreate : function(){
24585 cls: 'alert alert-dismissable alert-' + this.weight,
24590 html: this.html || ''
24596 cfg.cls += ' alert-messages-fixed';
24610 onRender : function(ct, position)
24612 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24615 var cfg = Roo.apply({}, this.getAutoCreate());
24619 cfg.cls += ' ' + this.cls;
24622 cfg.style = this.style;
24624 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24626 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24629 this.el.select('>button.close').on('click', this.hide, this);
24635 if (!this.rendered) {
24641 this.fireEvent('show', this);
24647 if (!this.rendered) {
24653 this.fireEvent('hide', this);
24656 update : function()
24658 // var e = this.el.dom.firstChild;
24660 // if(this.closable){
24661 // e = e.nextSibling;
24664 // e.data = this.html || '';
24666 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24682 * @class Roo.bootstrap.Graph
24683 * @extends Roo.bootstrap.Component
24684 * Bootstrap Graph class
24688 @cfg {String} graphtype bar | vbar | pie
24689 @cfg {number} g_x coodinator | centre x (pie)
24690 @cfg {number} g_y coodinator | centre y (pie)
24691 @cfg {number} g_r radius (pie)
24692 @cfg {number} g_height height of the chart (respected by all elements in the set)
24693 @cfg {number} g_width width of the chart (respected by all elements in the set)
24694 @cfg {Object} title The title of the chart
24697 -opts (object) options for the chart
24699 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24700 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24702 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.
24703 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24705 o stretch (boolean)
24707 -opts (object) options for the pie
24710 o startAngle (number)
24711 o endAngle (number)
24715 * Create a new Input
24716 * @param {Object} config The config object
24719 Roo.bootstrap.Graph = function(config){
24720 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24726 * The img click event for the img.
24727 * @param {Roo.EventObject} e
24733 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24744 //g_colors: this.colors,
24751 getAutoCreate : function(){
24762 onRender : function(ct,position){
24765 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24767 if (typeof(Raphael) == 'undefined') {
24768 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24772 this.raphael = Raphael(this.el.dom);
24774 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24775 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24776 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24777 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24779 r.text(160, 10, "Single Series Chart").attr(txtattr);
24780 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24781 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24782 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24784 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24785 r.barchart(330, 10, 300, 220, data1);
24786 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24787 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24790 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24791 // r.barchart(30, 30, 560, 250, xdata, {
24792 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24793 // axis : "0 0 1 1",
24794 // axisxlabels : xdata
24795 // //yvalues : cols,
24798 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24800 // this.load(null,xdata,{
24801 // axis : "0 0 1 1",
24802 // axisxlabels : xdata
24807 load : function(graphtype,xdata,opts)
24809 this.raphael.clear();
24811 graphtype = this.graphtype;
24816 var r = this.raphael,
24817 fin = function () {
24818 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24820 fout = function () {
24821 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24823 pfin = function() {
24824 this.sector.stop();
24825 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24828 this.label[0].stop();
24829 this.label[0].attr({ r: 7.5 });
24830 this.label[1].attr({ "font-weight": 800 });
24833 pfout = function() {
24834 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24837 this.label[0].animate({ r: 5 }, 500, "bounce");
24838 this.label[1].attr({ "font-weight": 400 });
24844 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24847 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24850 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24851 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24853 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24860 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24865 setTitle: function(o)
24870 initEvents: function() {
24873 this.el.on('click', this.onClick, this);
24877 onClick : function(e)
24879 Roo.log('img onclick');
24880 this.fireEvent('click', this, e);
24892 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24895 * @class Roo.bootstrap.dash.NumberBox
24896 * @extends Roo.bootstrap.Component
24897 * Bootstrap NumberBox class
24898 * @cfg {String} headline Box headline
24899 * @cfg {String} content Box content
24900 * @cfg {String} icon Box icon
24901 * @cfg {String} footer Footer text
24902 * @cfg {String} fhref Footer href
24905 * Create a new NumberBox
24906 * @param {Object} config The config object
24910 Roo.bootstrap.dash.NumberBox = function(config){
24911 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24915 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24924 getAutoCreate : function(){
24928 cls : 'small-box ',
24936 cls : 'roo-headline',
24937 html : this.headline
24941 cls : 'roo-content',
24942 html : this.content
24956 cls : 'ion ' + this.icon
24965 cls : 'small-box-footer',
24966 href : this.fhref || '#',
24970 cfg.cn.push(footer);
24977 onRender : function(ct,position){
24978 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24985 setHeadline: function (value)
24987 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24990 setFooter: function (value, href)
24992 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24995 this.el.select('a.small-box-footer',true).first().attr('href', href);
25000 setContent: function (value)
25002 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25005 initEvents: function()
25019 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25022 * @class Roo.bootstrap.dash.TabBox
25023 * @extends Roo.bootstrap.Component
25024 * Bootstrap TabBox class
25025 * @cfg {String} title Title of the TabBox
25026 * @cfg {String} icon Icon of the TabBox
25027 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25028 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25031 * Create a new TabBox
25032 * @param {Object} config The config object
25036 Roo.bootstrap.dash.TabBox = function(config){
25037 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25042 * When a pane is added
25043 * @param {Roo.bootstrap.dash.TabPane} pane
25047 * @event activatepane
25048 * When a pane is activated
25049 * @param {Roo.bootstrap.dash.TabPane} pane
25051 "activatepane" : true
25059 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25064 tabScrollable : false,
25066 getChildContainer : function()
25068 return this.el.select('.tab-content', true).first();
25071 getAutoCreate : function(){
25075 cls: 'pull-left header',
25083 cls: 'fa ' + this.icon
25089 cls: 'nav nav-tabs pull-right',
25095 if(this.tabScrollable){
25102 cls: 'nav nav-tabs pull-right',
25113 cls: 'nav-tabs-custom',
25118 cls: 'tab-content no-padding',
25126 initEvents : function()
25128 //Roo.log('add add pane handler');
25129 this.on('addpane', this.onAddPane, this);
25132 * Updates the box title
25133 * @param {String} html to set the title to.
25135 setTitle : function(value)
25137 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25139 onAddPane : function(pane)
25141 this.panes.push(pane);
25142 //Roo.log('addpane');
25144 // tabs are rendere left to right..
25145 if(!this.showtabs){
25149 var ctr = this.el.select('.nav-tabs', true).first();
25152 var existing = ctr.select('.nav-tab',true);
25153 var qty = existing.getCount();;
25156 var tab = ctr.createChild({
25158 cls : 'nav-tab' + (qty ? '' : ' active'),
25166 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25169 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25171 pane.el.addClass('active');
25176 onTabClick : function(ev,un,ob,pane)
25178 //Roo.log('tab - prev default');
25179 ev.preventDefault();
25182 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25183 pane.tab.addClass('active');
25184 //Roo.log(pane.title);
25185 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25186 // technically we should have a deactivate event.. but maybe add later.
25187 // and it should not de-activate the selected tab...
25188 this.fireEvent('activatepane', pane);
25189 pane.el.addClass('active');
25190 pane.fireEvent('activate');
25195 getActivePane : function()
25198 Roo.each(this.panes, function(p) {
25199 if(p.el.hasClass('active')){
25220 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25222 * @class Roo.bootstrap.TabPane
25223 * @extends Roo.bootstrap.Component
25224 * Bootstrap TabPane class
25225 * @cfg {Boolean} active (false | true) Default false
25226 * @cfg {String} title title of panel
25230 * Create a new TabPane
25231 * @param {Object} config The config object
25234 Roo.bootstrap.dash.TabPane = function(config){
25235 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25241 * When a pane is activated
25242 * @param {Roo.bootstrap.dash.TabPane} pane
25249 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25254 // the tabBox that this is attached to.
25257 getAutoCreate : function()
25265 cfg.cls += ' active';
25270 initEvents : function()
25272 //Roo.log('trigger add pane handler');
25273 this.parent().fireEvent('addpane', this)
25277 * Updates the tab title
25278 * @param {String} html to set the title to.
25280 setTitle: function(str)
25286 this.tab.select('a', true).first().dom.innerHTML = str;
25303 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25306 * @class Roo.bootstrap.menu.Menu
25307 * @extends Roo.bootstrap.Component
25308 * Bootstrap Menu class - container for Menu
25309 * @cfg {String} html Text of the menu
25310 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25311 * @cfg {String} icon Font awesome icon
25312 * @cfg {String} pos Menu align to (top | bottom) default bottom
25316 * Create a new Menu
25317 * @param {Object} config The config object
25321 Roo.bootstrap.menu.Menu = function(config){
25322 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25326 * @event beforeshow
25327 * Fires before this menu is displayed
25328 * @param {Roo.bootstrap.menu.Menu} this
25332 * @event beforehide
25333 * Fires before this menu is hidden
25334 * @param {Roo.bootstrap.menu.Menu} this
25339 * Fires after this menu is displayed
25340 * @param {Roo.bootstrap.menu.Menu} this
25345 * Fires after this menu is hidden
25346 * @param {Roo.bootstrap.menu.Menu} this
25351 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25352 * @param {Roo.bootstrap.menu.Menu} this
25353 * @param {Roo.EventObject} e
25360 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25364 weight : 'default',
25369 getChildContainer : function() {
25370 if(this.isSubMenu){
25374 return this.el.select('ul.dropdown-menu', true).first();
25377 getAutoCreate : function()
25382 cls : 'roo-menu-text',
25390 cls : 'fa ' + this.icon
25401 cls : 'dropdown-button btn btn-' + this.weight,
25406 cls : 'dropdown-toggle btn btn-' + this.weight,
25416 cls : 'dropdown-menu'
25422 if(this.pos == 'top'){
25423 cfg.cls += ' dropup';
25426 if(this.isSubMenu){
25429 cls : 'dropdown-menu'
25436 onRender : function(ct, position)
25438 this.isSubMenu = ct.hasClass('dropdown-submenu');
25440 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25443 initEvents : function()
25445 if(this.isSubMenu){
25449 this.hidden = true;
25451 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25452 this.triggerEl.on('click', this.onTriggerPress, this);
25454 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25455 this.buttonEl.on('click', this.onClick, this);
25461 if(this.isSubMenu){
25465 return this.el.select('ul.dropdown-menu', true).first();
25468 onClick : function(e)
25470 this.fireEvent("click", this, e);
25473 onTriggerPress : function(e)
25475 if (this.isVisible()) {
25482 isVisible : function(){
25483 return !this.hidden;
25488 this.fireEvent("beforeshow", this);
25490 this.hidden = false;
25491 this.el.addClass('open');
25493 Roo.get(document).on("mouseup", this.onMouseUp, this);
25495 this.fireEvent("show", this);
25502 this.fireEvent("beforehide", this);
25504 this.hidden = true;
25505 this.el.removeClass('open');
25507 Roo.get(document).un("mouseup", this.onMouseUp);
25509 this.fireEvent("hide", this);
25512 onMouseUp : function()
25526 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25529 * @class Roo.bootstrap.menu.Item
25530 * @extends Roo.bootstrap.Component
25531 * Bootstrap MenuItem class
25532 * @cfg {Boolean} submenu (true | false) default false
25533 * @cfg {String} html text of the item
25534 * @cfg {String} href the link
25535 * @cfg {Boolean} disable (true | false) default false
25536 * @cfg {Boolean} preventDefault (true | false) default true
25537 * @cfg {String} icon Font awesome icon
25538 * @cfg {String} pos Submenu align to (left | right) default right
25542 * Create a new Item
25543 * @param {Object} config The config object
25547 Roo.bootstrap.menu.Item = function(config){
25548 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25552 * Fires when the mouse is hovering over this menu
25553 * @param {Roo.bootstrap.menu.Item} this
25554 * @param {Roo.EventObject} e
25559 * Fires when the mouse exits this menu
25560 * @param {Roo.bootstrap.menu.Item} this
25561 * @param {Roo.EventObject} e
25567 * The raw click event for the entire grid.
25568 * @param {Roo.EventObject} e
25574 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25579 preventDefault: true,
25584 getAutoCreate : function()
25589 cls : 'roo-menu-item-text',
25597 cls : 'fa ' + this.icon
25606 href : this.href || '#',
25613 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25617 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25619 if(this.pos == 'left'){
25620 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25627 initEvents : function()
25629 this.el.on('mouseover', this.onMouseOver, this);
25630 this.el.on('mouseout', this.onMouseOut, this);
25632 this.el.select('a', true).first().on('click', this.onClick, this);
25636 onClick : function(e)
25638 if(this.preventDefault){
25639 e.preventDefault();
25642 this.fireEvent("click", this, e);
25645 onMouseOver : function(e)
25647 if(this.submenu && this.pos == 'left'){
25648 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25651 this.fireEvent("mouseover", this, e);
25654 onMouseOut : function(e)
25656 this.fireEvent("mouseout", this, e);
25668 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25671 * @class Roo.bootstrap.menu.Separator
25672 * @extends Roo.bootstrap.Component
25673 * Bootstrap Separator class
25676 * Create a new Separator
25677 * @param {Object} config The config object
25681 Roo.bootstrap.menu.Separator = function(config){
25682 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25685 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25687 getAutoCreate : function(){
25708 * @class Roo.bootstrap.Tooltip
25709 * Bootstrap Tooltip class
25710 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25711 * to determine which dom element triggers the tooltip.
25713 * It needs to add support for additional attributes like tooltip-position
25716 * Create a new Toolti
25717 * @param {Object} config The config object
25720 Roo.bootstrap.Tooltip = function(config){
25721 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25723 this.alignment = Roo.bootstrap.Tooltip.alignment;
25725 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25726 this.alignment = config.alignment;
25731 Roo.apply(Roo.bootstrap.Tooltip, {
25733 * @function init initialize tooltip monitoring.
25737 currentTip : false,
25738 currentRegion : false,
25744 Roo.get(document).on('mouseover', this.enter ,this);
25745 Roo.get(document).on('mouseout', this.leave, this);
25748 this.currentTip = new Roo.bootstrap.Tooltip();
25751 enter : function(ev)
25753 var dom = ev.getTarget();
25755 //Roo.log(['enter',dom]);
25756 var el = Roo.fly(dom);
25757 if (this.currentEl) {
25759 //Roo.log(this.currentEl);
25760 //Roo.log(this.currentEl.contains(dom));
25761 if (this.currentEl == el) {
25764 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25770 if (this.currentTip.el) {
25771 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25775 if(!el || el.dom == document){
25781 // you can not look for children, as if el is the body.. then everythign is the child..
25782 if (!el.attr('tooltip')) { //
25783 if (!el.select("[tooltip]").elements.length) {
25786 // is the mouse over this child...?
25787 bindEl = el.select("[tooltip]").first();
25788 var xy = ev.getXY();
25789 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25790 //Roo.log("not in region.");
25793 //Roo.log("child element over..");
25796 this.currentEl = bindEl;
25797 this.currentTip.bind(bindEl);
25798 this.currentRegion = Roo.lib.Region.getRegion(dom);
25799 this.currentTip.enter();
25802 leave : function(ev)
25804 var dom = ev.getTarget();
25805 //Roo.log(['leave',dom]);
25806 if (!this.currentEl) {
25811 if (dom != this.currentEl.dom) {
25814 var xy = ev.getXY();
25815 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25818 // only activate leave if mouse cursor is outside... bounding box..
25823 if (this.currentTip) {
25824 this.currentTip.leave();
25826 //Roo.log('clear currentEl');
25827 this.currentEl = false;
25832 'left' : ['r-l', [-2,0], 'right'],
25833 'right' : ['l-r', [2,0], 'left'],
25834 'bottom' : ['t-b', [0,2], 'top'],
25835 'top' : [ 'b-t', [0,-2], 'bottom']
25841 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25846 delay : null, // can be { show : 300 , hide: 500}
25850 hoverState : null, //???
25852 placement : 'bottom',
25856 getAutoCreate : function(){
25863 cls : 'tooltip-arrow'
25866 cls : 'tooltip-inner'
25873 bind : function(el)
25879 enter : function () {
25881 if (this.timeout != null) {
25882 clearTimeout(this.timeout);
25885 this.hoverState = 'in';
25886 //Roo.log("enter - show");
25887 if (!this.delay || !this.delay.show) {
25892 this.timeout = setTimeout(function () {
25893 if (_t.hoverState == 'in') {
25896 }, this.delay.show);
25900 clearTimeout(this.timeout);
25902 this.hoverState = 'out';
25903 if (!this.delay || !this.delay.hide) {
25909 this.timeout = setTimeout(function () {
25910 //Roo.log("leave - timeout");
25912 if (_t.hoverState == 'out') {
25914 Roo.bootstrap.Tooltip.currentEl = false;
25919 show : function (msg)
25922 this.render(document.body);
25925 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25927 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25929 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25931 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25933 var placement = typeof this.placement == 'function' ?
25934 this.placement.call(this, this.el, on_el) :
25937 var autoToken = /\s?auto?\s?/i;
25938 var autoPlace = autoToken.test(placement);
25940 placement = placement.replace(autoToken, '') || 'top';
25944 //this.el.setXY([0,0]);
25946 //this.el.dom.style.display='block';
25948 //this.el.appendTo(on_el);
25950 var p = this.getPosition();
25951 var box = this.el.getBox();
25957 var align = this.alignment[placement];
25959 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25961 if(placement == 'top' || placement == 'bottom'){
25963 placement = 'right';
25966 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25967 placement = 'left';
25970 var scroll = Roo.select('body', true).first().getScroll();
25972 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25978 this.el.alignTo(this.bindEl, align[0],align[1]);
25979 //var arrow = this.el.select('.arrow',true).first();
25980 //arrow.set(align[2],
25982 this.el.addClass(placement);
25984 this.el.addClass('in fade');
25986 this.hoverState = null;
25988 if (this.el.hasClass('fade')) {
25999 //this.el.setXY([0,0]);
26000 this.el.removeClass('in');
26016 * @class Roo.bootstrap.LocationPicker
26017 * @extends Roo.bootstrap.Component
26018 * Bootstrap LocationPicker class
26019 * @cfg {Number} latitude Position when init default 0
26020 * @cfg {Number} longitude Position when init default 0
26021 * @cfg {Number} zoom default 15
26022 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26023 * @cfg {Boolean} mapTypeControl default false
26024 * @cfg {Boolean} disableDoubleClickZoom default false
26025 * @cfg {Boolean} scrollwheel default true
26026 * @cfg {Boolean} streetViewControl default false
26027 * @cfg {Number} radius default 0
26028 * @cfg {String} locationName
26029 * @cfg {Boolean} draggable default true
26030 * @cfg {Boolean} enableAutocomplete default false
26031 * @cfg {Boolean} enableReverseGeocode default true
26032 * @cfg {String} markerTitle
26035 * Create a new LocationPicker
26036 * @param {Object} config The config object
26040 Roo.bootstrap.LocationPicker = function(config){
26042 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26047 * Fires when the picker initialized.
26048 * @param {Roo.bootstrap.LocationPicker} this
26049 * @param {Google Location} location
26053 * @event positionchanged
26054 * Fires when the picker position changed.
26055 * @param {Roo.bootstrap.LocationPicker} this
26056 * @param {Google Location} location
26058 positionchanged : true,
26061 * Fires when the map resize.
26062 * @param {Roo.bootstrap.LocationPicker} this
26067 * Fires when the map show.
26068 * @param {Roo.bootstrap.LocationPicker} this
26073 * Fires when the map hide.
26074 * @param {Roo.bootstrap.LocationPicker} this
26079 * Fires when click the map.
26080 * @param {Roo.bootstrap.LocationPicker} this
26081 * @param {Map event} e
26085 * @event mapRightClick
26086 * Fires when right click the map.
26087 * @param {Roo.bootstrap.LocationPicker} this
26088 * @param {Map event} e
26090 mapRightClick : true,
26092 * @event markerClick
26093 * Fires when click the marker.
26094 * @param {Roo.bootstrap.LocationPicker} this
26095 * @param {Map event} e
26097 markerClick : true,
26099 * @event markerRightClick
26100 * Fires when right click the marker.
26101 * @param {Roo.bootstrap.LocationPicker} this
26102 * @param {Map event} e
26104 markerRightClick : true,
26106 * @event OverlayViewDraw
26107 * Fires when OverlayView Draw
26108 * @param {Roo.bootstrap.LocationPicker} this
26110 OverlayViewDraw : true,
26112 * @event OverlayViewOnAdd
26113 * Fires when OverlayView Draw
26114 * @param {Roo.bootstrap.LocationPicker} this
26116 OverlayViewOnAdd : true,
26118 * @event OverlayViewOnRemove
26119 * Fires when OverlayView Draw
26120 * @param {Roo.bootstrap.LocationPicker} this
26122 OverlayViewOnRemove : true,
26124 * @event OverlayViewShow
26125 * Fires when OverlayView Draw
26126 * @param {Roo.bootstrap.LocationPicker} this
26127 * @param {Pixel} cpx
26129 OverlayViewShow : true,
26131 * @event OverlayViewHide
26132 * Fires when OverlayView Draw
26133 * @param {Roo.bootstrap.LocationPicker} this
26135 OverlayViewHide : true,
26137 * @event loadexception
26138 * Fires when load google lib failed.
26139 * @param {Roo.bootstrap.LocationPicker} this
26141 loadexception : true
26146 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26148 gMapContext: false,
26154 mapTypeControl: false,
26155 disableDoubleClickZoom: false,
26157 streetViewControl: false,
26161 enableAutocomplete: false,
26162 enableReverseGeocode: true,
26165 getAutoCreate: function()
26170 cls: 'roo-location-picker'
26176 initEvents: function(ct, position)
26178 if(!this.el.getWidth() || this.isApplied()){
26182 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26187 initial: function()
26189 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26190 this.fireEvent('loadexception', this);
26194 if(!this.mapTypeId){
26195 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26198 this.gMapContext = this.GMapContext();
26200 this.initOverlayView();
26202 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26206 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26207 _this.setPosition(_this.gMapContext.marker.position);
26210 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26211 _this.fireEvent('mapClick', this, event);
26215 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26216 _this.fireEvent('mapRightClick', this, event);
26220 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26221 _this.fireEvent('markerClick', this, event);
26225 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26226 _this.fireEvent('markerRightClick', this, event);
26230 this.setPosition(this.gMapContext.location);
26232 this.fireEvent('initial', this, this.gMapContext.location);
26235 initOverlayView: function()
26239 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26243 _this.fireEvent('OverlayViewDraw', _this);
26248 _this.fireEvent('OverlayViewOnAdd', _this);
26251 onRemove: function()
26253 _this.fireEvent('OverlayViewOnRemove', _this);
26256 show: function(cpx)
26258 _this.fireEvent('OverlayViewShow', _this, cpx);
26263 _this.fireEvent('OverlayViewHide', _this);
26269 fromLatLngToContainerPixel: function(event)
26271 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26274 isApplied: function()
26276 return this.getGmapContext() == false ? false : true;
26279 getGmapContext: function()
26281 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26284 GMapContext: function()
26286 var position = new google.maps.LatLng(this.latitude, this.longitude);
26288 var _map = new google.maps.Map(this.el.dom, {
26291 mapTypeId: this.mapTypeId,
26292 mapTypeControl: this.mapTypeControl,
26293 disableDoubleClickZoom: this.disableDoubleClickZoom,
26294 scrollwheel: this.scrollwheel,
26295 streetViewControl: this.streetViewControl,
26296 locationName: this.locationName,
26297 draggable: this.draggable,
26298 enableAutocomplete: this.enableAutocomplete,
26299 enableReverseGeocode: this.enableReverseGeocode
26302 var _marker = new google.maps.Marker({
26303 position: position,
26305 title: this.markerTitle,
26306 draggable: this.draggable
26313 location: position,
26314 radius: this.radius,
26315 locationName: this.locationName,
26316 addressComponents: {
26317 formatted_address: null,
26318 addressLine1: null,
26319 addressLine2: null,
26321 streetNumber: null,
26325 stateOrProvince: null
26328 domContainer: this.el.dom,
26329 geodecoder: new google.maps.Geocoder()
26333 drawCircle: function(center, radius, options)
26335 if (this.gMapContext.circle != null) {
26336 this.gMapContext.circle.setMap(null);
26340 options = Roo.apply({}, options, {
26341 strokeColor: "#0000FF",
26342 strokeOpacity: .35,
26344 fillColor: "#0000FF",
26348 options.map = this.gMapContext.map;
26349 options.radius = radius;
26350 options.center = center;
26351 this.gMapContext.circle = new google.maps.Circle(options);
26352 return this.gMapContext.circle;
26358 setPosition: function(location)
26360 this.gMapContext.location = location;
26361 this.gMapContext.marker.setPosition(location);
26362 this.gMapContext.map.panTo(location);
26363 this.drawCircle(location, this.gMapContext.radius, {});
26367 if (this.gMapContext.settings.enableReverseGeocode) {
26368 this.gMapContext.geodecoder.geocode({
26369 latLng: this.gMapContext.location
26370 }, function(results, status) {
26372 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26373 _this.gMapContext.locationName = results[0].formatted_address;
26374 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26376 _this.fireEvent('positionchanged', this, location);
26383 this.fireEvent('positionchanged', this, location);
26388 google.maps.event.trigger(this.gMapContext.map, "resize");
26390 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26392 this.fireEvent('resize', this);
26395 setPositionByLatLng: function(latitude, longitude)
26397 this.setPosition(new google.maps.LatLng(latitude, longitude));
26400 getCurrentPosition: function()
26403 latitude: this.gMapContext.location.lat(),
26404 longitude: this.gMapContext.location.lng()
26408 getAddressName: function()
26410 return this.gMapContext.locationName;
26413 getAddressComponents: function()
26415 return this.gMapContext.addressComponents;
26418 address_component_from_google_geocode: function(address_components)
26422 for (var i = 0; i < address_components.length; i++) {
26423 var component = address_components[i];
26424 if (component.types.indexOf("postal_code") >= 0) {
26425 result.postalCode = component.short_name;
26426 } else if (component.types.indexOf("street_number") >= 0) {
26427 result.streetNumber = component.short_name;
26428 } else if (component.types.indexOf("route") >= 0) {
26429 result.streetName = component.short_name;
26430 } else if (component.types.indexOf("neighborhood") >= 0) {
26431 result.city = component.short_name;
26432 } else if (component.types.indexOf("locality") >= 0) {
26433 result.city = component.short_name;
26434 } else if (component.types.indexOf("sublocality") >= 0) {
26435 result.district = component.short_name;
26436 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26437 result.stateOrProvince = component.short_name;
26438 } else if (component.types.indexOf("country") >= 0) {
26439 result.country = component.short_name;
26443 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26444 result.addressLine2 = "";
26448 setZoomLevel: function(zoom)
26450 this.gMapContext.map.setZoom(zoom);
26463 this.fireEvent('show', this);
26474 this.fireEvent('hide', this);
26479 Roo.apply(Roo.bootstrap.LocationPicker, {
26481 OverlayView : function(map, options)
26483 options = options || {};
26497 * @class Roo.bootstrap.Alert
26498 * @extends Roo.bootstrap.Component
26499 * Bootstrap Alert class
26500 * @cfg {String} title The title of alert
26501 * @cfg {String} html The content of alert
26502 * @cfg {String} weight ( success | info | warning | danger )
26503 * @cfg {String} faicon font-awesomeicon
26506 * Create a new alert
26507 * @param {Object} config The config object
26511 Roo.bootstrap.Alert = function(config){
26512 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26516 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26523 getAutoCreate : function()
26532 cls : 'roo-alert-icon'
26537 cls : 'roo-alert-title',
26542 cls : 'roo-alert-text',
26549 cfg.cn[0].cls += ' fa ' + this.faicon;
26553 cfg.cls += ' alert-' + this.weight;
26559 initEvents: function()
26561 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26564 setTitle : function(str)
26566 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26569 setText : function(str)
26571 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26574 setWeight : function(weight)
26577 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26580 this.weight = weight;
26582 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26585 setIcon : function(icon)
26588 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26591 this.faicon = icon;
26593 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26614 * @class Roo.bootstrap.UploadCropbox
26615 * @extends Roo.bootstrap.Component
26616 * Bootstrap UploadCropbox class
26617 * @cfg {String} emptyText show when image has been loaded
26618 * @cfg {String} rotateNotify show when image too small to rotate
26619 * @cfg {Number} errorTimeout default 3000
26620 * @cfg {Number} minWidth default 300
26621 * @cfg {Number} minHeight default 300
26622 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26623 * @cfg {Boolean} isDocument (true|false) default false
26624 * @cfg {String} url action url
26625 * @cfg {String} paramName default 'imageUpload'
26626 * @cfg {String} method default POST
26627 * @cfg {Boolean} loadMask (true|false) default true
26628 * @cfg {Boolean} loadingText default 'Loading...'
26631 * Create a new UploadCropbox
26632 * @param {Object} config The config object
26635 Roo.bootstrap.UploadCropbox = function(config){
26636 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26640 * @event beforeselectfile
26641 * Fire before select file
26642 * @param {Roo.bootstrap.UploadCropbox} this
26644 "beforeselectfile" : true,
26647 * Fire after initEvent
26648 * @param {Roo.bootstrap.UploadCropbox} this
26653 * Fire after initEvent
26654 * @param {Roo.bootstrap.UploadCropbox} this
26655 * @param {String} data
26660 * Fire when preparing the file data
26661 * @param {Roo.bootstrap.UploadCropbox} this
26662 * @param {Object} file
26667 * Fire when get exception
26668 * @param {Roo.bootstrap.UploadCropbox} this
26669 * @param {XMLHttpRequest} xhr
26671 "exception" : true,
26673 * @event beforeloadcanvas
26674 * Fire before load the canvas
26675 * @param {Roo.bootstrap.UploadCropbox} this
26676 * @param {String} src
26678 "beforeloadcanvas" : true,
26681 * Fire when trash image
26682 * @param {Roo.bootstrap.UploadCropbox} this
26687 * Fire when download the image
26688 * @param {Roo.bootstrap.UploadCropbox} this
26692 * @event footerbuttonclick
26693 * Fire when footerbuttonclick
26694 * @param {Roo.bootstrap.UploadCropbox} this
26695 * @param {String} type
26697 "footerbuttonclick" : true,
26701 * @param {Roo.bootstrap.UploadCropbox} this
26706 * Fire when rotate the image
26707 * @param {Roo.bootstrap.UploadCropbox} this
26708 * @param {String} pos
26713 * Fire when inspect the file
26714 * @param {Roo.bootstrap.UploadCropbox} this
26715 * @param {Object} file
26720 * Fire when xhr upload the file
26721 * @param {Roo.bootstrap.UploadCropbox} this
26722 * @param {Object} data
26727 * Fire when arrange the file data
26728 * @param {Roo.bootstrap.UploadCropbox} this
26729 * @param {Object} formData
26734 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26737 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26739 emptyText : 'Click to upload image',
26740 rotateNotify : 'Image is too small to rotate',
26741 errorTimeout : 3000,
26755 cropType : 'image/jpeg',
26757 canvasLoaded : false,
26758 isDocument : false,
26760 paramName : 'imageUpload',
26762 loadingText : 'Loading...',
26765 getAutoCreate : function()
26769 cls : 'roo-upload-cropbox',
26773 cls : 'roo-upload-cropbox-selector',
26778 cls : 'roo-upload-cropbox-body',
26779 style : 'cursor:pointer',
26783 cls : 'roo-upload-cropbox-preview'
26787 cls : 'roo-upload-cropbox-thumb'
26791 cls : 'roo-upload-cropbox-empty-notify',
26792 html : this.emptyText
26796 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26797 html : this.rotateNotify
26803 cls : 'roo-upload-cropbox-footer',
26806 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26816 onRender : function(ct, position)
26818 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26820 if (this.buttons.length) {
26822 Roo.each(this.buttons, function(bb) {
26824 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26826 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26832 this.maskEl = this.el;
26836 initEvents : function()
26838 this.urlAPI = (window.createObjectURL && window) ||
26839 (window.URL && URL.revokeObjectURL && URL) ||
26840 (window.webkitURL && webkitURL);
26842 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26843 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26845 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26846 this.selectorEl.hide();
26848 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26849 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26851 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26852 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26853 this.thumbEl.hide();
26855 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26856 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26858 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26859 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26860 this.errorEl.hide();
26862 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26863 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26864 this.footerEl.hide();
26866 this.setThumbBoxSize();
26872 this.fireEvent('initial', this);
26879 window.addEventListener("resize", function() { _this.resize(); } );
26881 this.bodyEl.on('click', this.beforeSelectFile, this);
26884 this.bodyEl.on('touchstart', this.onTouchStart, this);
26885 this.bodyEl.on('touchmove', this.onTouchMove, this);
26886 this.bodyEl.on('touchend', this.onTouchEnd, this);
26890 this.bodyEl.on('mousedown', this.onMouseDown, this);
26891 this.bodyEl.on('mousemove', this.onMouseMove, this);
26892 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26893 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26894 Roo.get(document).on('mouseup', this.onMouseUp, this);
26897 this.selectorEl.on('change', this.onFileSelected, this);
26903 this.baseScale = 1;
26905 this.baseRotate = 1;
26906 this.dragable = false;
26907 this.pinching = false;
26910 this.cropData = false;
26911 this.notifyEl.dom.innerHTML = this.emptyText;
26913 this.selectorEl.dom.value = '';
26917 resize : function()
26919 if(this.fireEvent('resize', this) != false){
26920 this.setThumbBoxPosition();
26921 this.setCanvasPosition();
26925 onFooterButtonClick : function(e, el, o, type)
26928 case 'rotate-left' :
26929 this.onRotateLeft(e);
26931 case 'rotate-right' :
26932 this.onRotateRight(e);
26935 this.beforeSelectFile(e);
26950 this.fireEvent('footerbuttonclick', this, type);
26953 beforeSelectFile : function(e)
26955 e.preventDefault();
26957 if(this.fireEvent('beforeselectfile', this) != false){
26958 this.selectorEl.dom.click();
26962 onFileSelected : function(e)
26964 e.preventDefault();
26966 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26970 var file = this.selectorEl.dom.files[0];
26972 if(this.fireEvent('inspect', this, file) != false){
26973 this.prepare(file);
26978 trash : function(e)
26980 this.fireEvent('trash', this);
26983 download : function(e)
26985 this.fireEvent('download', this);
26988 loadCanvas : function(src)
26990 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26994 this.imageEl = document.createElement('img');
26998 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27000 this.imageEl.src = src;
27004 onLoadCanvas : function()
27006 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27007 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27009 this.bodyEl.un('click', this.beforeSelectFile, this);
27011 this.notifyEl.hide();
27012 this.thumbEl.show();
27013 this.footerEl.show();
27015 this.baseRotateLevel();
27017 if(this.isDocument){
27018 this.setThumbBoxSize();
27021 this.setThumbBoxPosition();
27023 this.baseScaleLevel();
27029 this.canvasLoaded = true;
27032 this.maskEl.unmask();
27037 setCanvasPosition : function()
27039 if(!this.canvasEl){
27043 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27044 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27046 this.previewEl.setLeft(pw);
27047 this.previewEl.setTop(ph);
27051 onMouseDown : function(e)
27055 this.dragable = true;
27056 this.pinching = false;
27058 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27059 this.dragable = false;
27063 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27064 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27068 onMouseMove : function(e)
27072 if(!this.canvasLoaded){
27076 if (!this.dragable){
27080 var minX = Math.ceil(this.thumbEl.getLeft(true));
27081 var minY = Math.ceil(this.thumbEl.getTop(true));
27083 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27084 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27086 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27087 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27089 x = x - this.mouseX;
27090 y = y - this.mouseY;
27092 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27093 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27095 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27096 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27098 this.previewEl.setLeft(bgX);
27099 this.previewEl.setTop(bgY);
27101 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27102 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27105 onMouseUp : function(e)
27109 this.dragable = false;
27112 onMouseWheel : function(e)
27116 this.startScale = this.scale;
27118 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27120 if(!this.zoomable()){
27121 this.scale = this.startScale;
27130 zoomable : function()
27132 var minScale = this.thumbEl.getWidth() / this.minWidth;
27134 if(this.minWidth < this.minHeight){
27135 minScale = this.thumbEl.getHeight() / this.minHeight;
27138 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27139 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27143 (this.rotate == 0 || this.rotate == 180) &&
27145 width > this.imageEl.OriginWidth ||
27146 height > this.imageEl.OriginHeight ||
27147 (width < this.minWidth && height < this.minHeight)
27155 (this.rotate == 90 || this.rotate == 270) &&
27157 width > this.imageEl.OriginWidth ||
27158 height > this.imageEl.OriginHeight ||
27159 (width < this.minHeight && height < this.minWidth)
27166 !this.isDocument &&
27167 (this.rotate == 0 || this.rotate == 180) &&
27169 width < this.minWidth ||
27170 width > this.imageEl.OriginWidth ||
27171 height < this.minHeight ||
27172 height > this.imageEl.OriginHeight
27179 !this.isDocument &&
27180 (this.rotate == 90 || this.rotate == 270) &&
27182 width < this.minHeight ||
27183 width > this.imageEl.OriginWidth ||
27184 height < this.minWidth ||
27185 height > this.imageEl.OriginHeight
27195 onRotateLeft : function(e)
27197 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27199 var minScale = this.thumbEl.getWidth() / this.minWidth;
27201 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27202 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27204 this.startScale = this.scale;
27206 while (this.getScaleLevel() < minScale){
27208 this.scale = this.scale + 1;
27210 if(!this.zoomable()){
27215 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27216 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27221 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27228 this.scale = this.startScale;
27230 this.onRotateFail();
27235 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27237 if(this.isDocument){
27238 this.setThumbBoxSize();
27239 this.setThumbBoxPosition();
27240 this.setCanvasPosition();
27245 this.fireEvent('rotate', this, 'left');
27249 onRotateRight : function(e)
27251 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27253 var minScale = this.thumbEl.getWidth() / this.minWidth;
27255 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27256 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27258 this.startScale = this.scale;
27260 while (this.getScaleLevel() < minScale){
27262 this.scale = this.scale + 1;
27264 if(!this.zoomable()){
27269 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27270 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27275 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27282 this.scale = this.startScale;
27284 this.onRotateFail();
27289 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27291 if(this.isDocument){
27292 this.setThumbBoxSize();
27293 this.setThumbBoxPosition();
27294 this.setCanvasPosition();
27299 this.fireEvent('rotate', this, 'right');
27302 onRotateFail : function()
27304 this.errorEl.show(true);
27308 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27313 this.previewEl.dom.innerHTML = '';
27315 var canvasEl = document.createElement("canvas");
27317 var contextEl = canvasEl.getContext("2d");
27319 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27320 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27321 var center = this.imageEl.OriginWidth / 2;
27323 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27324 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27325 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27326 center = this.imageEl.OriginHeight / 2;
27329 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27331 contextEl.translate(center, center);
27332 contextEl.rotate(this.rotate * Math.PI / 180);
27334 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27336 this.canvasEl = document.createElement("canvas");
27338 this.contextEl = this.canvasEl.getContext("2d");
27340 switch (this.rotate) {
27343 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27344 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27346 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27351 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27352 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27354 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27355 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);
27359 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27364 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27365 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27367 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27368 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);
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);
27377 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27378 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27380 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27381 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
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);
27392 this.previewEl.appendChild(this.canvasEl);
27394 this.setCanvasPosition();
27399 if(!this.canvasLoaded){
27403 var imageCanvas = document.createElement("canvas");
27405 var imageContext = imageCanvas.getContext("2d");
27407 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27408 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27410 var center = imageCanvas.width / 2;
27412 imageContext.translate(center, center);
27414 imageContext.rotate(this.rotate * Math.PI / 180);
27416 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27418 var canvas = document.createElement("canvas");
27420 var context = canvas.getContext("2d");
27422 canvas.width = this.minWidth;
27423 canvas.height = this.minHeight;
27425 switch (this.rotate) {
27428 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27429 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27431 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27432 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27434 var targetWidth = this.minWidth - 2 * x;
27435 var targetHeight = this.minHeight - 2 * y;
27439 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27440 scale = targetWidth / width;
27443 if(x > 0 && y == 0){
27444 scale = targetHeight / height;
27447 if(x > 0 && y > 0){
27448 scale = targetWidth / width;
27450 if(width < height){
27451 scale = targetHeight / height;
27455 context.scale(scale, scale);
27457 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27458 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27460 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27461 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27463 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27468 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27469 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27471 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27472 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27474 var targetWidth = this.minWidth - 2 * x;
27475 var targetHeight = this.minHeight - 2 * y;
27479 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27480 scale = targetWidth / width;
27483 if(x > 0 && y == 0){
27484 scale = targetHeight / height;
27487 if(x > 0 && y > 0){
27488 scale = targetWidth / width;
27490 if(width < height){
27491 scale = targetHeight / height;
27495 context.scale(scale, scale);
27497 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27498 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27500 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27501 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27503 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27505 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27510 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27511 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27513 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27514 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27516 var targetWidth = this.minWidth - 2 * x;
27517 var targetHeight = this.minHeight - 2 * y;
27521 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27522 scale = targetWidth / width;
27525 if(x > 0 && y == 0){
27526 scale = targetHeight / height;
27529 if(x > 0 && y > 0){
27530 scale = targetWidth / width;
27532 if(width < height){
27533 scale = targetHeight / height;
27537 context.scale(scale, scale);
27539 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27540 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27542 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27543 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27545 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27546 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27548 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27553 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27554 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27556 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27557 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27559 var targetWidth = this.minWidth - 2 * x;
27560 var targetHeight = this.minHeight - 2 * y;
27564 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27565 scale = targetWidth / width;
27568 if(x > 0 && y == 0){
27569 scale = targetHeight / height;
27572 if(x > 0 && y > 0){
27573 scale = targetWidth / width;
27575 if(width < height){
27576 scale = targetHeight / height;
27580 context.scale(scale, scale);
27582 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27583 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27585 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27586 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27588 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27590 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27597 this.cropData = canvas.toDataURL(this.cropType);
27599 if(this.fireEvent('crop', this, this.cropData) !== false){
27600 this.process(this.file, this.cropData);
27607 setThumbBoxSize : function()
27611 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27612 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27613 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27615 this.minWidth = width;
27616 this.minHeight = height;
27618 if(this.rotate == 90 || this.rotate == 270){
27619 this.minWidth = height;
27620 this.minHeight = width;
27625 width = Math.ceil(this.minWidth * height / this.minHeight);
27627 if(this.minWidth > this.minHeight){
27629 height = Math.ceil(this.minHeight * width / this.minWidth);
27632 this.thumbEl.setStyle({
27633 width : width + 'px',
27634 height : height + 'px'
27641 setThumbBoxPosition : function()
27643 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27644 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27646 this.thumbEl.setLeft(x);
27647 this.thumbEl.setTop(y);
27651 baseRotateLevel : function()
27653 this.baseRotate = 1;
27656 typeof(this.exif) != 'undefined' &&
27657 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27658 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27660 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27663 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27667 baseScaleLevel : function()
27671 if(this.isDocument){
27673 if(this.baseRotate == 6 || this.baseRotate == 8){
27675 height = this.thumbEl.getHeight();
27676 this.baseScale = height / this.imageEl.OriginWidth;
27678 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27679 width = this.thumbEl.getWidth();
27680 this.baseScale = width / this.imageEl.OriginHeight;
27686 height = this.thumbEl.getHeight();
27687 this.baseScale = height / this.imageEl.OriginHeight;
27689 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27690 width = this.thumbEl.getWidth();
27691 this.baseScale = width / this.imageEl.OriginWidth;
27697 if(this.baseRotate == 6 || this.baseRotate == 8){
27699 width = this.thumbEl.getHeight();
27700 this.baseScale = width / this.imageEl.OriginHeight;
27702 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27703 height = this.thumbEl.getWidth();
27704 this.baseScale = height / this.imageEl.OriginHeight;
27707 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27708 height = this.thumbEl.getWidth();
27709 this.baseScale = height / this.imageEl.OriginHeight;
27711 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27712 width = this.thumbEl.getHeight();
27713 this.baseScale = width / this.imageEl.OriginWidth;
27720 width = this.thumbEl.getWidth();
27721 this.baseScale = width / this.imageEl.OriginWidth;
27723 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27724 height = this.thumbEl.getHeight();
27725 this.baseScale = height / this.imageEl.OriginHeight;
27728 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27730 height = this.thumbEl.getHeight();
27731 this.baseScale = height / this.imageEl.OriginHeight;
27733 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27734 width = this.thumbEl.getWidth();
27735 this.baseScale = width / this.imageEl.OriginWidth;
27743 getScaleLevel : function()
27745 return this.baseScale * Math.pow(1.1, this.scale);
27748 onTouchStart : function(e)
27750 if(!this.canvasLoaded){
27751 this.beforeSelectFile(e);
27755 var touches = e.browserEvent.touches;
27761 if(touches.length == 1){
27762 this.onMouseDown(e);
27766 if(touches.length != 2){
27772 for(var i = 0, finger; finger = touches[i]; i++){
27773 coords.push(finger.pageX, finger.pageY);
27776 var x = Math.pow(coords[0] - coords[2], 2);
27777 var y = Math.pow(coords[1] - coords[3], 2);
27779 this.startDistance = Math.sqrt(x + y);
27781 this.startScale = this.scale;
27783 this.pinching = true;
27784 this.dragable = false;
27788 onTouchMove : function(e)
27790 if(!this.pinching && !this.dragable){
27794 var touches = e.browserEvent.touches;
27801 this.onMouseMove(e);
27807 for(var i = 0, finger; finger = touches[i]; i++){
27808 coords.push(finger.pageX, finger.pageY);
27811 var x = Math.pow(coords[0] - coords[2], 2);
27812 var y = Math.pow(coords[1] - coords[3], 2);
27814 this.endDistance = Math.sqrt(x + y);
27816 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27818 if(!this.zoomable()){
27819 this.scale = this.startScale;
27827 onTouchEnd : function(e)
27829 this.pinching = false;
27830 this.dragable = false;
27834 process : function(file, crop)
27837 this.maskEl.mask(this.loadingText);
27840 this.xhr = new XMLHttpRequest();
27842 file.xhr = this.xhr;
27844 this.xhr.open(this.method, this.url, true);
27847 "Accept": "application/json",
27848 "Cache-Control": "no-cache",
27849 "X-Requested-With": "XMLHttpRequest"
27852 for (var headerName in headers) {
27853 var headerValue = headers[headerName];
27855 this.xhr.setRequestHeader(headerName, headerValue);
27861 this.xhr.onload = function()
27863 _this.xhrOnLoad(_this.xhr);
27866 this.xhr.onerror = function()
27868 _this.xhrOnError(_this.xhr);
27871 var formData = new FormData();
27873 formData.append('returnHTML', 'NO');
27876 formData.append('crop', crop);
27879 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27880 formData.append(this.paramName, file, file.name);
27883 if(typeof(file.filename) != 'undefined'){
27884 formData.append('filename', file.filename);
27887 if(typeof(file.mimetype) != 'undefined'){
27888 formData.append('mimetype', file.mimetype);
27891 if(this.fireEvent('arrange', this, formData) != false){
27892 this.xhr.send(formData);
27896 xhrOnLoad : function(xhr)
27899 this.maskEl.unmask();
27902 if (xhr.readyState !== 4) {
27903 this.fireEvent('exception', this, xhr);
27907 var response = Roo.decode(xhr.responseText);
27909 if(!response.success){
27910 this.fireEvent('exception', this, xhr);
27914 var response = Roo.decode(xhr.responseText);
27916 this.fireEvent('upload', this, response);
27920 xhrOnError : function()
27923 this.maskEl.unmask();
27926 Roo.log('xhr on error');
27928 var response = Roo.decode(xhr.responseText);
27934 prepare : function(file)
27937 this.maskEl.mask(this.loadingText);
27943 if(typeof(file) === 'string'){
27944 this.loadCanvas(file);
27948 if(!file || !this.urlAPI){
27953 this.cropType = file.type;
27957 if(this.fireEvent('prepare', this, this.file) != false){
27959 var reader = new FileReader();
27961 reader.onload = function (e) {
27962 if (e.target.error) {
27963 Roo.log(e.target.error);
27967 var buffer = e.target.result,
27968 dataView = new DataView(buffer),
27970 maxOffset = dataView.byteLength - 4,
27974 if (dataView.getUint16(0) === 0xffd8) {
27975 while (offset < maxOffset) {
27976 markerBytes = dataView.getUint16(offset);
27978 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27979 markerLength = dataView.getUint16(offset + 2) + 2;
27980 if (offset + markerLength > dataView.byteLength) {
27981 Roo.log('Invalid meta data: Invalid segment size.');
27985 if(markerBytes == 0xffe1){
27986 _this.parseExifData(
27993 offset += markerLength;
28003 var url = _this.urlAPI.createObjectURL(_this.file);
28005 _this.loadCanvas(url);
28010 reader.readAsArrayBuffer(this.file);
28016 parseExifData : function(dataView, offset, length)
28018 var tiffOffset = offset + 10,
28022 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28023 // No Exif data, might be XMP data instead
28027 // Check for the ASCII code for "Exif" (0x45786966):
28028 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28029 // No Exif data, might be XMP data instead
28032 if (tiffOffset + 8 > dataView.byteLength) {
28033 Roo.log('Invalid Exif data: Invalid segment size.');
28036 // Check for the two null bytes:
28037 if (dataView.getUint16(offset + 8) !== 0x0000) {
28038 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28041 // Check the byte alignment:
28042 switch (dataView.getUint16(tiffOffset)) {
28044 littleEndian = true;
28047 littleEndian = false;
28050 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28053 // Check for the TIFF tag marker (0x002A):
28054 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28055 Roo.log('Invalid Exif data: Missing TIFF marker.');
28058 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28059 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28061 this.parseExifTags(
28064 tiffOffset + dirOffset,
28069 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28074 if (dirOffset + 6 > dataView.byteLength) {
28075 Roo.log('Invalid Exif data: Invalid directory offset.');
28078 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28079 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28080 if (dirEndOffset + 4 > dataView.byteLength) {
28081 Roo.log('Invalid Exif data: Invalid directory size.');
28084 for (i = 0; i < tagsNumber; i += 1) {
28088 dirOffset + 2 + 12 * i, // tag offset
28092 // Return the offset to the next directory:
28093 return dataView.getUint32(dirEndOffset, littleEndian);
28096 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28098 var tag = dataView.getUint16(offset, littleEndian);
28100 this.exif[tag] = this.getExifValue(
28104 dataView.getUint16(offset + 2, littleEndian), // tag type
28105 dataView.getUint32(offset + 4, littleEndian), // tag length
28110 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28112 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28121 Roo.log('Invalid Exif data: Invalid tag type.');
28125 tagSize = tagType.size * length;
28126 // Determine if the value is contained in the dataOffset bytes,
28127 // or if the value at the dataOffset is a pointer to the actual data:
28128 dataOffset = tagSize > 4 ?
28129 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28130 if (dataOffset + tagSize > dataView.byteLength) {
28131 Roo.log('Invalid Exif data: Invalid data offset.');
28134 if (length === 1) {
28135 return tagType.getValue(dataView, dataOffset, littleEndian);
28138 for (i = 0; i < length; i += 1) {
28139 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28142 if (tagType.ascii) {
28144 // Concatenate the chars:
28145 for (i = 0; i < values.length; i += 1) {
28147 // Ignore the terminating NULL byte(s):
28148 if (c === '\u0000') {
28160 Roo.apply(Roo.bootstrap.UploadCropbox, {
28162 'Orientation': 0x0112
28166 1: 0, //'top-left',
28168 3: 180, //'bottom-right',
28169 // 4: 'bottom-left',
28171 6: 90, //'right-top',
28172 // 7: 'right-bottom',
28173 8: 270 //'left-bottom'
28177 // byte, 8-bit unsigned int:
28179 getValue: function (dataView, dataOffset) {
28180 return dataView.getUint8(dataOffset);
28184 // ascii, 8-bit byte:
28186 getValue: function (dataView, dataOffset) {
28187 return String.fromCharCode(dataView.getUint8(dataOffset));
28192 // short, 16 bit int:
28194 getValue: function (dataView, dataOffset, littleEndian) {
28195 return dataView.getUint16(dataOffset, littleEndian);
28199 // long, 32 bit int:
28201 getValue: function (dataView, dataOffset, littleEndian) {
28202 return dataView.getUint32(dataOffset, littleEndian);
28206 // rational = two long values, first is numerator, second is denominator:
28208 getValue: function (dataView, dataOffset, littleEndian) {
28209 return dataView.getUint32(dataOffset, littleEndian) /
28210 dataView.getUint32(dataOffset + 4, littleEndian);
28214 // slong, 32 bit signed int:
28216 getValue: function (dataView, dataOffset, littleEndian) {
28217 return dataView.getInt32(dataOffset, littleEndian);
28221 // srational, two slongs, first is numerator, second is denominator:
28223 getValue: function (dataView, dataOffset, littleEndian) {
28224 return dataView.getInt32(dataOffset, littleEndian) /
28225 dataView.getInt32(dataOffset + 4, littleEndian);
28235 cls : 'btn-group roo-upload-cropbox-rotate-left',
28236 action : 'rotate-left',
28240 cls : 'btn btn-default',
28241 html : '<i class="fa fa-undo"></i>'
28247 cls : 'btn-group roo-upload-cropbox-picture',
28248 action : 'picture',
28252 cls : 'btn btn-default',
28253 html : '<i class="fa fa-picture-o"></i>'
28259 cls : 'btn-group roo-upload-cropbox-rotate-right',
28260 action : 'rotate-right',
28264 cls : 'btn btn-default',
28265 html : '<i class="fa fa-repeat"></i>'
28273 cls : 'btn-group roo-upload-cropbox-rotate-left',
28274 action : 'rotate-left',
28278 cls : 'btn btn-default',
28279 html : '<i class="fa fa-undo"></i>'
28285 cls : 'btn-group roo-upload-cropbox-download',
28286 action : 'download',
28290 cls : 'btn btn-default',
28291 html : '<i class="fa fa-download"></i>'
28297 cls : 'btn-group roo-upload-cropbox-crop',
28302 cls : 'btn btn-default',
28303 html : '<i class="fa fa-crop"></i>'
28309 cls : 'btn-group roo-upload-cropbox-trash',
28314 cls : 'btn btn-default',
28315 html : '<i class="fa fa-trash"></i>'
28321 cls : 'btn-group roo-upload-cropbox-rotate-right',
28322 action : 'rotate-right',
28326 cls : 'btn btn-default',
28327 html : '<i class="fa fa-repeat"></i>'
28335 cls : 'btn-group roo-upload-cropbox-rotate-left',
28336 action : 'rotate-left',
28340 cls : 'btn btn-default',
28341 html : '<i class="fa fa-undo"></i>'
28347 cls : 'btn-group roo-upload-cropbox-rotate-right',
28348 action : 'rotate-right',
28352 cls : 'btn btn-default',
28353 html : '<i class="fa fa-repeat"></i>'
28366 * @class Roo.bootstrap.DocumentManager
28367 * @extends Roo.bootstrap.Component
28368 * Bootstrap DocumentManager class
28369 * @cfg {String} paramName default 'imageUpload'
28370 * @cfg {String} toolTipName default 'filename'
28371 * @cfg {String} method default POST
28372 * @cfg {String} url action url
28373 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28374 * @cfg {Boolean} multiple multiple upload default true
28375 * @cfg {Number} thumbSize default 300
28376 * @cfg {String} fieldLabel
28377 * @cfg {Number} labelWidth default 4
28378 * @cfg {String} labelAlign (left|top) default left
28379 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28380 * @cfg {Number} labellg set the width of label (1-12)
28381 * @cfg {Number} labelmd set the width of label (1-12)
28382 * @cfg {Number} labelsm set the width of label (1-12)
28383 * @cfg {Number} labelxs set the width of label (1-12)
28386 * Create a new DocumentManager
28387 * @param {Object} config The config object
28390 Roo.bootstrap.DocumentManager = function(config){
28391 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28394 this.delegates = [];
28399 * Fire when initial the DocumentManager
28400 * @param {Roo.bootstrap.DocumentManager} this
28405 * inspect selected file
28406 * @param {Roo.bootstrap.DocumentManager} this
28407 * @param {File} file
28412 * Fire when xhr load exception
28413 * @param {Roo.bootstrap.DocumentManager} this
28414 * @param {XMLHttpRequest} xhr
28416 "exception" : true,
28418 * @event afterupload
28419 * Fire when xhr load exception
28420 * @param {Roo.bootstrap.DocumentManager} this
28421 * @param {XMLHttpRequest} xhr
28423 "afterupload" : true,
28426 * prepare the form data
28427 * @param {Roo.bootstrap.DocumentManager} this
28428 * @param {Object} formData
28433 * Fire when remove the file
28434 * @param {Roo.bootstrap.DocumentManager} this
28435 * @param {Object} file
28440 * Fire after refresh the file
28441 * @param {Roo.bootstrap.DocumentManager} this
28446 * Fire after click the image
28447 * @param {Roo.bootstrap.DocumentManager} this
28448 * @param {Object} file
28453 * Fire when upload a image and editable set to true
28454 * @param {Roo.bootstrap.DocumentManager} this
28455 * @param {Object} file
28459 * @event beforeselectfile
28460 * Fire before select file
28461 * @param {Roo.bootstrap.DocumentManager} this
28463 "beforeselectfile" : true,
28466 * Fire before process file
28467 * @param {Roo.bootstrap.DocumentManager} this
28468 * @param {Object} file
28472 * @event previewrendered
28473 * Fire when preview rendered
28474 * @param {Roo.bootstrap.DocumentManager} this
28475 * @param {Object} file
28477 "previewrendered" : true
28482 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28491 paramName : 'imageUpload',
28492 toolTipName : 'filename',
28495 labelAlign : 'left',
28505 getAutoCreate : function()
28507 var managerWidget = {
28509 cls : 'roo-document-manager',
28513 cls : 'roo-document-manager-selector',
28518 cls : 'roo-document-manager-uploader',
28522 cls : 'roo-document-manager-upload-btn',
28523 html : '<i class="fa fa-plus"></i>'
28534 cls : 'column col-md-12',
28539 if(this.fieldLabel.length){
28544 cls : 'column col-md-12',
28545 html : this.fieldLabel
28549 cls : 'column col-md-12',
28554 if(this.labelAlign == 'left'){
28559 html : this.fieldLabel
28568 if(this.labelWidth > 12){
28569 content[0].style = "width: " + this.labelWidth + 'px';
28572 if(this.labelWidth < 13 && this.labelmd == 0){
28573 this.labelmd = this.labelWidth;
28576 if(this.labellg > 0){
28577 content[0].cls += ' col-lg-' + this.labellg;
28578 content[1].cls += ' col-lg-' + (12 - this.labellg);
28581 if(this.labelmd > 0){
28582 content[0].cls += ' col-md-' + this.labelmd;
28583 content[1].cls += ' col-md-' + (12 - this.labelmd);
28586 if(this.labelsm > 0){
28587 content[0].cls += ' col-sm-' + this.labelsm;
28588 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28591 if(this.labelxs > 0){
28592 content[0].cls += ' col-xs-' + this.labelxs;
28593 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28601 cls : 'row clearfix',
28609 initEvents : function()
28611 this.managerEl = this.el.select('.roo-document-manager', true).first();
28612 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28614 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28615 this.selectorEl.hide();
28618 this.selectorEl.attr('multiple', 'multiple');
28621 this.selectorEl.on('change', this.onFileSelected, this);
28623 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28624 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28626 this.uploader.on('click', this.onUploaderClick, this);
28628 this.renderProgressDialog();
28632 window.addEventListener("resize", function() { _this.refresh(); } );
28634 this.fireEvent('initial', this);
28637 renderProgressDialog : function()
28641 this.progressDialog = new Roo.bootstrap.Modal({
28642 cls : 'roo-document-manager-progress-dialog',
28643 allow_close : false,
28653 btnclick : function() {
28654 _this.uploadCancel();
28660 this.progressDialog.render(Roo.get(document.body));
28662 this.progress = new Roo.bootstrap.Progress({
28663 cls : 'roo-document-manager-progress',
28668 this.progress.render(this.progressDialog.getChildContainer());
28670 this.progressBar = new Roo.bootstrap.ProgressBar({
28671 cls : 'roo-document-manager-progress-bar',
28674 aria_valuemax : 12,
28678 this.progressBar.render(this.progress.getChildContainer());
28681 onUploaderClick : function(e)
28683 e.preventDefault();
28685 if(this.fireEvent('beforeselectfile', this) != false){
28686 this.selectorEl.dom.click();
28691 onFileSelected : function(e)
28693 e.preventDefault();
28695 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28699 Roo.each(this.selectorEl.dom.files, function(file){
28700 if(this.fireEvent('inspect', this, file) != false){
28701 this.files.push(file);
28711 this.selectorEl.dom.value = '';
28713 if(!this.files || !this.files.length){
28717 if(this.boxes > 0 && this.files.length > this.boxes){
28718 this.files = this.files.slice(0, this.boxes);
28721 this.uploader.show();
28723 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28724 this.uploader.hide();
28733 Roo.each(this.files, function(file){
28735 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28736 var f = this.renderPreview(file);
28741 if(file.type.indexOf('image') != -1){
28742 this.delegates.push(
28744 _this.process(file);
28745 }).createDelegate(this)
28753 _this.process(file);
28754 }).createDelegate(this)
28759 this.files = files;
28761 this.delegates = this.delegates.concat(docs);
28763 if(!this.delegates.length){
28768 this.progressBar.aria_valuemax = this.delegates.length;
28775 arrange : function()
28777 if(!this.delegates.length){
28778 this.progressDialog.hide();
28783 var delegate = this.delegates.shift();
28785 this.progressDialog.show();
28787 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28789 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28794 refresh : function()
28796 this.uploader.show();
28798 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28799 this.uploader.hide();
28802 Roo.isTouch ? this.closable(false) : this.closable(true);
28804 this.fireEvent('refresh', this);
28807 onRemove : function(e, el, o)
28809 e.preventDefault();
28811 this.fireEvent('remove', this, o);
28815 remove : function(o)
28819 Roo.each(this.files, function(file){
28820 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28829 this.files = files;
28836 Roo.each(this.files, function(file){
28841 file.target.remove();
28850 onClick : function(e, el, o)
28852 e.preventDefault();
28854 this.fireEvent('click', this, o);
28858 closable : function(closable)
28860 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28862 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28874 xhrOnLoad : function(xhr)
28876 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28880 if (xhr.readyState !== 4) {
28882 this.fireEvent('exception', this, xhr);
28886 var response = Roo.decode(xhr.responseText);
28888 if(!response.success){
28890 this.fireEvent('exception', this, xhr);
28894 var file = this.renderPreview(response.data);
28896 this.files.push(file);
28900 this.fireEvent('afterupload', this, xhr);
28904 xhrOnError : function(xhr)
28906 Roo.log('xhr on error');
28908 var response = Roo.decode(xhr.responseText);
28915 process : function(file)
28917 if(this.fireEvent('process', this, file) !== false){
28918 if(this.editable && file.type.indexOf('image') != -1){
28919 this.fireEvent('edit', this, file);
28923 this.uploadStart(file, false);
28930 uploadStart : function(file, crop)
28932 this.xhr = new XMLHttpRequest();
28934 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28939 file.xhr = this.xhr;
28941 this.managerEl.createChild({
28943 cls : 'roo-document-manager-loading',
28947 tooltip : file.name,
28948 cls : 'roo-document-manager-thumb',
28949 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28955 this.xhr.open(this.method, this.url, true);
28958 "Accept": "application/json",
28959 "Cache-Control": "no-cache",
28960 "X-Requested-With": "XMLHttpRequest"
28963 for (var headerName in headers) {
28964 var headerValue = headers[headerName];
28966 this.xhr.setRequestHeader(headerName, headerValue);
28972 this.xhr.onload = function()
28974 _this.xhrOnLoad(_this.xhr);
28977 this.xhr.onerror = function()
28979 _this.xhrOnError(_this.xhr);
28982 var formData = new FormData();
28984 formData.append('returnHTML', 'NO');
28987 formData.append('crop', crop);
28990 formData.append(this.paramName, file, file.name);
28997 if(this.fireEvent('prepare', this, formData, options) != false){
28999 if(options.manually){
29003 this.xhr.send(formData);
29007 this.uploadCancel();
29010 uploadCancel : function()
29016 this.delegates = [];
29018 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29025 renderPreview : function(file)
29027 if(typeof(file.target) != 'undefined' && file.target){
29031 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29033 var previewEl = this.managerEl.createChild({
29035 cls : 'roo-document-manager-preview',
29039 tooltip : file[this.toolTipName],
29040 cls : 'roo-document-manager-thumb',
29041 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29046 html : '<i class="fa fa-times-circle"></i>'
29051 var close = previewEl.select('button.close', true).first();
29053 close.on('click', this.onRemove, this, file);
29055 file.target = previewEl;
29057 var image = previewEl.select('img', true).first();
29061 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29063 image.on('click', this.onClick, this, file);
29065 this.fireEvent('previewrendered', this, file);
29071 onPreviewLoad : function(file, image)
29073 if(typeof(file.target) == 'undefined' || !file.target){
29077 var width = image.dom.naturalWidth || image.dom.width;
29078 var height = image.dom.naturalHeight || image.dom.height;
29080 if(width > height){
29081 file.target.addClass('wide');
29085 file.target.addClass('tall');
29090 uploadFromSource : function(file, crop)
29092 this.xhr = new XMLHttpRequest();
29094 this.managerEl.createChild({
29096 cls : 'roo-document-manager-loading',
29100 tooltip : file.name,
29101 cls : 'roo-document-manager-thumb',
29102 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29108 this.xhr.open(this.method, this.url, true);
29111 "Accept": "application/json",
29112 "Cache-Control": "no-cache",
29113 "X-Requested-With": "XMLHttpRequest"
29116 for (var headerName in headers) {
29117 var headerValue = headers[headerName];
29119 this.xhr.setRequestHeader(headerName, headerValue);
29125 this.xhr.onload = function()
29127 _this.xhrOnLoad(_this.xhr);
29130 this.xhr.onerror = function()
29132 _this.xhrOnError(_this.xhr);
29135 var formData = new FormData();
29137 formData.append('returnHTML', 'NO');
29139 formData.append('crop', crop);
29141 if(typeof(file.filename) != 'undefined'){
29142 formData.append('filename', file.filename);
29145 if(typeof(file.mimetype) != 'undefined'){
29146 formData.append('mimetype', file.mimetype);
29151 if(this.fireEvent('prepare', this, formData) != false){
29152 this.xhr.send(formData);
29162 * @class Roo.bootstrap.DocumentViewer
29163 * @extends Roo.bootstrap.Component
29164 * Bootstrap DocumentViewer class
29165 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29166 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29169 * Create a new DocumentViewer
29170 * @param {Object} config The config object
29173 Roo.bootstrap.DocumentViewer = function(config){
29174 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29179 * Fire after initEvent
29180 * @param {Roo.bootstrap.DocumentViewer} this
29186 * @param {Roo.bootstrap.DocumentViewer} this
29191 * Fire after download button
29192 * @param {Roo.bootstrap.DocumentViewer} this
29197 * Fire after trash button
29198 * @param {Roo.bootstrap.DocumentViewer} this
29205 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29207 showDownload : true,
29211 getAutoCreate : function()
29215 cls : 'roo-document-viewer',
29219 cls : 'roo-document-viewer-body',
29223 cls : 'roo-document-viewer-thumb',
29227 cls : 'roo-document-viewer-image'
29235 cls : 'roo-document-viewer-footer',
29238 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29242 cls : 'btn-group roo-document-viewer-download',
29246 cls : 'btn btn-default',
29247 html : '<i class="fa fa-download"></i>'
29253 cls : 'btn-group roo-document-viewer-trash',
29257 cls : 'btn btn-default',
29258 html : '<i class="fa fa-trash"></i>'
29271 initEvents : function()
29273 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29274 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29276 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29277 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29279 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29280 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29282 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29283 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29285 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29286 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29288 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29289 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29291 this.bodyEl.on('click', this.onClick, this);
29292 this.downloadBtn.on('click', this.onDownload, this);
29293 this.trashBtn.on('click', this.onTrash, this);
29295 this.downloadBtn.hide();
29296 this.trashBtn.hide();
29298 if(this.showDownload){
29299 this.downloadBtn.show();
29302 if(this.showTrash){
29303 this.trashBtn.show();
29306 if(!this.showDownload && !this.showTrash) {
29307 this.footerEl.hide();
29312 initial : function()
29314 this.fireEvent('initial', this);
29318 onClick : function(e)
29320 e.preventDefault();
29322 this.fireEvent('click', this);
29325 onDownload : function(e)
29327 e.preventDefault();
29329 this.fireEvent('download', this);
29332 onTrash : function(e)
29334 e.preventDefault();
29336 this.fireEvent('trash', this);
29348 * @class Roo.bootstrap.NavProgressBar
29349 * @extends Roo.bootstrap.Component
29350 * Bootstrap NavProgressBar class
29353 * Create a new nav progress bar
29354 * @param {Object} config The config object
29357 Roo.bootstrap.NavProgressBar = function(config){
29358 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29360 this.bullets = this.bullets || [];
29362 // Roo.bootstrap.NavProgressBar.register(this);
29366 * Fires when the active item changes
29367 * @param {Roo.bootstrap.NavProgressBar} this
29368 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29369 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29376 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29381 getAutoCreate : function()
29383 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29387 cls : 'roo-navigation-bar-group',
29391 cls : 'roo-navigation-top-bar'
29395 cls : 'roo-navigation-bullets-bar',
29399 cls : 'roo-navigation-bar'
29406 cls : 'roo-navigation-bottom-bar'
29416 initEvents: function()
29421 onRender : function(ct, position)
29423 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29425 if(this.bullets.length){
29426 Roo.each(this.bullets, function(b){
29435 addItem : function(cfg)
29437 var item = new Roo.bootstrap.NavProgressItem(cfg);
29439 item.parentId = this.id;
29440 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29443 var top = new Roo.bootstrap.Element({
29445 cls : 'roo-navigation-bar-text'
29448 var bottom = new Roo.bootstrap.Element({
29450 cls : 'roo-navigation-bar-text'
29453 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29454 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29456 var topText = new Roo.bootstrap.Element({
29458 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29461 var bottomText = new Roo.bootstrap.Element({
29463 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29466 topText.onRender(top.el, null);
29467 bottomText.onRender(bottom.el, null);
29470 item.bottomEl = bottom;
29473 this.barItems.push(item);
29478 getActive : function()
29480 var active = false;
29482 Roo.each(this.barItems, function(v){
29484 if (!v.isActive()) {
29496 setActiveItem : function(item)
29500 Roo.each(this.barItems, function(v){
29501 if (v.rid == item.rid) {
29505 if (v.isActive()) {
29506 v.setActive(false);
29511 item.setActive(true);
29513 this.fireEvent('changed', this, item, prev);
29516 getBarItem: function(rid)
29520 Roo.each(this.barItems, function(e) {
29521 if (e.rid != rid) {
29532 indexOfItem : function(item)
29536 Roo.each(this.barItems, function(v, i){
29538 if (v.rid != item.rid) {
29549 setActiveNext : function()
29551 var i = this.indexOfItem(this.getActive());
29553 if (i > this.barItems.length) {
29557 this.setActiveItem(this.barItems[i+1]);
29560 setActivePrev : function()
29562 var i = this.indexOfItem(this.getActive());
29568 this.setActiveItem(this.barItems[i-1]);
29571 format : function()
29573 if(!this.barItems.length){
29577 var width = 100 / this.barItems.length;
29579 Roo.each(this.barItems, function(i){
29580 i.el.setStyle('width', width + '%');
29581 i.topEl.el.setStyle('width', width + '%');
29582 i.bottomEl.el.setStyle('width', width + '%');
29591 * Nav Progress Item
29596 * @class Roo.bootstrap.NavProgressItem
29597 * @extends Roo.bootstrap.Component
29598 * Bootstrap NavProgressItem class
29599 * @cfg {String} rid the reference id
29600 * @cfg {Boolean} active (true|false) Is item active default false
29601 * @cfg {Boolean} disabled (true|false) Is item active default false
29602 * @cfg {String} html
29603 * @cfg {String} position (top|bottom) text position default bottom
29604 * @cfg {String} icon show icon instead of number
29607 * Create a new NavProgressItem
29608 * @param {Object} config The config object
29610 Roo.bootstrap.NavProgressItem = function(config){
29611 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29616 * The raw click event for the entire grid.
29617 * @param {Roo.bootstrap.NavProgressItem} this
29618 * @param {Roo.EventObject} e
29625 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29631 position : 'bottom',
29634 getAutoCreate : function()
29636 var iconCls = 'roo-navigation-bar-item-icon';
29638 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29642 cls: 'roo-navigation-bar-item',
29652 cfg.cls += ' active';
29655 cfg.cls += ' disabled';
29661 disable : function()
29663 this.setDisabled(true);
29666 enable : function()
29668 this.setDisabled(false);
29671 initEvents: function()
29673 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29675 this.iconEl.on('click', this.onClick, this);
29678 onClick : function(e)
29680 e.preventDefault();
29686 if(this.fireEvent('click', this, e) === false){
29690 this.parent().setActiveItem(this);
29693 isActive: function ()
29695 return this.active;
29698 setActive : function(state)
29700 if(this.active == state){
29704 this.active = state;
29707 this.el.addClass('active');
29711 this.el.removeClass('active');
29716 setDisabled : function(state)
29718 if(this.disabled == state){
29722 this.disabled = state;
29725 this.el.addClass('disabled');
29729 this.el.removeClass('disabled');
29732 tooltipEl : function()
29734 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29747 * @class Roo.bootstrap.FieldLabel
29748 * @extends Roo.bootstrap.Component
29749 * Bootstrap FieldLabel class
29750 * @cfg {String} html contents of the element
29751 * @cfg {String} tag tag of the element default label
29752 * @cfg {String} cls class of the element
29753 * @cfg {String} target label target
29754 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29755 * @cfg {String} invalidClass default "text-warning"
29756 * @cfg {String} validClass default "text-success"
29757 * @cfg {String} iconTooltip default "This field is required"
29758 * @cfg {String} indicatorpos (left|right) default left
29761 * Create a new FieldLabel
29762 * @param {Object} config The config object
29765 Roo.bootstrap.FieldLabel = function(config){
29766 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29771 * Fires after the field has been marked as invalid.
29772 * @param {Roo.form.FieldLabel} this
29773 * @param {String} msg The validation message
29778 * Fires after the field has been validated with no errors.
29779 * @param {Roo.form.FieldLabel} this
29785 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29792 invalidClass : 'has-warning',
29793 validClass : 'has-success',
29794 iconTooltip : 'This field is required',
29795 indicatorpos : 'left',
29797 getAutoCreate : function(){
29801 cls : 'roo-bootstrap-field-label ' + this.cls,
29806 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29807 tooltip : this.iconTooltip
29816 if(this.indicatorpos == 'right'){
29819 cls : 'roo-bootstrap-field-label ' + this.cls,
29828 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29829 tooltip : this.iconTooltip
29838 initEvents: function()
29840 Roo.bootstrap.Element.superclass.initEvents.call(this);
29842 this.indicator = this.indicatorEl();
29844 if(this.indicator){
29845 this.indicator.removeClass('visible');
29846 this.indicator.addClass('invisible');
29849 Roo.bootstrap.FieldLabel.register(this);
29852 indicatorEl : function()
29854 var indicator = this.el.select('i.roo-required-indicator',true).first();
29865 * Mark this field as valid
29867 markValid : function()
29869 if(this.indicator){
29870 this.indicator.removeClass('visible');
29871 this.indicator.addClass('invisible');
29874 this.el.removeClass(this.invalidClass);
29876 this.el.addClass(this.validClass);
29878 this.fireEvent('valid', this);
29882 * Mark this field as invalid
29883 * @param {String} msg The validation message
29885 markInvalid : function(msg)
29887 if(this.indicator){
29888 this.indicator.removeClass('invisible');
29889 this.indicator.addClass('visible');
29892 this.el.removeClass(this.validClass);
29894 this.el.addClass(this.invalidClass);
29896 this.fireEvent('invalid', this, msg);
29902 Roo.apply(Roo.bootstrap.FieldLabel, {
29907 * register a FieldLabel Group
29908 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29910 register : function(label)
29912 if(this.groups.hasOwnProperty(label.target)){
29916 this.groups[label.target] = label;
29920 * fetch a FieldLabel Group based on the target
29921 * @param {string} target
29922 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29924 get: function(target) {
29925 if (typeof(this.groups[target]) == 'undefined') {
29929 return this.groups[target] ;
29938 * page DateSplitField.
29944 * @class Roo.bootstrap.DateSplitField
29945 * @extends Roo.bootstrap.Component
29946 * Bootstrap DateSplitField class
29947 * @cfg {string} fieldLabel - the label associated
29948 * @cfg {Number} labelWidth set the width of label (0-12)
29949 * @cfg {String} labelAlign (top|left)
29950 * @cfg {Boolean} dayAllowBlank (true|false) default false
29951 * @cfg {Boolean} monthAllowBlank (true|false) default false
29952 * @cfg {Boolean} yearAllowBlank (true|false) default false
29953 * @cfg {string} dayPlaceholder
29954 * @cfg {string} monthPlaceholder
29955 * @cfg {string} yearPlaceholder
29956 * @cfg {string} dayFormat default 'd'
29957 * @cfg {string} monthFormat default 'm'
29958 * @cfg {string} yearFormat default 'Y'
29959 * @cfg {Number} labellg set the width of label (1-12)
29960 * @cfg {Number} labelmd set the width of label (1-12)
29961 * @cfg {Number} labelsm set the width of label (1-12)
29962 * @cfg {Number} labelxs set the width of label (1-12)
29966 * Create a new DateSplitField
29967 * @param {Object} config The config object
29970 Roo.bootstrap.DateSplitField = function(config){
29971 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29977 * getting the data of years
29978 * @param {Roo.bootstrap.DateSplitField} this
29979 * @param {Object} years
29984 * getting the data of days
29985 * @param {Roo.bootstrap.DateSplitField} this
29986 * @param {Object} days
29991 * Fires after the field has been marked as invalid.
29992 * @param {Roo.form.Field} this
29993 * @param {String} msg The validation message
29998 * Fires after the field has been validated with no errors.
29999 * @param {Roo.form.Field} this
30005 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30008 labelAlign : 'top',
30010 dayAllowBlank : false,
30011 monthAllowBlank : false,
30012 yearAllowBlank : false,
30013 dayPlaceholder : '',
30014 monthPlaceholder : '',
30015 yearPlaceholder : '',
30019 isFormField : true,
30025 getAutoCreate : function()
30029 cls : 'row roo-date-split-field-group',
30034 cls : 'form-hidden-field roo-date-split-field-group-value',
30040 var labelCls = 'col-md-12';
30041 var contentCls = 'col-md-4';
30043 if(this.fieldLabel){
30047 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30051 html : this.fieldLabel
30056 if(this.labelAlign == 'left'){
30058 if(this.labelWidth > 12){
30059 label.style = "width: " + this.labelWidth + 'px';
30062 if(this.labelWidth < 13 && this.labelmd == 0){
30063 this.labelmd = this.labelWidth;
30066 if(this.labellg > 0){
30067 labelCls = ' col-lg-' + this.labellg;
30068 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30071 if(this.labelmd > 0){
30072 labelCls = ' col-md-' + this.labelmd;
30073 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30076 if(this.labelsm > 0){
30077 labelCls = ' col-sm-' + this.labelsm;
30078 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30081 if(this.labelxs > 0){
30082 labelCls = ' col-xs-' + this.labelxs;
30083 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30087 label.cls += ' ' + labelCls;
30089 cfg.cn.push(label);
30092 Roo.each(['day', 'month', 'year'], function(t){
30095 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30102 inputEl: function ()
30104 return this.el.select('.roo-date-split-field-group-value', true).first();
30107 onRender : function(ct, position)
30111 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30113 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30115 this.dayField = new Roo.bootstrap.ComboBox({
30116 allowBlank : this.dayAllowBlank,
30117 alwaysQuery : true,
30118 displayField : 'value',
30121 forceSelection : true,
30123 placeholder : this.dayPlaceholder,
30124 selectOnFocus : true,
30125 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30126 triggerAction : 'all',
30128 valueField : 'value',
30129 store : new Roo.data.SimpleStore({
30130 data : (function() {
30132 _this.fireEvent('days', _this, days);
30135 fields : [ 'value' ]
30138 select : function (_self, record, index)
30140 _this.setValue(_this.getValue());
30145 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30147 this.monthField = new Roo.bootstrap.MonthField({
30148 after : '<i class=\"fa fa-calendar\"></i>',
30149 allowBlank : this.monthAllowBlank,
30150 placeholder : this.monthPlaceholder,
30153 render : function (_self)
30155 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30156 e.preventDefault();
30160 select : function (_self, oldvalue, newvalue)
30162 _this.setValue(_this.getValue());
30167 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30169 this.yearField = new Roo.bootstrap.ComboBox({
30170 allowBlank : this.yearAllowBlank,
30171 alwaysQuery : true,
30172 displayField : 'value',
30175 forceSelection : true,
30177 placeholder : this.yearPlaceholder,
30178 selectOnFocus : true,
30179 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30180 triggerAction : 'all',
30182 valueField : 'value',
30183 store : new Roo.data.SimpleStore({
30184 data : (function() {
30186 _this.fireEvent('years', _this, years);
30189 fields : [ 'value' ]
30192 select : function (_self, record, index)
30194 _this.setValue(_this.getValue());
30199 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30202 setValue : function(v, format)
30204 this.inputEl.dom.value = v;
30206 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30208 var d = Date.parseDate(v, f);
30215 this.setDay(d.format(this.dayFormat));
30216 this.setMonth(d.format(this.monthFormat));
30217 this.setYear(d.format(this.yearFormat));
30224 setDay : function(v)
30226 this.dayField.setValue(v);
30227 this.inputEl.dom.value = this.getValue();
30232 setMonth : function(v)
30234 this.monthField.setValue(v, true);
30235 this.inputEl.dom.value = this.getValue();
30240 setYear : function(v)
30242 this.yearField.setValue(v);
30243 this.inputEl.dom.value = this.getValue();
30248 getDay : function()
30250 return this.dayField.getValue();
30253 getMonth : function()
30255 return this.monthField.getValue();
30258 getYear : function()
30260 return this.yearField.getValue();
30263 getValue : function()
30265 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30267 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30277 this.inputEl.dom.value = '';
30282 validate : function()
30284 var d = this.dayField.validate();
30285 var m = this.monthField.validate();
30286 var y = this.yearField.validate();
30291 (!this.dayAllowBlank && !d) ||
30292 (!this.monthAllowBlank && !m) ||
30293 (!this.yearAllowBlank && !y)
30298 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30307 this.markInvalid();
30312 markValid : function()
30315 var label = this.el.select('label', true).first();
30316 var icon = this.el.select('i.fa-star', true).first();
30322 this.fireEvent('valid', this);
30326 * Mark this field as invalid
30327 * @param {String} msg The validation message
30329 markInvalid : function(msg)
30332 var label = this.el.select('label', true).first();
30333 var icon = this.el.select('i.fa-star', true).first();
30335 if(label && !icon){
30336 this.el.select('.roo-date-split-field-label', true).createChild({
30338 cls : 'text-danger fa fa-lg fa-star',
30339 tooltip : 'This field is required',
30340 style : 'margin-right:5px;'
30344 this.fireEvent('invalid', this, msg);
30347 clearInvalid : function()
30349 var label = this.el.select('label', true).first();
30350 var icon = this.el.select('i.fa-star', true).first();
30356 this.fireEvent('valid', this);
30359 getName: function()
30369 * http://masonry.desandro.com
30371 * The idea is to render all the bricks based on vertical width...
30373 * The original code extends 'outlayer' - we might need to use that....
30379 * @class Roo.bootstrap.LayoutMasonry
30380 * @extends Roo.bootstrap.Component
30381 * Bootstrap Layout Masonry class
30384 * Create a new Element
30385 * @param {Object} config The config object
30388 Roo.bootstrap.LayoutMasonry = function(config){
30390 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30394 Roo.bootstrap.LayoutMasonry.register(this);
30400 * Fire after layout the items
30401 * @param {Roo.bootstrap.LayoutMasonry} this
30402 * @param {Roo.EventObject} e
30409 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30412 * @cfg {Boolean} isLayoutInstant = no animation?
30414 isLayoutInstant : false, // needed?
30417 * @cfg {Number} boxWidth width of the columns
30422 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30427 * @cfg {Number} padWidth padding below box..
30432 * @cfg {Number} gutter gutter width..
30437 * @cfg {Number} maxCols maximum number of columns
30443 * @cfg {Boolean} isAutoInitial defalut true
30445 isAutoInitial : true,
30450 * @cfg {Boolean} isHorizontal defalut false
30452 isHorizontal : false,
30454 currentSize : null,
30460 bricks: null, //CompositeElement
30464 _isLayoutInited : false,
30466 // isAlternative : false, // only use for vertical layout...
30469 * @cfg {Number} alternativePadWidth padding below box..
30471 alternativePadWidth : 50,
30473 selectedBrick : [],
30475 getAutoCreate : function(){
30477 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30481 cls: 'blog-masonary-wrapper ' + this.cls,
30483 cls : 'mas-boxes masonary'
30490 getChildContainer: function( )
30492 if (this.boxesEl) {
30493 return this.boxesEl;
30496 this.boxesEl = this.el.select('.mas-boxes').first();
30498 return this.boxesEl;
30502 initEvents : function()
30506 if(this.isAutoInitial){
30507 Roo.log('hook children rendered');
30508 this.on('childrenrendered', function() {
30509 Roo.log('children rendered');
30515 initial : function()
30517 this.selectedBrick = [];
30519 this.currentSize = this.el.getBox(true);
30521 Roo.EventManager.onWindowResize(this.resize, this);
30523 if(!this.isAutoInitial){
30531 //this.layout.defer(500,this);
30535 resize : function()
30537 var cs = this.el.getBox(true);
30540 this.currentSize.width == cs.width &&
30541 this.currentSize.x == cs.x &&
30542 this.currentSize.height == cs.height &&
30543 this.currentSize.y == cs.y
30545 Roo.log("no change in with or X or Y");
30549 this.currentSize = cs;
30555 layout : function()
30557 this._resetLayout();
30559 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30561 this.layoutItems( isInstant );
30563 this._isLayoutInited = true;
30565 this.fireEvent('layout', this);
30569 _resetLayout : function()
30571 if(this.isHorizontal){
30572 this.horizontalMeasureColumns();
30576 this.verticalMeasureColumns();
30580 verticalMeasureColumns : function()
30582 this.getContainerWidth();
30584 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30585 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30589 var boxWidth = this.boxWidth + this.padWidth;
30591 if(this.containerWidth < this.boxWidth){
30592 boxWidth = this.containerWidth
30595 var containerWidth = this.containerWidth;
30597 var cols = Math.floor(containerWidth / boxWidth);
30599 this.cols = Math.max( cols, 1 );
30601 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30603 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30605 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30607 this.colWidth = boxWidth + avail - this.padWidth;
30609 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30610 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30613 horizontalMeasureColumns : function()
30615 this.getContainerWidth();
30617 var boxWidth = this.boxWidth;
30619 if(this.containerWidth < boxWidth){
30620 boxWidth = this.containerWidth;
30623 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30625 this.el.setHeight(boxWidth);
30629 getContainerWidth : function()
30631 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30634 layoutItems : function( isInstant )
30636 Roo.log(this.bricks);
30638 var items = Roo.apply([], this.bricks);
30640 if(this.isHorizontal){
30641 this._horizontalLayoutItems( items , isInstant );
30645 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30646 // this._verticalAlternativeLayoutItems( items , isInstant );
30650 this._verticalLayoutItems( items , isInstant );
30654 _verticalLayoutItems : function ( items , isInstant)
30656 if ( !items || !items.length ) {
30661 ['xs', 'xs', 'xs', 'tall'],
30662 ['xs', 'xs', 'tall'],
30663 ['xs', 'xs', 'sm'],
30664 ['xs', 'xs', 'xs'],
30670 ['sm', 'xs', 'xs'],
30674 ['tall', 'xs', 'xs', 'xs'],
30675 ['tall', 'xs', 'xs'],
30687 Roo.each(items, function(item, k){
30689 switch (item.size) {
30690 // these layouts take up a full box,
30701 boxes.push([item]);
30724 var filterPattern = function(box, length)
30732 var pattern = box.slice(0, length);
30736 Roo.each(pattern, function(i){
30737 format.push(i.size);
30740 Roo.each(standard, function(s){
30742 if(String(s) != String(format)){
30751 if(!match && length == 1){
30756 filterPattern(box, length - 1);
30760 queue.push(pattern);
30762 box = box.slice(length, box.length);
30764 filterPattern(box, 4);
30770 Roo.each(boxes, function(box, k){
30776 if(box.length == 1){
30781 filterPattern(box, 4);
30785 this._processVerticalLayoutQueue( queue, isInstant );
30789 // _verticalAlternativeLayoutItems : function( items , isInstant )
30791 // if ( !items || !items.length ) {
30795 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30799 _horizontalLayoutItems : function ( items , isInstant)
30801 if ( !items || !items.length || items.length < 3) {
30807 var eItems = items.slice(0, 3);
30809 items = items.slice(3, items.length);
30812 ['xs', 'xs', 'xs', 'wide'],
30813 ['xs', 'xs', 'wide'],
30814 ['xs', 'xs', 'sm'],
30815 ['xs', 'xs', 'xs'],
30821 ['sm', 'xs', 'xs'],
30825 ['wide', 'xs', 'xs', 'xs'],
30826 ['wide', 'xs', 'xs'],
30839 Roo.each(items, function(item, k){
30841 switch (item.size) {
30852 boxes.push([item]);
30876 var filterPattern = function(box, length)
30884 var pattern = box.slice(0, length);
30888 Roo.each(pattern, function(i){
30889 format.push(i.size);
30892 Roo.each(standard, function(s){
30894 if(String(s) != String(format)){
30903 if(!match && length == 1){
30908 filterPattern(box, length - 1);
30912 queue.push(pattern);
30914 box = box.slice(length, box.length);
30916 filterPattern(box, 4);
30922 Roo.each(boxes, function(box, k){
30928 if(box.length == 1){
30933 filterPattern(box, 4);
30940 var pos = this.el.getBox(true);
30944 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30946 var hit_end = false;
30948 Roo.each(queue, function(box){
30952 Roo.each(box, function(b){
30954 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30964 Roo.each(box, function(b){
30966 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30969 mx = Math.max(mx, b.x);
30973 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30977 Roo.each(box, function(b){
30979 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30993 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30996 /** Sets position of item in DOM
30997 * @param {Element} item
30998 * @param {Number} x - horizontal position
30999 * @param {Number} y - vertical position
31000 * @param {Boolean} isInstant - disables transitions
31002 _processVerticalLayoutQueue : function( queue, isInstant )
31004 var pos = this.el.getBox(true);
31009 for (var i = 0; i < this.cols; i++){
31013 Roo.each(queue, function(box, k){
31015 var col = k % this.cols;
31017 Roo.each(box, function(b,kk){
31019 b.el.position('absolute');
31021 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31022 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31024 if(b.size == 'md-left' || b.size == 'md-right'){
31025 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31026 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31029 b.el.setWidth(width);
31030 b.el.setHeight(height);
31032 b.el.select('iframe',true).setSize(width,height);
31036 for (var i = 0; i < this.cols; i++){
31038 if(maxY[i] < maxY[col]){
31043 col = Math.min(col, i);
31047 x = pos.x + col * (this.colWidth + this.padWidth);
31051 var positions = [];
31053 switch (box.length){
31055 positions = this.getVerticalOneBoxColPositions(x, y, box);
31058 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31061 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31064 positions = this.getVerticalFourBoxColPositions(x, y, box);
31070 Roo.each(box, function(b,kk){
31072 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31074 var sz = b.el.getSize();
31076 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31084 for (var i = 0; i < this.cols; i++){
31085 mY = Math.max(mY, maxY[i]);
31088 this.el.setHeight(mY - pos.y);
31092 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31094 // var pos = this.el.getBox(true);
31097 // var maxX = pos.right;
31099 // var maxHeight = 0;
31101 // Roo.each(items, function(item, k){
31105 // item.el.position('absolute');
31107 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31109 // item.el.setWidth(width);
31111 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31113 // item.el.setHeight(height);
31116 // item.el.setXY([x, y], isInstant ? false : true);
31118 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31121 // y = y + height + this.alternativePadWidth;
31123 // maxHeight = maxHeight + height + this.alternativePadWidth;
31127 // this.el.setHeight(maxHeight);
31131 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31133 var pos = this.el.getBox(true);
31138 var maxX = pos.right;
31140 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31142 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31144 Roo.each(queue, function(box, k){
31146 Roo.each(box, function(b, kk){
31148 b.el.position('absolute');
31150 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31151 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31153 if(b.size == 'md-left' || b.size == 'md-right'){
31154 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31155 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31158 b.el.setWidth(width);
31159 b.el.setHeight(height);
31167 var positions = [];
31169 switch (box.length){
31171 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31174 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31177 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31180 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31186 Roo.each(box, function(b,kk){
31188 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31190 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31198 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31200 Roo.each(eItems, function(b,k){
31202 b.size = (k == 0) ? 'sm' : 'xs';
31203 b.x = (k == 0) ? 2 : 1;
31204 b.y = (k == 0) ? 2 : 1;
31206 b.el.position('absolute');
31208 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31210 b.el.setWidth(width);
31212 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31214 b.el.setHeight(height);
31218 var positions = [];
31221 x : maxX - this.unitWidth * 2 - this.gutter,
31226 x : maxX - this.unitWidth,
31227 y : minY + (this.unitWidth + this.gutter) * 2
31231 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31235 Roo.each(eItems, function(b,k){
31237 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31243 getVerticalOneBoxColPositions : function(x, y, box)
31247 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31249 if(box[0].size == 'md-left'){
31253 if(box[0].size == 'md-right'){
31258 x : x + (this.unitWidth + this.gutter) * rand,
31265 getVerticalTwoBoxColPositions : function(x, y, box)
31269 if(box[0].size == 'xs'){
31273 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31277 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31291 x : x + (this.unitWidth + this.gutter) * 2,
31292 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31299 getVerticalThreeBoxColPositions : function(x, y, box)
31303 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31311 x : x + (this.unitWidth + this.gutter) * 1,
31316 x : x + (this.unitWidth + this.gutter) * 2,
31324 if(box[0].size == 'xs' && box[1].size == 'xs'){
31333 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31337 x : x + (this.unitWidth + this.gutter) * 1,
31351 x : x + (this.unitWidth + this.gutter) * 2,
31356 x : x + (this.unitWidth + this.gutter) * 2,
31357 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31364 getVerticalFourBoxColPositions : function(x, y, box)
31368 if(box[0].size == 'xs'){
31377 y : y + (this.unitHeight + this.gutter) * 1
31382 y : y + (this.unitHeight + this.gutter) * 2
31386 x : x + (this.unitWidth + this.gutter) * 1,
31400 x : x + (this.unitWidth + this.gutter) * 2,
31405 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31406 y : y + (this.unitHeight + this.gutter) * 1
31410 x : x + (this.unitWidth + this.gutter) * 2,
31411 y : y + (this.unitWidth + this.gutter) * 2
31418 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31422 if(box[0].size == 'md-left'){
31424 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31431 if(box[0].size == 'md-right'){
31433 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31434 y : minY + (this.unitWidth + this.gutter) * 1
31440 var rand = Math.floor(Math.random() * (4 - box[0].y));
31443 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31444 y : minY + (this.unitWidth + this.gutter) * rand
31451 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31455 if(box[0].size == 'xs'){
31458 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31463 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31464 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31472 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31477 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31478 y : minY + (this.unitWidth + this.gutter) * 2
31485 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31489 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31492 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31497 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31498 y : minY + (this.unitWidth + this.gutter) * 1
31502 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31503 y : minY + (this.unitWidth + this.gutter) * 2
31510 if(box[0].size == 'xs' && box[1].size == 'xs'){
31513 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31518 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31523 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31524 y : minY + (this.unitWidth + this.gutter) * 1
31532 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31537 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31538 y : minY + (this.unitWidth + this.gutter) * 2
31542 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31543 y : minY + (this.unitWidth + this.gutter) * 2
31550 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31554 if(box[0].size == 'xs'){
31557 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31562 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31567 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31572 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31573 y : minY + (this.unitWidth + this.gutter) * 1
31581 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31586 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31587 y : minY + (this.unitWidth + this.gutter) * 2
31591 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31592 y : minY + (this.unitWidth + this.gutter) * 2
31596 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31597 y : minY + (this.unitWidth + this.gutter) * 2
31605 * remove a Masonry Brick
31606 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31608 removeBrick : function(brick_id)
31614 for (var i = 0; i<this.bricks.length; i++) {
31615 if (this.bricks[i].id == brick_id) {
31616 this.bricks.splice(i,1);
31617 this.el.dom.removeChild(Roo.get(brick_id).dom);
31624 * adds a Masonry Brick
31625 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31627 addBrick : function(cfg)
31629 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31630 //this.register(cn);
31631 cn.parentId = this.id;
31632 cn.onRender(this.el, null);
31637 * register a Masonry Brick
31638 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31641 register : function(brick)
31643 this.bricks.push(brick);
31644 brick.masonryId = this.id;
31648 * clear all the Masonry Brick
31650 clearAll : function()
31653 //this.getChildContainer().dom.innerHTML = "";
31654 this.el.dom.innerHTML = '';
31657 getSelected : function()
31659 if (!this.selectedBrick) {
31663 return this.selectedBrick;
31667 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31671 * register a Masonry Layout
31672 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31675 register : function(layout)
31677 this.groups[layout.id] = layout;
31680 * fetch a Masonry Layout based on the masonry layout ID
31681 * @param {string} the masonry layout to add
31682 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31685 get: function(layout_id) {
31686 if (typeof(this.groups[layout_id]) == 'undefined') {
31689 return this.groups[layout_id] ;
31701 * http://masonry.desandro.com
31703 * The idea is to render all the bricks based on vertical width...
31705 * The original code extends 'outlayer' - we might need to use that....
31711 * @class Roo.bootstrap.LayoutMasonryAuto
31712 * @extends Roo.bootstrap.Component
31713 * Bootstrap Layout Masonry class
31716 * Create a new Element
31717 * @param {Object} config The config object
31720 Roo.bootstrap.LayoutMasonryAuto = function(config){
31721 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31724 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31727 * @cfg {Boolean} isFitWidth - resize the width..
31729 isFitWidth : false, // options..
31731 * @cfg {Boolean} isOriginLeft = left align?
31733 isOriginLeft : true,
31735 * @cfg {Boolean} isOriginTop = top align?
31737 isOriginTop : false,
31739 * @cfg {Boolean} isLayoutInstant = no animation?
31741 isLayoutInstant : false, // needed?
31743 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31745 isResizingContainer : true,
31747 * @cfg {Number} columnWidth width of the columns
31753 * @cfg {Number} maxCols maximum number of columns
31758 * @cfg {Number} padHeight padding below box..
31764 * @cfg {Boolean} isAutoInitial defalut true
31767 isAutoInitial : true,
31773 initialColumnWidth : 0,
31774 currentSize : null,
31776 colYs : null, // array.
31783 bricks: null, //CompositeElement
31784 cols : 0, // array?
31785 // element : null, // wrapped now this.el
31786 _isLayoutInited : null,
31789 getAutoCreate : function(){
31793 cls: 'blog-masonary-wrapper ' + this.cls,
31795 cls : 'mas-boxes masonary'
31802 getChildContainer: function( )
31804 if (this.boxesEl) {
31805 return this.boxesEl;
31808 this.boxesEl = this.el.select('.mas-boxes').first();
31810 return this.boxesEl;
31814 initEvents : function()
31818 if(this.isAutoInitial){
31819 Roo.log('hook children rendered');
31820 this.on('childrenrendered', function() {
31821 Roo.log('children rendered');
31828 initial : function()
31830 this.reloadItems();
31832 this.currentSize = this.el.getBox(true);
31834 /// was window resize... - let's see if this works..
31835 Roo.EventManager.onWindowResize(this.resize, this);
31837 if(!this.isAutoInitial){
31842 this.layout.defer(500,this);
31845 reloadItems: function()
31847 this.bricks = this.el.select('.masonry-brick', true);
31849 this.bricks.each(function(b) {
31850 //Roo.log(b.getSize());
31851 if (!b.attr('originalwidth')) {
31852 b.attr('originalwidth', b.getSize().width);
31857 Roo.log(this.bricks.elements.length);
31860 resize : function()
31863 var cs = this.el.getBox(true);
31865 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31866 Roo.log("no change in with or X");
31869 this.currentSize = cs;
31873 layout : function()
31876 this._resetLayout();
31877 //this._manageStamps();
31879 // don't animate first layout
31880 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31881 this.layoutItems( isInstant );
31883 // flag for initalized
31884 this._isLayoutInited = true;
31887 layoutItems : function( isInstant )
31889 //var items = this._getItemsForLayout( this.items );
31890 // original code supports filtering layout items.. we just ignore it..
31892 this._layoutItems( this.bricks , isInstant );
31894 this._postLayout();
31896 _layoutItems : function ( items , isInstant)
31898 //this.fireEvent( 'layout', this, items );
31901 if ( !items || !items.elements.length ) {
31902 // no items, emit event with empty array
31907 items.each(function(item) {
31908 Roo.log("layout item");
31910 // get x/y object from method
31911 var position = this._getItemLayoutPosition( item );
31913 position.item = item;
31914 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31915 queue.push( position );
31918 this._processLayoutQueue( queue );
31920 /** Sets position of item in DOM
31921 * @param {Element} item
31922 * @param {Number} x - horizontal position
31923 * @param {Number} y - vertical position
31924 * @param {Boolean} isInstant - disables transitions
31926 _processLayoutQueue : function( queue )
31928 for ( var i=0, len = queue.length; i < len; i++ ) {
31929 var obj = queue[i];
31930 obj.item.position('absolute');
31931 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31937 * Any logic you want to do after each layout,
31938 * i.e. size the container
31940 _postLayout : function()
31942 this.resizeContainer();
31945 resizeContainer : function()
31947 if ( !this.isResizingContainer ) {
31950 var size = this._getContainerSize();
31952 this.el.setSize(size.width,size.height);
31953 this.boxesEl.setSize(size.width,size.height);
31959 _resetLayout : function()
31961 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31962 this.colWidth = this.el.getWidth();
31963 //this.gutter = this.el.getWidth();
31965 this.measureColumns();
31971 this.colYs.push( 0 );
31977 measureColumns : function()
31979 this.getContainerWidth();
31980 // if columnWidth is 0, default to outerWidth of first item
31981 if ( !this.columnWidth ) {
31982 var firstItem = this.bricks.first();
31983 Roo.log(firstItem);
31984 this.columnWidth = this.containerWidth;
31985 if (firstItem && firstItem.attr('originalwidth') ) {
31986 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31988 // columnWidth fall back to item of first element
31989 Roo.log("set column width?");
31990 this.initialColumnWidth = this.columnWidth ;
31992 // if first elem has no width, default to size of container
31997 if (this.initialColumnWidth) {
31998 this.columnWidth = this.initialColumnWidth;
32003 // column width is fixed at the top - however if container width get's smaller we should
32006 // this bit calcs how man columns..
32008 var columnWidth = this.columnWidth += this.gutter;
32010 // calculate columns
32011 var containerWidth = this.containerWidth + this.gutter;
32013 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32014 // fix rounding errors, typically with gutters
32015 var excess = columnWidth - containerWidth % columnWidth;
32018 // if overshoot is less than a pixel, round up, otherwise floor it
32019 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32020 cols = Math[ mathMethod ]( cols );
32021 this.cols = Math.max( cols, 1 );
32022 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32024 // padding positioning..
32025 var totalColWidth = this.cols * this.columnWidth;
32026 var padavail = this.containerWidth - totalColWidth;
32027 // so for 2 columns - we need 3 'pads'
32029 var padNeeded = (1+this.cols) * this.padWidth;
32031 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32033 this.columnWidth += padExtra
32034 //this.padWidth = Math.floor(padavail / ( this.cols));
32036 // adjust colum width so that padding is fixed??
32038 // we have 3 columns ... total = width * 3
32039 // we have X left over... that should be used by
32041 //if (this.expandC) {
32049 getContainerWidth : function()
32051 /* // container is parent if fit width
32052 var container = this.isFitWidth ? this.element.parentNode : this.element;
32053 // check that this.size and size are there
32054 // IE8 triggers resize on body size change, so they might not be
32056 var size = getSize( container ); //FIXME
32057 this.containerWidth = size && size.innerWidth; //FIXME
32060 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32064 _getItemLayoutPosition : function( item ) // what is item?
32066 // we resize the item to our columnWidth..
32068 item.setWidth(this.columnWidth);
32069 item.autoBoxAdjust = false;
32071 var sz = item.getSize();
32073 // how many columns does this brick span
32074 var remainder = this.containerWidth % this.columnWidth;
32076 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32077 // round if off by 1 pixel, otherwise use ceil
32078 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32079 colSpan = Math.min( colSpan, this.cols );
32081 // normally this should be '1' as we dont' currently allow multi width columns..
32083 var colGroup = this._getColGroup( colSpan );
32084 // get the minimum Y value from the columns
32085 var minimumY = Math.min.apply( Math, colGroup );
32086 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32088 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32090 // position the brick
32092 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32093 y: this.currentSize.y + minimumY + this.padHeight
32097 // apply setHeight to necessary columns
32098 var setHeight = minimumY + sz.height + this.padHeight;
32099 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32101 var setSpan = this.cols + 1 - colGroup.length;
32102 for ( var i = 0; i < setSpan; i++ ) {
32103 this.colYs[ shortColIndex + i ] = setHeight ;
32110 * @param {Number} colSpan - number of columns the element spans
32111 * @returns {Array} colGroup
32113 _getColGroup : function( colSpan )
32115 if ( colSpan < 2 ) {
32116 // if brick spans only one column, use all the column Ys
32121 // how many different places could this brick fit horizontally
32122 var groupCount = this.cols + 1 - colSpan;
32123 // for each group potential horizontal position
32124 for ( var i = 0; i < groupCount; i++ ) {
32125 // make an array of colY values for that one group
32126 var groupColYs = this.colYs.slice( i, i + colSpan );
32127 // and get the max value of the array
32128 colGroup[i] = Math.max.apply( Math, groupColYs );
32133 _manageStamp : function( stamp )
32135 var stampSize = stamp.getSize();
32136 var offset = stamp.getBox();
32137 // get the columns that this stamp affects
32138 var firstX = this.isOriginLeft ? offset.x : offset.right;
32139 var lastX = firstX + stampSize.width;
32140 var firstCol = Math.floor( firstX / this.columnWidth );
32141 firstCol = Math.max( 0, firstCol );
32143 var lastCol = Math.floor( lastX / this.columnWidth );
32144 // lastCol should not go over if multiple of columnWidth #425
32145 lastCol -= lastX % this.columnWidth ? 0 : 1;
32146 lastCol = Math.min( this.cols - 1, lastCol );
32148 // set colYs to bottom of the stamp
32149 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32152 for ( var i = firstCol; i <= lastCol; i++ ) {
32153 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32158 _getContainerSize : function()
32160 this.maxY = Math.max.apply( Math, this.colYs );
32165 if ( this.isFitWidth ) {
32166 size.width = this._getContainerFitWidth();
32172 _getContainerFitWidth : function()
32174 var unusedCols = 0;
32175 // count unused columns
32178 if ( this.colYs[i] !== 0 ) {
32183 // fit container to columns that have been used
32184 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32187 needsResizeLayout : function()
32189 var previousWidth = this.containerWidth;
32190 this.getContainerWidth();
32191 return previousWidth !== this.containerWidth;
32206 * @class Roo.bootstrap.MasonryBrick
32207 * @extends Roo.bootstrap.Component
32208 * Bootstrap MasonryBrick class
32211 * Create a new MasonryBrick
32212 * @param {Object} config The config object
32215 Roo.bootstrap.MasonryBrick = function(config){
32217 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32219 Roo.bootstrap.MasonryBrick.register(this);
32225 * When a MasonryBrick is clcik
32226 * @param {Roo.bootstrap.MasonryBrick} this
32227 * @param {Roo.EventObject} e
32233 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32236 * @cfg {String} title
32240 * @cfg {String} html
32244 * @cfg {String} bgimage
32248 * @cfg {String} videourl
32252 * @cfg {String} cls
32256 * @cfg {String} href
32260 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32265 * @cfg {String} placetitle (center|bottom)
32270 * @cfg {Boolean} isFitContainer defalut true
32272 isFitContainer : true,
32275 * @cfg {Boolean} preventDefault defalut false
32277 preventDefault : false,
32280 * @cfg {Boolean} inverse defalut false
32282 maskInverse : false,
32284 getAutoCreate : function()
32286 if(!this.isFitContainer){
32287 return this.getSplitAutoCreate();
32290 var cls = 'masonry-brick masonry-brick-full';
32292 if(this.href.length){
32293 cls += ' masonry-brick-link';
32296 if(this.bgimage.length){
32297 cls += ' masonry-brick-image';
32300 if(this.maskInverse){
32301 cls += ' mask-inverse';
32304 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32305 cls += ' enable-mask';
32309 cls += ' masonry-' + this.size + '-brick';
32312 if(this.placetitle.length){
32314 switch (this.placetitle) {
32316 cls += ' masonry-center-title';
32319 cls += ' masonry-bottom-title';
32326 if(!this.html.length && !this.bgimage.length){
32327 cls += ' masonry-center-title';
32330 if(!this.html.length && this.bgimage.length){
32331 cls += ' masonry-bottom-title';
32336 cls += ' ' + this.cls;
32340 tag: (this.href.length) ? 'a' : 'div',
32345 cls: 'masonry-brick-mask'
32349 cls: 'masonry-brick-paragraph',
32355 if(this.href.length){
32356 cfg.href = this.href;
32359 var cn = cfg.cn[1].cn;
32361 if(this.title.length){
32364 cls: 'masonry-brick-title',
32369 if(this.html.length){
32372 cls: 'masonry-brick-text',
32377 if (!this.title.length && !this.html.length) {
32378 cfg.cn[1].cls += ' hide';
32381 if(this.bgimage.length){
32384 cls: 'masonry-brick-image-view',
32389 if(this.videourl.length){
32390 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32391 // youtube support only?
32394 cls: 'masonry-brick-image-view',
32397 allowfullscreen : true
32405 getSplitAutoCreate : function()
32407 var cls = 'masonry-brick masonry-brick-split';
32409 if(this.href.length){
32410 cls += ' masonry-brick-link';
32413 if(this.bgimage.length){
32414 cls += ' masonry-brick-image';
32418 cls += ' masonry-' + this.size + '-brick';
32421 switch (this.placetitle) {
32423 cls += ' masonry-center-title';
32426 cls += ' masonry-bottom-title';
32429 if(!this.bgimage.length){
32430 cls += ' masonry-center-title';
32433 if(this.bgimage.length){
32434 cls += ' masonry-bottom-title';
32440 cls += ' ' + this.cls;
32444 tag: (this.href.length) ? 'a' : 'div',
32449 cls: 'masonry-brick-split-head',
32453 cls: 'masonry-brick-paragraph',
32460 cls: 'masonry-brick-split-body',
32466 if(this.href.length){
32467 cfg.href = this.href;
32470 if(this.title.length){
32471 cfg.cn[0].cn[0].cn.push({
32473 cls: 'masonry-brick-title',
32478 if(this.html.length){
32479 cfg.cn[1].cn.push({
32481 cls: 'masonry-brick-text',
32486 if(this.bgimage.length){
32487 cfg.cn[0].cn.push({
32489 cls: 'masonry-brick-image-view',
32494 if(this.videourl.length){
32495 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32496 // youtube support only?
32497 cfg.cn[0].cn.cn.push({
32499 cls: 'masonry-brick-image-view',
32502 allowfullscreen : true
32509 initEvents: function()
32511 switch (this.size) {
32544 this.el.on('touchstart', this.onTouchStart, this);
32545 this.el.on('touchmove', this.onTouchMove, this);
32546 this.el.on('touchend', this.onTouchEnd, this);
32547 this.el.on('contextmenu', this.onContextMenu, this);
32549 this.el.on('mouseenter' ,this.enter, this);
32550 this.el.on('mouseleave', this.leave, this);
32551 this.el.on('click', this.onClick, this);
32554 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32555 this.parent().bricks.push(this);
32560 onClick: function(e, el)
32562 var time = this.endTimer - this.startTimer;
32563 // Roo.log(e.preventDefault());
32566 e.preventDefault();
32571 if(!this.preventDefault){
32575 e.preventDefault();
32577 if (this.activcClass != '') {
32578 this.selectBrick();
32581 this.fireEvent('click', this);
32584 enter: function(e, el)
32586 e.preventDefault();
32588 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32592 if(this.bgimage.length && this.html.length){
32593 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32597 leave: function(e, el)
32599 e.preventDefault();
32601 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32605 if(this.bgimage.length && this.html.length){
32606 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32610 onTouchStart: function(e, el)
32612 // e.preventDefault();
32614 this.touchmoved = false;
32616 if(!this.isFitContainer){
32620 if(!this.bgimage.length || !this.html.length){
32624 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32626 this.timer = new Date().getTime();
32630 onTouchMove: function(e, el)
32632 this.touchmoved = true;
32635 onContextMenu : function(e,el)
32637 e.preventDefault();
32638 e.stopPropagation();
32642 onTouchEnd: function(e, el)
32644 // e.preventDefault();
32646 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32653 if(!this.bgimage.length || !this.html.length){
32655 if(this.href.length){
32656 window.location.href = this.href;
32662 if(!this.isFitContainer){
32666 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32668 window.location.href = this.href;
32671 //selection on single brick only
32672 selectBrick : function() {
32674 if (!this.parentId) {
32678 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32679 var index = m.selectedBrick.indexOf(this.id);
32682 m.selectedBrick.splice(index,1);
32683 this.el.removeClass(this.activeClass);
32687 for(var i = 0; i < m.selectedBrick.length; i++) {
32688 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32689 b.el.removeClass(b.activeClass);
32692 m.selectedBrick = [];
32694 m.selectedBrick.push(this.id);
32695 this.el.addClass(this.activeClass);
32701 Roo.apply(Roo.bootstrap.MasonryBrick, {
32704 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32706 * register a Masonry Brick
32707 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32710 register : function(brick)
32712 //this.groups[brick.id] = brick;
32713 this.groups.add(brick.id, brick);
32716 * fetch a masonry brick based on the masonry brick ID
32717 * @param {string} the masonry brick to add
32718 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32721 get: function(brick_id)
32723 // if (typeof(this.groups[brick_id]) == 'undefined') {
32726 // return this.groups[brick_id] ;
32728 if(this.groups.key(brick_id)) {
32729 return this.groups.key(brick_id);
32747 * @class Roo.bootstrap.Brick
32748 * @extends Roo.bootstrap.Component
32749 * Bootstrap Brick class
32752 * Create a new Brick
32753 * @param {Object} config The config object
32756 Roo.bootstrap.Brick = function(config){
32757 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32763 * When a Brick is click
32764 * @param {Roo.bootstrap.Brick} this
32765 * @param {Roo.EventObject} e
32771 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32774 * @cfg {String} title
32778 * @cfg {String} html
32782 * @cfg {String} bgimage
32786 * @cfg {String} cls
32790 * @cfg {String} href
32794 * @cfg {String} video
32798 * @cfg {Boolean} square
32802 getAutoCreate : function()
32804 var cls = 'roo-brick';
32806 if(this.href.length){
32807 cls += ' roo-brick-link';
32810 if(this.bgimage.length){
32811 cls += ' roo-brick-image';
32814 if(!this.html.length && !this.bgimage.length){
32815 cls += ' roo-brick-center-title';
32818 if(!this.html.length && this.bgimage.length){
32819 cls += ' roo-brick-bottom-title';
32823 cls += ' ' + this.cls;
32827 tag: (this.href.length) ? 'a' : 'div',
32832 cls: 'roo-brick-paragraph',
32838 if(this.href.length){
32839 cfg.href = this.href;
32842 var cn = cfg.cn[0].cn;
32844 if(this.title.length){
32847 cls: 'roo-brick-title',
32852 if(this.html.length){
32855 cls: 'roo-brick-text',
32862 if(this.bgimage.length){
32865 cls: 'roo-brick-image-view',
32873 initEvents: function()
32875 if(this.title.length || this.html.length){
32876 this.el.on('mouseenter' ,this.enter, this);
32877 this.el.on('mouseleave', this.leave, this);
32880 Roo.EventManager.onWindowResize(this.resize, this);
32882 if(this.bgimage.length){
32883 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
32884 this.imageEl.on('load', this.onImageLoad, this);
32891 onImageLoad : function()
32896 resize : function()
32898 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32900 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32902 if(this.bgimage.length){
32903 var image = this.el.select('.roo-brick-image-view', true).first();
32905 image.setWidth(paragraph.getWidth());
32908 image.setHeight(paragraph.getWidth());
32911 this.el.setHeight(image.getHeight());
32912 paragraph.setHeight(image.getHeight());
32918 enter: function(e, el)
32920 e.preventDefault();
32922 if(this.bgimage.length){
32923 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32924 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32928 leave: function(e, el)
32930 e.preventDefault();
32932 if(this.bgimage.length){
32933 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32934 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32950 * @class Roo.bootstrap.NumberField
32951 * @extends Roo.bootstrap.Input
32952 * Bootstrap NumberField class
32958 * Create a new NumberField
32959 * @param {Object} config The config object
32962 Roo.bootstrap.NumberField = function(config){
32963 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32966 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32969 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32971 allowDecimals : true,
32973 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32975 decimalSeparator : ".",
32977 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32979 decimalPrecision : 2,
32981 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32983 allowNegative : true,
32985 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32987 minValue : Number.NEGATIVE_INFINITY,
32989 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32991 maxValue : Number.MAX_VALUE,
32993 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32995 minText : "The minimum value for this field is {0}",
32997 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32999 maxText : "The maximum value for this field is {0}",
33001 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33002 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33004 nanText : "{0} is not a valid number",
33006 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33011 initEvents : function()
33013 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33015 var allowed = "0123456789";
33017 if(this.allowDecimals){
33018 allowed += this.decimalSeparator;
33021 if(this.allowNegative){
33025 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33027 var keyPress = function(e){
33029 var k = e.getKey();
33031 var c = e.getCharCode();
33034 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33035 allowed.indexOf(String.fromCharCode(c)) === -1
33041 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33045 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33050 this.el.on("keypress", keyPress, this);
33053 validateValue : function(value)
33056 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33060 var num = this.parseValue(value);
33063 this.markInvalid(String.format(this.nanText, value));
33067 if(num < this.minValue){
33068 this.markInvalid(String.format(this.minText, this.minValue));
33072 if(num > this.maxValue){
33073 this.markInvalid(String.format(this.maxText, this.maxValue));
33080 getValue : function()
33082 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
33085 parseValue : function(value)
33087 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33088 return isNaN(value) ? '' : value;
33091 fixPrecision : function(value)
33093 var nan = isNaN(value);
33095 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33096 return nan ? '' : value;
33098 return parseFloat(value).toFixed(this.decimalPrecision);
33101 setValue : function(v)
33103 v = this.fixPrecision(v);
33104 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
33107 decimalPrecisionFcn : function(v)
33109 return Math.floor(v);
33112 beforeBlur : function()
33118 var v = this.parseValue(this.getRawValue());
33133 * @class Roo.bootstrap.DocumentSlider
33134 * @extends Roo.bootstrap.Component
33135 * Bootstrap DocumentSlider class
33138 * Create a new DocumentViewer
33139 * @param {Object} config The config object
33142 Roo.bootstrap.DocumentSlider = function(config){
33143 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33150 * Fire after initEvent
33151 * @param {Roo.bootstrap.DocumentSlider} this
33156 * Fire after update
33157 * @param {Roo.bootstrap.DocumentSlider} this
33163 * @param {Roo.bootstrap.DocumentSlider} this
33169 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33175 getAutoCreate : function()
33179 cls : 'roo-document-slider',
33183 cls : 'roo-document-slider-header',
33187 cls : 'roo-document-slider-header-title'
33193 cls : 'roo-document-slider-body',
33197 cls : 'roo-document-slider-prev',
33201 cls : 'fa fa-chevron-left'
33207 cls : 'roo-document-slider-thumb',
33211 cls : 'roo-document-slider-image'
33217 cls : 'roo-document-slider-next',
33221 cls : 'fa fa-chevron-right'
33233 initEvents : function()
33235 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33236 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33238 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33239 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33241 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33242 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33244 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33245 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33247 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33248 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33250 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33251 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33253 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33254 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33256 this.thumbEl.on('click', this.onClick, this);
33258 this.prevIndicator.on('click', this.prev, this);
33260 this.nextIndicator.on('click', this.next, this);
33264 initial : function()
33266 if(this.files.length){
33267 this.indicator = 1;
33271 this.fireEvent('initial', this);
33274 update : function()
33276 this.imageEl.attr('src', this.files[this.indicator - 1]);
33278 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33280 this.prevIndicator.show();
33282 if(this.indicator == 1){
33283 this.prevIndicator.hide();
33286 this.nextIndicator.show();
33288 if(this.indicator == this.files.length){
33289 this.nextIndicator.hide();
33292 this.thumbEl.scrollTo('top');
33294 this.fireEvent('update', this);
33297 onClick : function(e)
33299 e.preventDefault();
33301 this.fireEvent('click', this);
33306 e.preventDefault();
33308 this.indicator = Math.max(1, this.indicator - 1);
33315 e.preventDefault();
33317 this.indicator = Math.min(this.files.length, this.indicator + 1);
33331 * @class Roo.bootstrap.RadioSet
33332 * @extends Roo.bootstrap.Input
33333 * Bootstrap RadioSet class
33334 * @cfg {String} indicatorpos (left|right) default left
33335 * @cfg {Boolean} inline (true|false) inline the element (default true)
33336 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33338 * Create a new RadioSet
33339 * @param {Object} config The config object
33342 Roo.bootstrap.RadioSet = function(config){
33344 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33348 Roo.bootstrap.RadioSet.register(this);
33353 * Fires when the element is checked or unchecked.
33354 * @param {Roo.bootstrap.RadioSet} this This radio
33355 * @param {Roo.bootstrap.Radio} item The checked item
33362 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33370 indicatorpos : 'left',
33372 getAutoCreate : function()
33376 cls : 'roo-radio-set-label',
33380 html : this.fieldLabel
33385 if(this.indicatorpos == 'left'){
33388 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33389 tooltip : 'This field is required'
33394 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33395 tooltip : 'This field is required'
33401 cls : 'roo-radio-set-items'
33404 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33406 if (align === 'left' && this.fieldLabel.length) {
33409 cls : "roo-radio-set-right",
33415 if(this.labelWidth > 12){
33416 label.style = "width: " + this.labelWidth + 'px';
33419 if(this.labelWidth < 13 && this.labelmd == 0){
33420 this.labelmd = this.labelWidth;
33423 if(this.labellg > 0){
33424 label.cls += ' col-lg-' + this.labellg;
33425 items.cls += ' col-lg-' + (12 - this.labellg);
33428 if(this.labelmd > 0){
33429 label.cls += ' col-md-' + this.labelmd;
33430 items.cls += ' col-md-' + (12 - this.labelmd);
33433 if(this.labelsm > 0){
33434 label.cls += ' col-sm-' + this.labelsm;
33435 items.cls += ' col-sm-' + (12 - this.labelsm);
33438 if(this.labelxs > 0){
33439 label.cls += ' col-xs-' + this.labelxs;
33440 items.cls += ' col-xs-' + (12 - this.labelxs);
33446 cls : 'roo-radio-set',
33450 cls : 'roo-radio-set-input',
33453 value : this.value ? this.value : ''
33460 if(this.weight.length){
33461 cfg.cls += ' roo-radio-' + this.weight;
33465 cfg.cls += ' roo-radio-set-inline';
33469 ['xs','sm','md','lg'].map(function(size){
33470 if (settings[size]) {
33471 cfg.cls += ' col-' + size + '-' + settings[size];
33479 initEvents : function()
33481 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33482 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33484 if(!this.fieldLabel.length){
33485 this.labelEl.hide();
33488 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33489 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33491 this.indicatorEl().addClass('invisible');
33493 this.originalValue = this.getValue();
33497 inputEl: function ()
33499 return this.el.select('.roo-radio-set-input', true).first();
33502 getChildContainer : function()
33504 return this.itemsEl;
33507 register : function(item)
33509 this.radioes.push(item);
33513 validate : function()
33517 Roo.each(this.radioes, function(i){
33526 if(this.allowBlank) {
33530 if(this.disabled || valid){
33535 this.markInvalid();
33540 markValid : function()
33542 if(this.labelEl.isVisible(true)){
33543 this.indicatorEl().removeClass('visible');
33544 this.indicatorEl().addClass('invisible');
33547 this.el.removeClass([this.invalidClass, this.validClass]);
33548 this.el.addClass(this.validClass);
33550 this.fireEvent('valid', this);
33553 markInvalid : function(msg)
33555 if(this.allowBlank || this.disabled){
33559 if(this.labelEl.isVisible(true)){
33560 this.indicatorEl().removeClass('invisible');
33561 this.indicatorEl().addClass('visible');
33564 this.el.removeClass([this.invalidClass, this.validClass]);
33565 this.el.addClass(this.invalidClass);
33567 this.fireEvent('invalid', this, msg);
33571 setValue : function(v, suppressEvent)
33573 if(this.value === v){
33580 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33583 Roo.each(this.radioes, function(i){
33586 i.el.removeClass('checked');
33588 if(i.value === v || i.value.toString() === v.toString()){
33590 i.el.addClass('checked');
33592 if(suppressEvent !== true){
33593 this.fireEvent('check', this, i);
33602 clearInvalid : function(){
33604 if(!this.el || this.preventMark){
33608 this.el.removeClass([this.invalidClass]);
33610 this.fireEvent('valid', this);
33615 Roo.apply(Roo.bootstrap.RadioSet, {
33619 register : function(set)
33621 this.groups[set.name] = set;
33624 get: function(name)
33626 if (typeof(this.groups[name]) == 'undefined') {
33630 return this.groups[name] ;
33636 * Ext JS Library 1.1.1
33637 * Copyright(c) 2006-2007, Ext JS, LLC.
33639 * Originally Released Under LGPL - original licence link has changed is not relivant.
33642 * <script type="text/javascript">
33647 * @class Roo.bootstrap.SplitBar
33648 * @extends Roo.util.Observable
33649 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33653 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33654 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33655 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33656 split.minSize = 100;
33657 split.maxSize = 600;
33658 split.animate = true;
33659 split.on('moved', splitterMoved);
33662 * Create a new SplitBar
33663 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33664 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33665 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33666 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33667 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33668 position of the SplitBar).
33670 Roo.bootstrap.SplitBar = function(cfg){
33675 // dragElement : elm
33676 // resizingElement: el,
33678 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33679 // placement : Roo.bootstrap.SplitBar.LEFT ,
33680 // existingProxy ???
33683 this.el = Roo.get(cfg.dragElement, true);
33684 this.el.dom.unselectable = "on";
33686 this.resizingEl = Roo.get(cfg.resizingElement, true);
33690 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33691 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33694 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33697 * The minimum size of the resizing element. (Defaults to 0)
33703 * The maximum size of the resizing element. (Defaults to 2000)
33706 this.maxSize = 2000;
33709 * Whether to animate the transition to the new size
33712 this.animate = false;
33715 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33718 this.useShim = false;
33723 if(!cfg.existingProxy){
33725 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33727 this.proxy = Roo.get(cfg.existingProxy).dom;
33730 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33733 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33736 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33739 this.dragSpecs = {};
33742 * @private The adapter to use to positon and resize elements
33744 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33745 this.adapter.init(this);
33747 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33749 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33750 this.el.addClass("roo-splitbar-h");
33753 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33754 this.el.addClass("roo-splitbar-v");
33760 * Fires when the splitter is moved (alias for {@link #event-moved})
33761 * @param {Roo.bootstrap.SplitBar} this
33762 * @param {Number} newSize the new width or height
33767 * Fires when the splitter is moved
33768 * @param {Roo.bootstrap.SplitBar} this
33769 * @param {Number} newSize the new width or height
33773 * @event beforeresize
33774 * Fires before the splitter is dragged
33775 * @param {Roo.bootstrap.SplitBar} this
33777 "beforeresize" : true,
33779 "beforeapply" : true
33782 Roo.util.Observable.call(this);
33785 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
33786 onStartProxyDrag : function(x, y){
33787 this.fireEvent("beforeresize", this);
33789 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
33791 o.enableDisplayMode("block");
33792 // all splitbars share the same overlay
33793 Roo.bootstrap.SplitBar.prototype.overlay = o;
33795 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33796 this.overlay.show();
33797 Roo.get(this.proxy).setDisplayed("block");
33798 var size = this.adapter.getElementSize(this);
33799 this.activeMinSize = this.getMinimumSize();;
33800 this.activeMaxSize = this.getMaximumSize();;
33801 var c1 = size - this.activeMinSize;
33802 var c2 = Math.max(this.activeMaxSize - size, 0);
33803 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33804 this.dd.resetConstraints();
33805 this.dd.setXConstraint(
33806 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
33807 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
33809 this.dd.setYConstraint(0, 0);
33811 this.dd.resetConstraints();
33812 this.dd.setXConstraint(0, 0);
33813 this.dd.setYConstraint(
33814 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
33815 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
33818 this.dragSpecs.startSize = size;
33819 this.dragSpecs.startPoint = [x, y];
33820 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
33824 * @private Called after the drag operation by the DDProxy
33826 onEndProxyDrag : function(e){
33827 Roo.get(this.proxy).setDisplayed(false);
33828 var endPoint = Roo.lib.Event.getXY(e);
33830 this.overlay.hide();
33833 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33834 newSize = this.dragSpecs.startSize +
33835 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
33836 endPoint[0] - this.dragSpecs.startPoint[0] :
33837 this.dragSpecs.startPoint[0] - endPoint[0]
33840 newSize = this.dragSpecs.startSize +
33841 (this.placement == Roo.bootstrap.SplitBar.TOP ?
33842 endPoint[1] - this.dragSpecs.startPoint[1] :
33843 this.dragSpecs.startPoint[1] - endPoint[1]
33846 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
33847 if(newSize != this.dragSpecs.startSize){
33848 if(this.fireEvent('beforeapply', this, newSize) !== false){
33849 this.adapter.setElementSize(this, newSize);
33850 this.fireEvent("moved", this, newSize);
33851 this.fireEvent("resize", this, newSize);
33857 * Get the adapter this SplitBar uses
33858 * @return The adapter object
33860 getAdapter : function(){
33861 return this.adapter;
33865 * Set the adapter this SplitBar uses
33866 * @param {Object} adapter A SplitBar adapter object
33868 setAdapter : function(adapter){
33869 this.adapter = adapter;
33870 this.adapter.init(this);
33874 * Gets the minimum size for the resizing element
33875 * @return {Number} The minimum size
33877 getMinimumSize : function(){
33878 return this.minSize;
33882 * Sets the minimum size for the resizing element
33883 * @param {Number} minSize The minimum size
33885 setMinimumSize : function(minSize){
33886 this.minSize = minSize;
33890 * Gets the maximum size for the resizing element
33891 * @return {Number} The maximum size
33893 getMaximumSize : function(){
33894 return this.maxSize;
33898 * Sets the maximum size for the resizing element
33899 * @param {Number} maxSize The maximum size
33901 setMaximumSize : function(maxSize){
33902 this.maxSize = maxSize;
33906 * Sets the initialize size for the resizing element
33907 * @param {Number} size The initial size
33909 setCurrentSize : function(size){
33910 var oldAnimate = this.animate;
33911 this.animate = false;
33912 this.adapter.setElementSize(this, size);
33913 this.animate = oldAnimate;
33917 * Destroy this splitbar.
33918 * @param {Boolean} removeEl True to remove the element
33920 destroy : function(removeEl){
33922 this.shim.remove();
33925 this.proxy.parentNode.removeChild(this.proxy);
33933 * @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.
33935 Roo.bootstrap.SplitBar.createProxy = function(dir){
33936 var proxy = new Roo.Element(document.createElement("div"));
33937 proxy.unselectable();
33938 var cls = 'roo-splitbar-proxy';
33939 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33940 document.body.appendChild(proxy.dom);
33945 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33946 * Default Adapter. It assumes the splitter and resizing element are not positioned
33947 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33949 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33952 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33953 // do nothing for now
33954 init : function(s){
33958 * Called before drag operations to get the current size of the resizing element.
33959 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33961 getElementSize : function(s){
33962 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33963 return s.resizingEl.getWidth();
33965 return s.resizingEl.getHeight();
33970 * Called after drag operations to set the size of the resizing element.
33971 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33972 * @param {Number} newSize The new size to set
33973 * @param {Function} onComplete A function to be invoked when resizing is complete
33975 setElementSize : function(s, newSize, onComplete){
33976 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33978 s.resizingEl.setWidth(newSize);
33980 onComplete(s, newSize);
33983 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33988 s.resizingEl.setHeight(newSize);
33990 onComplete(s, newSize);
33993 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34000 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34001 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34002 * Adapter that moves the splitter element to align with the resized sizing element.
34003 * Used with an absolute positioned SplitBar.
34004 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34005 * document.body, make sure you assign an id to the body element.
34007 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34008 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34009 this.container = Roo.get(container);
34012 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34013 init : function(s){
34014 this.basic.init(s);
34017 getElementSize : function(s){
34018 return this.basic.getElementSize(s);
34021 setElementSize : function(s, newSize, onComplete){
34022 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34025 moveSplitter : function(s){
34026 var yes = Roo.bootstrap.SplitBar;
34027 switch(s.placement){
34029 s.el.setX(s.resizingEl.getRight());
34032 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34035 s.el.setY(s.resizingEl.getBottom());
34038 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34045 * Orientation constant - Create a vertical SplitBar
34049 Roo.bootstrap.SplitBar.VERTICAL = 1;
34052 * Orientation constant - Create a horizontal SplitBar
34056 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34059 * Placement constant - The resizing element is to the left of the splitter element
34063 Roo.bootstrap.SplitBar.LEFT = 1;
34066 * Placement constant - The resizing element is to the right of the splitter element
34070 Roo.bootstrap.SplitBar.RIGHT = 2;
34073 * Placement constant - The resizing element is positioned above the splitter element
34077 Roo.bootstrap.SplitBar.TOP = 3;
34080 * Placement constant - The resizing element is positioned under splitter element
34084 Roo.bootstrap.SplitBar.BOTTOM = 4;
34085 Roo.namespace("Roo.bootstrap.layout");/*
34087 * Ext JS Library 1.1.1
34088 * Copyright(c) 2006-2007, Ext JS, LLC.
34090 * Originally Released Under LGPL - original licence link has changed is not relivant.
34093 * <script type="text/javascript">
34097 * @class Roo.bootstrap.layout.Manager
34098 * @extends Roo.bootstrap.Component
34099 * Base class for layout managers.
34101 Roo.bootstrap.layout.Manager = function(config)
34103 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34109 /** false to disable window resize monitoring @type Boolean */
34110 this.monitorWindowResize = true;
34115 * Fires when a layout is performed.
34116 * @param {Roo.LayoutManager} this
34120 * @event regionresized
34121 * Fires when the user resizes a region.
34122 * @param {Roo.LayoutRegion} region The resized region
34123 * @param {Number} newSize The new size (width for east/west, height for north/south)
34125 "regionresized" : true,
34127 * @event regioncollapsed
34128 * Fires when a region is collapsed.
34129 * @param {Roo.LayoutRegion} region The collapsed region
34131 "regioncollapsed" : true,
34133 * @event regionexpanded
34134 * Fires when a region is expanded.
34135 * @param {Roo.LayoutRegion} region The expanded region
34137 "regionexpanded" : true
34139 this.updating = false;
34142 this.el = Roo.get(config.el);
34148 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34153 monitorWindowResize : true,
34159 onRender : function(ct, position)
34162 this.el = Roo.get(ct);
34165 //this.fireEvent('render',this);
34169 initEvents: function()
34173 // ie scrollbar fix
34174 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34175 document.body.scroll = "no";
34176 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34177 this.el.position('relative');
34179 this.id = this.el.id;
34180 this.el.addClass("roo-layout-container");
34181 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34182 if(this.el.dom != document.body ) {
34183 this.el.on('resize', this.layout,this);
34184 this.el.on('show', this.layout,this);
34190 * Returns true if this layout is currently being updated
34191 * @return {Boolean}
34193 isUpdating : function(){
34194 return this.updating;
34198 * Suspend the LayoutManager from doing auto-layouts while
34199 * making multiple add or remove calls
34201 beginUpdate : function(){
34202 this.updating = true;
34206 * Restore auto-layouts and optionally disable the manager from performing a layout
34207 * @param {Boolean} noLayout true to disable a layout update
34209 endUpdate : function(noLayout){
34210 this.updating = false;
34216 layout: function(){
34220 onRegionResized : function(region, newSize){
34221 this.fireEvent("regionresized", region, newSize);
34225 onRegionCollapsed : function(region){
34226 this.fireEvent("regioncollapsed", region);
34229 onRegionExpanded : function(region){
34230 this.fireEvent("regionexpanded", region);
34234 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34235 * performs box-model adjustments.
34236 * @return {Object} The size as an object {width: (the width), height: (the height)}
34238 getViewSize : function()
34241 if(this.el.dom != document.body){
34242 size = this.el.getSize();
34244 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34246 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34247 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34252 * Returns the Element this layout is bound to.
34253 * @return {Roo.Element}
34255 getEl : function(){
34260 * Returns the specified region.
34261 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34262 * @return {Roo.LayoutRegion}
34264 getRegion : function(target){
34265 return this.regions[target.toLowerCase()];
34268 onWindowResize : function(){
34269 if(this.monitorWindowResize){
34276 * Ext JS Library 1.1.1
34277 * Copyright(c) 2006-2007, Ext JS, LLC.
34279 * Originally Released Under LGPL - original licence link has changed is not relivant.
34282 * <script type="text/javascript">
34285 * @class Roo.bootstrap.layout.Border
34286 * @extends Roo.bootstrap.layout.Manager
34287 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34288 * please see: examples/bootstrap/nested.html<br><br>
34290 <b>The container the layout is rendered into can be either the body element or any other element.
34291 If it is not the body element, the container needs to either be an absolute positioned element,
34292 or you will need to add "position:relative" to the css of the container. You will also need to specify
34293 the container size if it is not the body element.</b>
34296 * Create a new Border
34297 * @param {Object} config Configuration options
34299 Roo.bootstrap.layout.Border = function(config){
34300 config = config || {};
34301 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34305 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34306 if(config[region]){
34307 config[region].region = region;
34308 this.addRegion(config[region]);
34314 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34316 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34318 * Creates and adds a new region if it doesn't already exist.
34319 * @param {String} target The target region key (north, south, east, west or center).
34320 * @param {Object} config The regions config object
34321 * @return {BorderLayoutRegion} The new region
34323 addRegion : function(config)
34325 if(!this.regions[config.region]){
34326 var r = this.factory(config);
34327 this.bindRegion(r);
34329 return this.regions[config.region];
34333 bindRegion : function(r){
34334 this.regions[r.config.region] = r;
34336 r.on("visibilitychange", this.layout, this);
34337 r.on("paneladded", this.layout, this);
34338 r.on("panelremoved", this.layout, this);
34339 r.on("invalidated", this.layout, this);
34340 r.on("resized", this.onRegionResized, this);
34341 r.on("collapsed", this.onRegionCollapsed, this);
34342 r.on("expanded", this.onRegionExpanded, this);
34346 * Performs a layout update.
34348 layout : function()
34350 if(this.updating) {
34354 // render all the rebions if they have not been done alreayd?
34355 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34356 if(this.regions[region] && !this.regions[region].bodyEl){
34357 this.regions[region].onRender(this.el)
34361 var size = this.getViewSize();
34362 var w = size.width;
34363 var h = size.height;
34368 //var x = 0, y = 0;
34370 var rs = this.regions;
34371 var north = rs["north"];
34372 var south = rs["south"];
34373 var west = rs["west"];
34374 var east = rs["east"];
34375 var center = rs["center"];
34376 //if(this.hideOnLayout){ // not supported anymore
34377 //c.el.setStyle("display", "none");
34379 if(north && north.isVisible()){
34380 var b = north.getBox();
34381 var m = north.getMargins();
34382 b.width = w - (m.left+m.right);
34385 centerY = b.height + b.y + m.bottom;
34386 centerH -= centerY;
34387 north.updateBox(this.safeBox(b));
34389 if(south && south.isVisible()){
34390 var b = south.getBox();
34391 var m = south.getMargins();
34392 b.width = w - (m.left+m.right);
34394 var totalHeight = (b.height + m.top + m.bottom);
34395 b.y = h - totalHeight + m.top;
34396 centerH -= totalHeight;
34397 south.updateBox(this.safeBox(b));
34399 if(west && west.isVisible()){
34400 var b = west.getBox();
34401 var m = west.getMargins();
34402 b.height = centerH - (m.top+m.bottom);
34404 b.y = centerY + m.top;
34405 var totalWidth = (b.width + m.left + m.right);
34406 centerX += totalWidth;
34407 centerW -= totalWidth;
34408 west.updateBox(this.safeBox(b));
34410 if(east && east.isVisible()){
34411 var b = east.getBox();
34412 var m = east.getMargins();
34413 b.height = centerH - (m.top+m.bottom);
34414 var totalWidth = (b.width + m.left + m.right);
34415 b.x = w - totalWidth + m.left;
34416 b.y = centerY + m.top;
34417 centerW -= totalWidth;
34418 east.updateBox(this.safeBox(b));
34421 var m = center.getMargins();
34423 x: centerX + m.left,
34424 y: centerY + m.top,
34425 width: centerW - (m.left+m.right),
34426 height: centerH - (m.top+m.bottom)
34428 //if(this.hideOnLayout){
34429 //center.el.setStyle("display", "block");
34431 center.updateBox(this.safeBox(centerBox));
34434 this.fireEvent("layout", this);
34438 safeBox : function(box){
34439 box.width = Math.max(0, box.width);
34440 box.height = Math.max(0, box.height);
34445 * Adds a ContentPanel (or subclass) to this layout.
34446 * @param {String} target The target region key (north, south, east, west or center).
34447 * @param {Roo.ContentPanel} panel The panel to add
34448 * @return {Roo.ContentPanel} The added panel
34450 add : function(target, panel){
34452 target = target.toLowerCase();
34453 return this.regions[target].add(panel);
34457 * Remove a ContentPanel (or subclass) to this layout.
34458 * @param {String} target The target region key (north, south, east, west or center).
34459 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34460 * @return {Roo.ContentPanel} The removed panel
34462 remove : function(target, panel){
34463 target = target.toLowerCase();
34464 return this.regions[target].remove(panel);
34468 * Searches all regions for a panel with the specified id
34469 * @param {String} panelId
34470 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34472 findPanel : function(panelId){
34473 var rs = this.regions;
34474 for(var target in rs){
34475 if(typeof rs[target] != "function"){
34476 var p = rs[target].getPanel(panelId);
34486 * Searches all regions for a panel with the specified id and activates (shows) it.
34487 * @param {String/ContentPanel} panelId The panels id or the panel itself
34488 * @return {Roo.ContentPanel} The shown panel or null
34490 showPanel : function(panelId) {
34491 var rs = this.regions;
34492 for(var target in rs){
34493 var r = rs[target];
34494 if(typeof r != "function"){
34495 if(r.hasPanel(panelId)){
34496 return r.showPanel(panelId);
34504 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34505 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34508 restoreState : function(provider){
34510 provider = Roo.state.Manager;
34512 var sm = new Roo.LayoutStateManager();
34513 sm.init(this, provider);
34519 * Adds a xtype elements to the layout.
34523 xtype : 'ContentPanel',
34530 xtype : 'NestedLayoutPanel',
34536 items : [ ... list of content panels or nested layout panels.. ]
34540 * @param {Object} cfg Xtype definition of item to add.
34542 addxtype : function(cfg)
34544 // basically accepts a pannel...
34545 // can accept a layout region..!?!?
34546 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34549 // theory? children can only be panels??
34551 //if (!cfg.xtype.match(/Panel$/)) {
34556 if (typeof(cfg.region) == 'undefined') {
34557 Roo.log("Failed to add Panel, region was not set");
34561 var region = cfg.region;
34567 xitems = cfg.items;
34574 case 'Content': // ContentPanel (el, cfg)
34575 case 'Scroll': // ContentPanel (el, cfg)
34577 cfg.autoCreate = true;
34578 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34580 // var el = this.el.createChild();
34581 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34584 this.add(region, ret);
34588 case 'TreePanel': // our new panel!
34589 cfg.el = this.el.createChild();
34590 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34591 this.add(region, ret);
34596 // create a new Layout (which is a Border Layout...
34598 var clayout = cfg.layout;
34599 clayout.el = this.el.createChild();
34600 clayout.items = clayout.items || [];
34604 // replace this exitems with the clayout ones..
34605 xitems = clayout.items;
34607 // force background off if it's in center...
34608 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34609 cfg.background = false;
34611 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34614 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34615 //console.log('adding nested layout panel ' + cfg.toSource());
34616 this.add(region, ret);
34617 nb = {}; /// find first...
34622 // needs grid and region
34624 //var el = this.getRegion(region).el.createChild();
34626 *var el = this.el.createChild();
34627 // create the grid first...
34628 cfg.grid.container = el;
34629 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34632 if (region == 'center' && this.active ) {
34633 cfg.background = false;
34636 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34638 this.add(region, ret);
34640 if (cfg.background) {
34641 // render grid on panel activation (if panel background)
34642 ret.on('activate', function(gp) {
34643 if (!gp.grid.rendered) {
34644 // gp.grid.render(el);
34648 // cfg.grid.render(el);
34654 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34655 // it was the old xcomponent building that caused this before.
34656 // espeically if border is the top element in the tree.
34666 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34668 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34669 this.add(region, ret);
34673 throw "Can not add '" + cfg.xtype + "' to Border";
34679 this.beginUpdate();
34683 Roo.each(xitems, function(i) {
34684 region = nb && i.region ? i.region : false;
34686 var add = ret.addxtype(i);
34689 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34690 if (!i.background) {
34691 abn[region] = nb[region] ;
34698 // make the last non-background panel active..
34699 //if (nb) { Roo.log(abn); }
34702 for(var r in abn) {
34703 region = this.getRegion(r);
34705 // tried using nb[r], but it does not work..
34707 region.showPanel(abn[r]);
34718 factory : function(cfg)
34721 var validRegions = Roo.bootstrap.layout.Border.regions;
34723 var target = cfg.region;
34726 var r = Roo.bootstrap.layout;
34730 return new r.North(cfg);
34732 return new r.South(cfg);
34734 return new r.East(cfg);
34736 return new r.West(cfg);
34738 return new r.Center(cfg);
34740 throw 'Layout region "'+target+'" not supported.';
34747 * Ext JS Library 1.1.1
34748 * Copyright(c) 2006-2007, Ext JS, LLC.
34750 * Originally Released Under LGPL - original licence link has changed is not relivant.
34753 * <script type="text/javascript">
34757 * @class Roo.bootstrap.layout.Basic
34758 * @extends Roo.util.Observable
34759 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34760 * and does not have a titlebar, tabs or any other features. All it does is size and position
34761 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34762 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34763 * @cfg {string} region the region that it inhabits..
34764 * @cfg {bool} skipConfig skip config?
34768 Roo.bootstrap.layout.Basic = function(config){
34770 this.mgr = config.mgr;
34772 this.position = config.region;
34774 var skipConfig = config.skipConfig;
34778 * @scope Roo.BasicLayoutRegion
34782 * @event beforeremove
34783 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
34784 * @param {Roo.LayoutRegion} this
34785 * @param {Roo.ContentPanel} panel The panel
34786 * @param {Object} e The cancel event object
34788 "beforeremove" : true,
34790 * @event invalidated
34791 * Fires when the layout for this region is changed.
34792 * @param {Roo.LayoutRegion} this
34794 "invalidated" : true,
34796 * @event visibilitychange
34797 * Fires when this region is shown or hidden
34798 * @param {Roo.LayoutRegion} this
34799 * @param {Boolean} visibility true or false
34801 "visibilitychange" : true,
34803 * @event paneladded
34804 * Fires when a panel is added.
34805 * @param {Roo.LayoutRegion} this
34806 * @param {Roo.ContentPanel} panel The panel
34808 "paneladded" : true,
34810 * @event panelremoved
34811 * Fires when a panel is removed.
34812 * @param {Roo.LayoutRegion} this
34813 * @param {Roo.ContentPanel} panel The panel
34815 "panelremoved" : true,
34817 * @event beforecollapse
34818 * Fires when this region before collapse.
34819 * @param {Roo.LayoutRegion} this
34821 "beforecollapse" : true,
34824 * Fires when this region is collapsed.
34825 * @param {Roo.LayoutRegion} this
34827 "collapsed" : true,
34830 * Fires when this region is expanded.
34831 * @param {Roo.LayoutRegion} this
34836 * Fires when this region is slid into view.
34837 * @param {Roo.LayoutRegion} this
34839 "slideshow" : true,
34842 * Fires when this region slides out of view.
34843 * @param {Roo.LayoutRegion} this
34845 "slidehide" : true,
34847 * @event panelactivated
34848 * Fires when a panel is activated.
34849 * @param {Roo.LayoutRegion} this
34850 * @param {Roo.ContentPanel} panel The activated panel
34852 "panelactivated" : true,
34855 * Fires when the user resizes this region.
34856 * @param {Roo.LayoutRegion} this
34857 * @param {Number} newSize The new size (width for east/west, height for north/south)
34861 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34862 this.panels = new Roo.util.MixedCollection();
34863 this.panels.getKey = this.getPanelId.createDelegate(this);
34865 this.activePanel = null;
34866 // ensure listeners are added...
34868 if (config.listeners || config.events) {
34869 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34870 listeners : config.listeners || {},
34871 events : config.events || {}
34875 if(skipConfig !== true){
34876 this.applyConfig(config);
34880 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34882 getPanelId : function(p){
34886 applyConfig : function(config){
34887 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34888 this.config = config;
34893 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34894 * the width, for horizontal (north, south) the height.
34895 * @param {Number} newSize The new width or height
34897 resizeTo : function(newSize){
34898 var el = this.el ? this.el :
34899 (this.activePanel ? this.activePanel.getEl() : null);
34901 switch(this.position){
34904 el.setWidth(newSize);
34905 this.fireEvent("resized", this, newSize);
34909 el.setHeight(newSize);
34910 this.fireEvent("resized", this, newSize);
34916 getBox : function(){
34917 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34920 getMargins : function(){
34921 return this.margins;
34924 updateBox : function(box){
34926 var el = this.activePanel.getEl();
34927 el.dom.style.left = box.x + "px";
34928 el.dom.style.top = box.y + "px";
34929 this.activePanel.setSize(box.width, box.height);
34933 * Returns the container element for this region.
34934 * @return {Roo.Element}
34936 getEl : function(){
34937 return this.activePanel;
34941 * Returns true if this region is currently visible.
34942 * @return {Boolean}
34944 isVisible : function(){
34945 return this.activePanel ? true : false;
34948 setActivePanel : function(panel){
34949 panel = this.getPanel(panel);
34950 if(this.activePanel && this.activePanel != panel){
34951 this.activePanel.setActiveState(false);
34952 this.activePanel.getEl().setLeftTop(-10000,-10000);
34954 this.activePanel = panel;
34955 panel.setActiveState(true);
34957 panel.setSize(this.box.width, this.box.height);
34959 this.fireEvent("panelactivated", this, panel);
34960 this.fireEvent("invalidated");
34964 * Show the specified panel.
34965 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34966 * @return {Roo.ContentPanel} The shown panel or null
34968 showPanel : function(panel){
34969 panel = this.getPanel(panel);
34971 this.setActivePanel(panel);
34977 * Get the active panel for this region.
34978 * @return {Roo.ContentPanel} The active panel or null
34980 getActivePanel : function(){
34981 return this.activePanel;
34985 * Add the passed ContentPanel(s)
34986 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34987 * @return {Roo.ContentPanel} The panel added (if only one was added)
34989 add : function(panel){
34990 if(arguments.length > 1){
34991 for(var i = 0, len = arguments.length; i < len; i++) {
34992 this.add(arguments[i]);
34996 if(this.hasPanel(panel)){
34997 this.showPanel(panel);
35000 var el = panel.getEl();
35001 if(el.dom.parentNode != this.mgr.el.dom){
35002 this.mgr.el.dom.appendChild(el.dom);
35004 if(panel.setRegion){
35005 panel.setRegion(this);
35007 this.panels.add(panel);
35008 el.setStyle("position", "absolute");
35009 if(!panel.background){
35010 this.setActivePanel(panel);
35011 if(this.config.initialSize && this.panels.getCount()==1){
35012 this.resizeTo(this.config.initialSize);
35015 this.fireEvent("paneladded", this, panel);
35020 * Returns true if the panel is in this region.
35021 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35022 * @return {Boolean}
35024 hasPanel : function(panel){
35025 if(typeof panel == "object"){ // must be panel obj
35026 panel = panel.getId();
35028 return this.getPanel(panel) ? true : false;
35032 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35033 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35034 * @param {Boolean} preservePanel Overrides the config preservePanel option
35035 * @return {Roo.ContentPanel} The panel that was removed
35037 remove : function(panel, preservePanel){
35038 panel = this.getPanel(panel);
35043 this.fireEvent("beforeremove", this, panel, e);
35044 if(e.cancel === true){
35047 var panelId = panel.getId();
35048 this.panels.removeKey(panelId);
35053 * Returns the panel specified or null if it's not in this region.
35054 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35055 * @return {Roo.ContentPanel}
35057 getPanel : function(id){
35058 if(typeof id == "object"){ // must be panel obj
35061 return this.panels.get(id);
35065 * Returns this regions position (north/south/east/west/center).
35068 getPosition: function(){
35069 return this.position;
35073 * Ext JS Library 1.1.1
35074 * Copyright(c) 2006-2007, Ext JS, LLC.
35076 * Originally Released Under LGPL - original licence link has changed is not relivant.
35079 * <script type="text/javascript">
35083 * @class Roo.bootstrap.layout.Region
35084 * @extends Roo.bootstrap.layout.Basic
35085 * This class represents a region in a layout manager.
35087 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35088 * @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})
35089 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35090 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35091 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35092 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35093 * @cfg {String} title The title for the region (overrides panel titles)
35094 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35095 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35096 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35097 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35098 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35099 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35100 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35101 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35102 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35103 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35105 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35106 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35107 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35108 * @cfg {Number} width For East/West panels
35109 * @cfg {Number} height For North/South panels
35110 * @cfg {Boolean} split To show the splitter
35111 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35113 * @cfg {string} cls Extra CSS classes to add to region
35115 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35116 * @cfg {string} region the region that it inhabits..
35119 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35120 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35122 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35123 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35124 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35126 Roo.bootstrap.layout.Region = function(config)
35128 this.applyConfig(config);
35130 var mgr = config.mgr;
35131 var pos = config.region;
35132 config.skipConfig = true;
35133 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35136 this.onRender(mgr.el);
35139 this.visible = true;
35140 this.collapsed = false;
35141 this.unrendered_panels = [];
35144 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35146 position: '', // set by wrapper (eg. north/south etc..)
35147 unrendered_panels : null, // unrendered panels.
35148 createBody : function(){
35149 /** This region's body element
35150 * @type Roo.Element */
35151 this.bodyEl = this.el.createChild({
35153 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35157 onRender: function(ctr, pos)
35159 var dh = Roo.DomHelper;
35160 /** This region's container element
35161 * @type Roo.Element */
35162 this.el = dh.append(ctr.dom, {
35164 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35166 /** This region's title element
35167 * @type Roo.Element */
35169 this.titleEl = dh.append(this.el.dom,
35172 unselectable: "on",
35173 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35175 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35176 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35179 this.titleEl.enableDisplayMode();
35180 /** This region's title text element
35181 * @type HTMLElement */
35182 this.titleTextEl = this.titleEl.dom.firstChild;
35183 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35185 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35186 this.closeBtn.enableDisplayMode();
35187 this.closeBtn.on("click", this.closeClicked, this);
35188 this.closeBtn.hide();
35190 this.createBody(this.config);
35191 if(this.config.hideWhenEmpty){
35193 this.on("paneladded", this.validateVisibility, this);
35194 this.on("panelremoved", this.validateVisibility, this);
35196 if(this.autoScroll){
35197 this.bodyEl.setStyle("overflow", "auto");
35199 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35201 //if(c.titlebar !== false){
35202 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35203 this.titleEl.hide();
35205 this.titleEl.show();
35206 if(this.config.title){
35207 this.titleTextEl.innerHTML = this.config.title;
35211 if(this.config.collapsed){
35212 this.collapse(true);
35214 if(this.config.hidden){
35218 if (this.unrendered_panels && this.unrendered_panels.length) {
35219 for (var i =0;i< this.unrendered_panels.length; i++) {
35220 this.add(this.unrendered_panels[i]);
35222 this.unrendered_panels = null;
35228 applyConfig : function(c)
35231 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35232 var dh = Roo.DomHelper;
35233 if(c.titlebar !== false){
35234 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35235 this.collapseBtn.on("click", this.collapse, this);
35236 this.collapseBtn.enableDisplayMode();
35238 if(c.showPin === true || this.showPin){
35239 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35240 this.stickBtn.enableDisplayMode();
35241 this.stickBtn.on("click", this.expand, this);
35242 this.stickBtn.hide();
35247 /** This region's collapsed element
35248 * @type Roo.Element */
35251 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35252 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35255 if(c.floatable !== false){
35256 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35257 this.collapsedEl.on("click", this.collapseClick, this);
35260 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35261 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35262 id: "message", unselectable: "on", style:{"float":"left"}});
35263 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35265 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35266 this.expandBtn.on("click", this.expand, this);
35270 if(this.collapseBtn){
35271 this.collapseBtn.setVisible(c.collapsible == true);
35274 this.cmargins = c.cmargins || this.cmargins ||
35275 (this.position == "west" || this.position == "east" ?
35276 {top: 0, left: 2, right:2, bottom: 0} :
35277 {top: 2, left: 0, right:0, bottom: 2});
35279 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35282 this.bottomTabs = c.tabPosition != "top";
35284 this.autoScroll = c.autoScroll || false;
35289 this.duration = c.duration || .30;
35290 this.slideDuration = c.slideDuration || .45;
35295 * Returns true if this region is currently visible.
35296 * @return {Boolean}
35298 isVisible : function(){
35299 return this.visible;
35303 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35304 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35306 //setCollapsedTitle : function(title){
35307 // title = title || " ";
35308 // if(this.collapsedTitleTextEl){
35309 // this.collapsedTitleTextEl.innerHTML = title;
35313 getBox : function(){
35315 // if(!this.collapsed){
35316 b = this.el.getBox(false, true);
35318 // b = this.collapsedEl.getBox(false, true);
35323 getMargins : function(){
35324 return this.margins;
35325 //return this.collapsed ? this.cmargins : this.margins;
35328 highlight : function(){
35329 this.el.addClass("x-layout-panel-dragover");
35332 unhighlight : function(){
35333 this.el.removeClass("x-layout-panel-dragover");
35336 updateBox : function(box)
35338 if (!this.bodyEl) {
35339 return; // not rendered yet..
35343 if(!this.collapsed){
35344 this.el.dom.style.left = box.x + "px";
35345 this.el.dom.style.top = box.y + "px";
35346 this.updateBody(box.width, box.height);
35348 this.collapsedEl.dom.style.left = box.x + "px";
35349 this.collapsedEl.dom.style.top = box.y + "px";
35350 this.collapsedEl.setSize(box.width, box.height);
35353 this.tabs.autoSizeTabs();
35357 updateBody : function(w, h)
35360 this.el.setWidth(w);
35361 w -= this.el.getBorderWidth("rl");
35362 if(this.config.adjustments){
35363 w += this.config.adjustments[0];
35366 if(h !== null && h > 0){
35367 this.el.setHeight(h);
35368 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35369 h -= this.el.getBorderWidth("tb");
35370 if(this.config.adjustments){
35371 h += this.config.adjustments[1];
35373 this.bodyEl.setHeight(h);
35375 h = this.tabs.syncHeight(h);
35378 if(this.panelSize){
35379 w = w !== null ? w : this.panelSize.width;
35380 h = h !== null ? h : this.panelSize.height;
35382 if(this.activePanel){
35383 var el = this.activePanel.getEl();
35384 w = w !== null ? w : el.getWidth();
35385 h = h !== null ? h : el.getHeight();
35386 this.panelSize = {width: w, height: h};
35387 this.activePanel.setSize(w, h);
35389 if(Roo.isIE && this.tabs){
35390 this.tabs.el.repaint();
35395 * Returns the container element for this region.
35396 * @return {Roo.Element}
35398 getEl : function(){
35403 * Hides this region.
35406 //if(!this.collapsed){
35407 this.el.dom.style.left = "-2000px";
35410 // this.collapsedEl.dom.style.left = "-2000px";
35411 // this.collapsedEl.hide();
35413 this.visible = false;
35414 this.fireEvent("visibilitychange", this, false);
35418 * Shows this region if it was previously hidden.
35421 //if(!this.collapsed){
35424 // this.collapsedEl.show();
35426 this.visible = true;
35427 this.fireEvent("visibilitychange", this, true);
35430 closeClicked : function(){
35431 if(this.activePanel){
35432 this.remove(this.activePanel);
35436 collapseClick : function(e){
35438 e.stopPropagation();
35441 e.stopPropagation();
35447 * Collapses this region.
35448 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35451 collapse : function(skipAnim, skipCheck = false){
35452 if(this.collapsed) {
35456 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35458 this.collapsed = true;
35460 this.split.el.hide();
35462 if(this.config.animate && skipAnim !== true){
35463 this.fireEvent("invalidated", this);
35464 this.animateCollapse();
35466 this.el.setLocation(-20000,-20000);
35468 this.collapsedEl.show();
35469 this.fireEvent("collapsed", this);
35470 this.fireEvent("invalidated", this);
35476 animateCollapse : function(){
35481 * Expands this region if it was previously collapsed.
35482 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35483 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35486 expand : function(e, skipAnim){
35488 e.stopPropagation();
35490 if(!this.collapsed || this.el.hasActiveFx()) {
35494 this.afterSlideIn();
35497 this.collapsed = false;
35498 if(this.config.animate && skipAnim !== true){
35499 this.animateExpand();
35503 this.split.el.show();
35505 this.collapsedEl.setLocation(-2000,-2000);
35506 this.collapsedEl.hide();
35507 this.fireEvent("invalidated", this);
35508 this.fireEvent("expanded", this);
35512 animateExpand : function(){
35516 initTabs : function()
35518 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35520 var ts = new Roo.bootstrap.panel.Tabs({
35521 el: this.bodyEl.dom,
35522 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35523 disableTooltips: this.config.disableTabTips,
35524 toolbar : this.config.toolbar
35527 if(this.config.hideTabs){
35528 ts.stripWrap.setDisplayed(false);
35531 ts.resizeTabs = this.config.resizeTabs === true;
35532 ts.minTabWidth = this.config.minTabWidth || 40;
35533 ts.maxTabWidth = this.config.maxTabWidth || 250;
35534 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35535 ts.monitorResize = false;
35536 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35537 ts.bodyEl.addClass('roo-layout-tabs-body');
35538 this.panels.each(this.initPanelAsTab, this);
35541 initPanelAsTab : function(panel){
35542 var ti = this.tabs.addTab(
35546 this.config.closeOnTab && panel.isClosable(),
35549 if(panel.tabTip !== undefined){
35550 ti.setTooltip(panel.tabTip);
35552 ti.on("activate", function(){
35553 this.setActivePanel(panel);
35556 if(this.config.closeOnTab){
35557 ti.on("beforeclose", function(t, e){
35559 this.remove(panel);
35563 panel.tabItem = ti;
35568 updatePanelTitle : function(panel, title)
35570 if(this.activePanel == panel){
35571 this.updateTitle(title);
35574 var ti = this.tabs.getTab(panel.getEl().id);
35576 if(panel.tabTip !== undefined){
35577 ti.setTooltip(panel.tabTip);
35582 updateTitle : function(title){
35583 if(this.titleTextEl && !this.config.title){
35584 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35588 setActivePanel : function(panel)
35590 panel = this.getPanel(panel);
35591 if(this.activePanel && this.activePanel != panel){
35592 if(this.activePanel.setActiveState(false) === false){
35596 this.activePanel = panel;
35597 panel.setActiveState(true);
35598 if(this.panelSize){
35599 panel.setSize(this.panelSize.width, this.panelSize.height);
35602 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35604 this.updateTitle(panel.getTitle());
35606 this.fireEvent("invalidated", this);
35608 this.fireEvent("panelactivated", this, panel);
35612 * Shows the specified panel.
35613 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35614 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35616 showPanel : function(panel)
35618 panel = this.getPanel(panel);
35621 var tab = this.tabs.getTab(panel.getEl().id);
35622 if(tab.isHidden()){
35623 this.tabs.unhideTab(tab.id);
35627 this.setActivePanel(panel);
35634 * Get the active panel for this region.
35635 * @return {Roo.ContentPanel} The active panel or null
35637 getActivePanel : function(){
35638 return this.activePanel;
35641 validateVisibility : function(){
35642 if(this.panels.getCount() < 1){
35643 this.updateTitle(" ");
35644 this.closeBtn.hide();
35647 if(!this.isVisible()){
35654 * Adds the passed ContentPanel(s) to this region.
35655 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35656 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35658 add : function(panel)
35660 if(arguments.length > 1){
35661 for(var i = 0, len = arguments.length; i < len; i++) {
35662 this.add(arguments[i]);
35667 // if we have not been rendered yet, then we can not really do much of this..
35668 if (!this.bodyEl) {
35669 this.unrendered_panels.push(panel);
35676 if(this.hasPanel(panel)){
35677 this.showPanel(panel);
35680 panel.setRegion(this);
35681 this.panels.add(panel);
35682 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35683 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35684 // and hide them... ???
35685 this.bodyEl.dom.appendChild(panel.getEl().dom);
35686 if(panel.background !== true){
35687 this.setActivePanel(panel);
35689 this.fireEvent("paneladded", this, panel);
35696 this.initPanelAsTab(panel);
35700 if(panel.background !== true){
35701 this.tabs.activate(panel.getEl().id);
35703 this.fireEvent("paneladded", this, panel);
35708 * Hides the tab for the specified panel.
35709 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35711 hidePanel : function(panel){
35712 if(this.tabs && (panel = this.getPanel(panel))){
35713 this.tabs.hideTab(panel.getEl().id);
35718 * Unhides the tab for a previously hidden panel.
35719 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35721 unhidePanel : function(panel){
35722 if(this.tabs && (panel = this.getPanel(panel))){
35723 this.tabs.unhideTab(panel.getEl().id);
35727 clearPanels : function(){
35728 while(this.panels.getCount() > 0){
35729 this.remove(this.panels.first());
35734 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35735 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35736 * @param {Boolean} preservePanel Overrides the config preservePanel option
35737 * @return {Roo.ContentPanel} The panel that was removed
35739 remove : function(panel, preservePanel)
35741 panel = this.getPanel(panel);
35746 this.fireEvent("beforeremove", this, panel, e);
35747 if(e.cancel === true){
35750 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35751 var panelId = panel.getId();
35752 this.panels.removeKey(panelId);
35754 document.body.appendChild(panel.getEl().dom);
35757 this.tabs.removeTab(panel.getEl().id);
35758 }else if (!preservePanel){
35759 this.bodyEl.dom.removeChild(panel.getEl().dom);
35761 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35762 var p = this.panels.first();
35763 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35764 tempEl.appendChild(p.getEl().dom);
35765 this.bodyEl.update("");
35766 this.bodyEl.dom.appendChild(p.getEl().dom);
35768 this.updateTitle(p.getTitle());
35770 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
35771 this.setActivePanel(p);
35773 panel.setRegion(null);
35774 if(this.activePanel == panel){
35775 this.activePanel = null;
35777 if(this.config.autoDestroy !== false && preservePanel !== true){
35778 try{panel.destroy();}catch(e){}
35780 this.fireEvent("panelremoved", this, panel);
35785 * Returns the TabPanel component used by this region
35786 * @return {Roo.TabPanel}
35788 getTabs : function(){
35792 createTool : function(parentEl, className){
35793 var btn = Roo.DomHelper.append(parentEl, {
35795 cls: "x-layout-tools-button",
35798 cls: "roo-layout-tools-button-inner " + className,
35802 btn.addClassOnOver("roo-layout-tools-button-over");
35807 * Ext JS Library 1.1.1
35808 * Copyright(c) 2006-2007, Ext JS, LLC.
35810 * Originally Released Under LGPL - original licence link has changed is not relivant.
35813 * <script type="text/javascript">
35819 * @class Roo.SplitLayoutRegion
35820 * @extends Roo.LayoutRegion
35821 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
35823 Roo.bootstrap.layout.Split = function(config){
35824 this.cursor = config.cursor;
35825 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
35828 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
35830 splitTip : "Drag to resize.",
35831 collapsibleSplitTip : "Drag to resize. Double click to hide.",
35832 useSplitTips : false,
35834 applyConfig : function(config){
35835 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
35838 onRender : function(ctr,pos) {
35840 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
35841 if(!this.config.split){
35846 var splitEl = Roo.DomHelper.append(ctr.dom, {
35848 id: this.el.id + "-split",
35849 cls: "roo-layout-split roo-layout-split-"+this.position,
35852 /** The SplitBar for this region
35853 * @type Roo.SplitBar */
35854 // does not exist yet...
35855 Roo.log([this.position, this.orientation]);
35857 this.split = new Roo.bootstrap.SplitBar({
35858 dragElement : splitEl,
35859 resizingElement: this.el,
35860 orientation : this.orientation
35863 this.split.on("moved", this.onSplitMove, this);
35864 this.split.useShim = this.config.useShim === true;
35865 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35866 if(this.useSplitTips){
35867 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35869 //if(config.collapsible){
35870 // this.split.el.on("dblclick", this.collapse, this);
35873 if(typeof this.config.minSize != "undefined"){
35874 this.split.minSize = this.config.minSize;
35876 if(typeof this.config.maxSize != "undefined"){
35877 this.split.maxSize = this.config.maxSize;
35879 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35880 this.hideSplitter();
35885 getHMaxSize : function(){
35886 var cmax = this.config.maxSize || 10000;
35887 var center = this.mgr.getRegion("center");
35888 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35891 getVMaxSize : function(){
35892 var cmax = this.config.maxSize || 10000;
35893 var center = this.mgr.getRegion("center");
35894 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35897 onSplitMove : function(split, newSize){
35898 this.fireEvent("resized", this, newSize);
35902 * Returns the {@link Roo.SplitBar} for this region.
35903 * @return {Roo.SplitBar}
35905 getSplitBar : function(){
35910 this.hideSplitter();
35911 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35914 hideSplitter : function(){
35916 this.split.el.setLocation(-2000,-2000);
35917 this.split.el.hide();
35923 this.split.el.show();
35925 Roo.bootstrap.layout.Split.superclass.show.call(this);
35928 beforeSlide: function(){
35929 if(Roo.isGecko){// firefox overflow auto bug workaround
35930 this.bodyEl.clip();
35932 this.tabs.bodyEl.clip();
35934 if(this.activePanel){
35935 this.activePanel.getEl().clip();
35937 if(this.activePanel.beforeSlide){
35938 this.activePanel.beforeSlide();
35944 afterSlide : function(){
35945 if(Roo.isGecko){// firefox overflow auto bug workaround
35946 this.bodyEl.unclip();
35948 this.tabs.bodyEl.unclip();
35950 if(this.activePanel){
35951 this.activePanel.getEl().unclip();
35952 if(this.activePanel.afterSlide){
35953 this.activePanel.afterSlide();
35959 initAutoHide : function(){
35960 if(this.autoHide !== false){
35961 if(!this.autoHideHd){
35962 var st = new Roo.util.DelayedTask(this.slideIn, this);
35963 this.autoHideHd = {
35964 "mouseout": function(e){
35965 if(!e.within(this.el, true)){
35969 "mouseover" : function(e){
35975 this.el.on(this.autoHideHd);
35979 clearAutoHide : function(){
35980 if(this.autoHide !== false){
35981 this.el.un("mouseout", this.autoHideHd.mouseout);
35982 this.el.un("mouseover", this.autoHideHd.mouseover);
35986 clearMonitor : function(){
35987 Roo.get(document).un("click", this.slideInIf, this);
35990 // these names are backwards but not changed for compat
35991 slideOut : function(){
35992 if(this.isSlid || this.el.hasActiveFx()){
35995 this.isSlid = true;
35996 if(this.collapseBtn){
35997 this.collapseBtn.hide();
35999 this.closeBtnState = this.closeBtn.getStyle('display');
36000 this.closeBtn.hide();
36002 this.stickBtn.show();
36005 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36006 this.beforeSlide();
36007 this.el.setStyle("z-index", 10001);
36008 this.el.slideIn(this.getSlideAnchor(), {
36009 callback: function(){
36011 this.initAutoHide();
36012 Roo.get(document).on("click", this.slideInIf, this);
36013 this.fireEvent("slideshow", this);
36020 afterSlideIn : function(){
36021 this.clearAutoHide();
36022 this.isSlid = false;
36023 this.clearMonitor();
36024 this.el.setStyle("z-index", "");
36025 if(this.collapseBtn){
36026 this.collapseBtn.show();
36028 this.closeBtn.setStyle('display', this.closeBtnState);
36030 this.stickBtn.hide();
36032 this.fireEvent("slidehide", this);
36035 slideIn : function(cb){
36036 if(!this.isSlid || this.el.hasActiveFx()){
36040 this.isSlid = false;
36041 this.beforeSlide();
36042 this.el.slideOut(this.getSlideAnchor(), {
36043 callback: function(){
36044 this.el.setLeftTop(-10000, -10000);
36046 this.afterSlideIn();
36054 slideInIf : function(e){
36055 if(!e.within(this.el)){
36060 animateCollapse : function(){
36061 this.beforeSlide();
36062 this.el.setStyle("z-index", 20000);
36063 var anchor = this.getSlideAnchor();
36064 this.el.slideOut(anchor, {
36065 callback : function(){
36066 this.el.setStyle("z-index", "");
36067 this.collapsedEl.slideIn(anchor, {duration:.3});
36069 this.el.setLocation(-10000,-10000);
36071 this.fireEvent("collapsed", this);
36078 animateExpand : function(){
36079 this.beforeSlide();
36080 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36081 this.el.setStyle("z-index", 20000);
36082 this.collapsedEl.hide({
36085 this.el.slideIn(this.getSlideAnchor(), {
36086 callback : function(){
36087 this.el.setStyle("z-index", "");
36090 this.split.el.show();
36092 this.fireEvent("invalidated", this);
36093 this.fireEvent("expanded", this);
36121 getAnchor : function(){
36122 return this.anchors[this.position];
36125 getCollapseAnchor : function(){
36126 return this.canchors[this.position];
36129 getSlideAnchor : function(){
36130 return this.sanchors[this.position];
36133 getAlignAdj : function(){
36134 var cm = this.cmargins;
36135 switch(this.position){
36151 getExpandAdj : function(){
36152 var c = this.collapsedEl, cm = this.cmargins;
36153 switch(this.position){
36155 return [-(cm.right+c.getWidth()+cm.left), 0];
36158 return [cm.right+c.getWidth()+cm.left, 0];
36161 return [0, -(cm.top+cm.bottom+c.getHeight())];
36164 return [0, cm.top+cm.bottom+c.getHeight()];
36170 * Ext JS Library 1.1.1
36171 * Copyright(c) 2006-2007, Ext JS, LLC.
36173 * Originally Released Under LGPL - original licence link has changed is not relivant.
36176 * <script type="text/javascript">
36179 * These classes are private internal classes
36181 Roo.bootstrap.layout.Center = function(config){
36182 config.region = "center";
36183 Roo.bootstrap.layout.Region.call(this, config);
36184 this.visible = true;
36185 this.minWidth = config.minWidth || 20;
36186 this.minHeight = config.minHeight || 20;
36189 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36191 // center panel can't be hidden
36195 // center panel can't be hidden
36198 getMinWidth: function(){
36199 return this.minWidth;
36202 getMinHeight: function(){
36203 return this.minHeight;
36216 Roo.bootstrap.layout.North = function(config)
36218 config.region = 'north';
36219 config.cursor = 'n-resize';
36221 Roo.bootstrap.layout.Split.call(this, config);
36225 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36226 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36227 this.split.el.addClass("roo-layout-split-v");
36229 var size = config.initialSize || config.height;
36230 if(typeof size != "undefined"){
36231 this.el.setHeight(size);
36234 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36236 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36240 getBox : function(){
36241 if(this.collapsed){
36242 return this.collapsedEl.getBox();
36244 var box = this.el.getBox();
36246 box.height += this.split.el.getHeight();
36251 updateBox : function(box){
36252 if(this.split && !this.collapsed){
36253 box.height -= this.split.el.getHeight();
36254 this.split.el.setLeft(box.x);
36255 this.split.el.setTop(box.y+box.height);
36256 this.split.el.setWidth(box.width);
36258 if(this.collapsed){
36259 this.updateBody(box.width, null);
36261 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36269 Roo.bootstrap.layout.South = function(config){
36270 config.region = 'south';
36271 config.cursor = 's-resize';
36272 Roo.bootstrap.layout.Split.call(this, config);
36274 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36275 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36276 this.split.el.addClass("roo-layout-split-v");
36278 var size = config.initialSize || config.height;
36279 if(typeof size != "undefined"){
36280 this.el.setHeight(size);
36284 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36285 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36286 getBox : function(){
36287 if(this.collapsed){
36288 return this.collapsedEl.getBox();
36290 var box = this.el.getBox();
36292 var sh = this.split.el.getHeight();
36299 updateBox : function(box){
36300 if(this.split && !this.collapsed){
36301 var sh = this.split.el.getHeight();
36304 this.split.el.setLeft(box.x);
36305 this.split.el.setTop(box.y-sh);
36306 this.split.el.setWidth(box.width);
36308 if(this.collapsed){
36309 this.updateBody(box.width, null);
36311 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36315 Roo.bootstrap.layout.East = function(config){
36316 config.region = "east";
36317 config.cursor = "e-resize";
36318 Roo.bootstrap.layout.Split.call(this, config);
36320 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36321 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36322 this.split.el.addClass("roo-layout-split-h");
36324 var size = config.initialSize || config.width;
36325 if(typeof size != "undefined"){
36326 this.el.setWidth(size);
36329 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36330 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36331 getBox : function(){
36332 if(this.collapsed){
36333 return this.collapsedEl.getBox();
36335 var box = this.el.getBox();
36337 var sw = this.split.el.getWidth();
36344 updateBox : function(box){
36345 if(this.split && !this.collapsed){
36346 var sw = this.split.el.getWidth();
36348 this.split.el.setLeft(box.x);
36349 this.split.el.setTop(box.y);
36350 this.split.el.setHeight(box.height);
36353 if(this.collapsed){
36354 this.updateBody(null, box.height);
36356 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36360 Roo.bootstrap.layout.West = function(config){
36361 config.region = "west";
36362 config.cursor = "w-resize";
36364 Roo.bootstrap.layout.Split.call(this, config);
36366 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36367 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36368 this.split.el.addClass("roo-layout-split-h");
36372 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36373 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36375 onRender: function(ctr, pos)
36377 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36378 var size = this.config.initialSize || this.config.width;
36379 if(typeof size != "undefined"){
36380 this.el.setWidth(size);
36384 getBox : function(){
36385 if(this.collapsed){
36386 return this.collapsedEl.getBox();
36388 var box = this.el.getBox();
36390 box.width += this.split.el.getWidth();
36395 updateBox : function(box){
36396 if(this.split && !this.collapsed){
36397 var sw = this.split.el.getWidth();
36399 this.split.el.setLeft(box.x+box.width);
36400 this.split.el.setTop(box.y);
36401 this.split.el.setHeight(box.height);
36403 if(this.collapsed){
36404 this.updateBody(null, box.height);
36406 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36409 Roo.namespace("Roo.bootstrap.panel");/*
36411 * Ext JS Library 1.1.1
36412 * Copyright(c) 2006-2007, Ext JS, LLC.
36414 * Originally Released Under LGPL - original licence link has changed is not relivant.
36417 * <script type="text/javascript">
36420 * @class Roo.ContentPanel
36421 * @extends Roo.util.Observable
36422 * A basic ContentPanel element.
36423 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36424 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36425 * @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
36426 * @cfg {Boolean} closable True if the panel can be closed/removed
36427 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36428 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36429 * @cfg {Toolbar} toolbar A toolbar for this panel
36430 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36431 * @cfg {String} title The title for this panel
36432 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36433 * @cfg {String} url Calls {@link #setUrl} with this value
36434 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36435 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36436 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36437 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36438 * @cfg {Boolean} badges render the badges
36441 * Create a new ContentPanel.
36442 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36443 * @param {String/Object} config A string to set only the title or a config object
36444 * @param {String} content (optional) Set the HTML content for this panel
36445 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36447 Roo.bootstrap.panel.Content = function( config){
36449 this.tpl = config.tpl || false;
36451 var el = config.el;
36452 var content = config.content;
36454 if(config.autoCreate){ // xtype is available if this is called from factory
36457 this.el = Roo.get(el);
36458 if(!this.el && config && config.autoCreate){
36459 if(typeof config.autoCreate == "object"){
36460 if(!config.autoCreate.id){
36461 config.autoCreate.id = config.id||el;
36463 this.el = Roo.DomHelper.append(document.body,
36464 config.autoCreate, true);
36466 var elcfg = { tag: "div",
36467 cls: "roo-layout-inactive-content",
36471 elcfg.html = config.html;
36475 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36478 this.closable = false;
36479 this.loaded = false;
36480 this.active = false;
36483 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36485 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36487 this.wrapEl = this.el; //this.el.wrap();
36489 if (config.toolbar.items) {
36490 ti = config.toolbar.items ;
36491 delete config.toolbar.items ;
36495 this.toolbar.render(this.wrapEl, 'before');
36496 for(var i =0;i < ti.length;i++) {
36497 // Roo.log(['add child', items[i]]);
36498 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36500 this.toolbar.items = nitems;
36501 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36502 delete config.toolbar;
36506 // xtype created footer. - not sure if will work as we normally have to render first..
36507 if (this.footer && !this.footer.el && this.footer.xtype) {
36508 if (!this.wrapEl) {
36509 this.wrapEl = this.el.wrap();
36512 this.footer.container = this.wrapEl.createChild();
36514 this.footer = Roo.factory(this.footer, Roo);
36519 if(typeof config == "string"){
36520 this.title = config;
36522 Roo.apply(this, config);
36526 this.resizeEl = Roo.get(this.resizeEl, true);
36528 this.resizeEl = this.el;
36530 // handle view.xtype
36538 * Fires when this panel is activated.
36539 * @param {Roo.ContentPanel} this
36543 * @event deactivate
36544 * Fires when this panel is activated.
36545 * @param {Roo.ContentPanel} this
36547 "deactivate" : true,
36551 * Fires when this panel is resized if fitToFrame is true.
36552 * @param {Roo.ContentPanel} this
36553 * @param {Number} width The width after any component adjustments
36554 * @param {Number} height The height after any component adjustments
36560 * Fires when this tab is created
36561 * @param {Roo.ContentPanel} this
36572 if(this.autoScroll){
36573 this.resizeEl.setStyle("overflow", "auto");
36575 // fix randome scrolling
36576 //this.el.on('scroll', function() {
36577 // Roo.log('fix random scolling');
36578 // this.scrollTo('top',0);
36581 content = content || this.content;
36583 this.setContent(content);
36585 if(config && config.url){
36586 this.setUrl(this.url, this.params, this.loadOnce);
36591 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36593 if (this.view && typeof(this.view.xtype) != 'undefined') {
36594 this.view.el = this.el.appendChild(document.createElement("div"));
36595 this.view = Roo.factory(this.view);
36596 this.view.render && this.view.render(false, '');
36600 this.fireEvent('render', this);
36603 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36607 setRegion : function(region){
36608 this.region = region;
36609 this.setActiveClass(region && !this.background);
36613 setActiveClass: function(state)
36616 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36617 this.el.setStyle('position','relative');
36619 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36620 this.el.setStyle('position', 'absolute');
36625 * Returns the toolbar for this Panel if one was configured.
36626 * @return {Roo.Toolbar}
36628 getToolbar : function(){
36629 return this.toolbar;
36632 setActiveState : function(active)
36634 this.active = active;
36635 this.setActiveClass(active);
36637 if(this.fireEvent("deactivate", this) === false){
36642 this.fireEvent("activate", this);
36646 * Updates this panel's element
36647 * @param {String} content The new content
36648 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36650 setContent : function(content, loadScripts){
36651 this.el.update(content, loadScripts);
36654 ignoreResize : function(w, h){
36655 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36658 this.lastSize = {width: w, height: h};
36663 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36664 * @return {Roo.UpdateManager} The UpdateManager
36666 getUpdateManager : function(){
36667 return this.el.getUpdateManager();
36670 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36671 * @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:
36674 url: "your-url.php",
36675 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36676 callback: yourFunction,
36677 scope: yourObject, //(optional scope)
36680 text: "Loading...",
36685 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36686 * 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.
36687 * @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}
36688 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36689 * @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.
36690 * @return {Roo.ContentPanel} this
36693 var um = this.el.getUpdateManager();
36694 um.update.apply(um, arguments);
36700 * 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.
36701 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36702 * @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)
36703 * @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)
36704 * @return {Roo.UpdateManager} The UpdateManager
36706 setUrl : function(url, params, loadOnce){
36707 if(this.refreshDelegate){
36708 this.removeListener("activate", this.refreshDelegate);
36710 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36711 this.on("activate", this.refreshDelegate);
36712 return this.el.getUpdateManager();
36715 _handleRefresh : function(url, params, loadOnce){
36716 if(!loadOnce || !this.loaded){
36717 var updater = this.el.getUpdateManager();
36718 updater.update(url, params, this._setLoaded.createDelegate(this));
36722 _setLoaded : function(){
36723 this.loaded = true;
36727 * Returns this panel's id
36730 getId : function(){
36735 * Returns this panel's element - used by regiosn to add.
36736 * @return {Roo.Element}
36738 getEl : function(){
36739 return this.wrapEl || this.el;
36744 adjustForComponents : function(width, height)
36746 //Roo.log('adjustForComponents ');
36747 if(this.resizeEl != this.el){
36748 width -= this.el.getFrameWidth('lr');
36749 height -= this.el.getFrameWidth('tb');
36752 var te = this.toolbar.getEl();
36753 te.setWidth(width);
36754 height -= te.getHeight();
36757 var te = this.footer.getEl();
36758 te.setWidth(width);
36759 height -= te.getHeight();
36763 if(this.adjustments){
36764 width += this.adjustments[0];
36765 height += this.adjustments[1];
36767 return {"width": width, "height": height};
36770 setSize : function(width, height){
36771 if(this.fitToFrame && !this.ignoreResize(width, height)){
36772 if(this.fitContainer && this.resizeEl != this.el){
36773 this.el.setSize(width, height);
36775 var size = this.adjustForComponents(width, height);
36776 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
36777 this.fireEvent('resize', this, size.width, size.height);
36782 * Returns this panel's title
36785 getTitle : function(){
36787 if (typeof(this.title) != 'object') {
36792 for (var k in this.title) {
36793 if (!this.title.hasOwnProperty(k)) {
36797 if (k.indexOf('-') >= 0) {
36798 var s = k.split('-');
36799 for (var i = 0; i<s.length; i++) {
36800 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
36803 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
36810 * Set this panel's title
36811 * @param {String} title
36813 setTitle : function(title){
36814 this.title = title;
36816 this.region.updatePanelTitle(this, title);
36821 * Returns true is this panel was configured to be closable
36822 * @return {Boolean}
36824 isClosable : function(){
36825 return this.closable;
36828 beforeSlide : function(){
36830 this.resizeEl.clip();
36833 afterSlide : function(){
36835 this.resizeEl.unclip();
36839 * Force a content refresh from the URL specified in the {@link #setUrl} method.
36840 * Will fail silently if the {@link #setUrl} method has not been called.
36841 * This does not activate the panel, just updates its content.
36843 refresh : function(){
36844 if(this.refreshDelegate){
36845 this.loaded = false;
36846 this.refreshDelegate();
36851 * Destroys this panel
36853 destroy : function(){
36854 this.el.removeAllListeners();
36855 var tempEl = document.createElement("span");
36856 tempEl.appendChild(this.el.dom);
36857 tempEl.innerHTML = "";
36863 * form - if the content panel contains a form - this is a reference to it.
36864 * @type {Roo.form.Form}
36868 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36869 * This contains a reference to it.
36875 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36885 * @param {Object} cfg Xtype definition of item to add.
36889 getChildContainer: function () {
36890 return this.getEl();
36895 var ret = new Roo.factory(cfg);
36900 if (cfg.xtype.match(/^Form$/)) {
36903 //if (this.footer) {
36904 // el = this.footer.container.insertSibling(false, 'before');
36906 el = this.el.createChild();
36909 this.form = new Roo.form.Form(cfg);
36912 if ( this.form.allItems.length) {
36913 this.form.render(el.dom);
36917 // should only have one of theses..
36918 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36919 // views.. should not be just added - used named prop 'view''
36921 cfg.el = this.el.appendChild(document.createElement("div"));
36924 var ret = new Roo.factory(cfg);
36926 ret.render && ret.render(false, ''); // render blank..
36936 * @class Roo.bootstrap.panel.Grid
36937 * @extends Roo.bootstrap.panel.Content
36939 * Create a new GridPanel.
36940 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36941 * @param {Object} config A the config object
36947 Roo.bootstrap.panel.Grid = function(config)
36951 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36952 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36954 config.el = this.wrapper;
36955 //this.el = this.wrapper;
36957 if (config.container) {
36958 // ctor'ed from a Border/panel.grid
36961 this.wrapper.setStyle("overflow", "hidden");
36962 this.wrapper.addClass('roo-grid-container');
36967 if(config.toolbar){
36968 var tool_el = this.wrapper.createChild();
36969 this.toolbar = Roo.factory(config.toolbar);
36971 if (config.toolbar.items) {
36972 ti = config.toolbar.items ;
36973 delete config.toolbar.items ;
36977 this.toolbar.render(tool_el);
36978 for(var i =0;i < ti.length;i++) {
36979 // Roo.log(['add child', items[i]]);
36980 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36982 this.toolbar.items = nitems;
36984 delete config.toolbar;
36987 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36988 config.grid.scrollBody = true;;
36989 config.grid.monitorWindowResize = false; // turn off autosizing
36990 config.grid.autoHeight = false;
36991 config.grid.autoWidth = false;
36993 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36995 if (config.background) {
36996 // render grid on panel activation (if panel background)
36997 this.on('activate', function(gp) {
36998 if (!gp.grid.rendered) {
36999 gp.grid.render(this.wrapper);
37000 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37005 this.grid.render(this.wrapper);
37006 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37009 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37010 // ??? needed ??? config.el = this.wrapper;
37015 // xtype created footer. - not sure if will work as we normally have to render first..
37016 if (this.footer && !this.footer.el && this.footer.xtype) {
37018 var ctr = this.grid.getView().getFooterPanel(true);
37019 this.footer.dataSource = this.grid.dataSource;
37020 this.footer = Roo.factory(this.footer, Roo);
37021 this.footer.render(ctr);
37031 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37032 getId : function(){
37033 return this.grid.id;
37037 * Returns the grid for this panel
37038 * @return {Roo.bootstrap.Table}
37040 getGrid : function(){
37044 setSize : function(width, height){
37045 if(!this.ignoreResize(width, height)){
37046 var grid = this.grid;
37047 var size = this.adjustForComponents(width, height);
37048 var gridel = grid.getGridEl();
37049 gridel.setSize(size.width, size.height);
37051 var thd = grid.getGridEl().select('thead',true).first();
37052 var tbd = grid.getGridEl().select('tbody', true).first();
37054 tbd.setSize(width, height - thd.getHeight());
37063 beforeSlide : function(){
37064 this.grid.getView().scroller.clip();
37067 afterSlide : function(){
37068 this.grid.getView().scroller.unclip();
37071 destroy : function(){
37072 this.grid.destroy();
37074 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37079 * @class Roo.bootstrap.panel.Nest
37080 * @extends Roo.bootstrap.panel.Content
37082 * Create a new Panel, that can contain a layout.Border.
37085 * @param {Roo.BorderLayout} layout The layout for this panel
37086 * @param {String/Object} config A string to set only the title or a config object
37088 Roo.bootstrap.panel.Nest = function(config)
37090 // construct with only one argument..
37091 /* FIXME - implement nicer consturctors
37092 if (layout.layout) {
37094 layout = config.layout;
37095 delete config.layout;
37097 if (layout.xtype && !layout.getEl) {
37098 // then layout needs constructing..
37099 layout = Roo.factory(layout, Roo);
37103 config.el = config.layout.getEl();
37105 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37107 config.layout.monitorWindowResize = false; // turn off autosizing
37108 this.layout = config.layout;
37109 this.layout.getEl().addClass("roo-layout-nested-layout");
37116 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37118 setSize : function(width, height){
37119 if(!this.ignoreResize(width, height)){
37120 var size = this.adjustForComponents(width, height);
37121 var el = this.layout.getEl();
37122 if (size.height < 1) {
37123 el.setWidth(size.width);
37125 el.setSize(size.width, size.height);
37127 var touch = el.dom.offsetWidth;
37128 this.layout.layout();
37129 // ie requires a double layout on the first pass
37130 if(Roo.isIE && !this.initialized){
37131 this.initialized = true;
37132 this.layout.layout();
37137 // activate all subpanels if not currently active..
37139 setActiveState : function(active){
37140 this.active = active;
37141 this.setActiveClass(active);
37144 this.fireEvent("deactivate", this);
37148 this.fireEvent("activate", this);
37149 // not sure if this should happen before or after..
37150 if (!this.layout) {
37151 return; // should not happen..
37154 for (var r in this.layout.regions) {
37155 reg = this.layout.getRegion(r);
37156 if (reg.getActivePanel()) {
37157 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37158 reg.setActivePanel(reg.getActivePanel());
37161 if (!reg.panels.length) {
37164 reg.showPanel(reg.getPanel(0));
37173 * Returns the nested BorderLayout for this panel
37174 * @return {Roo.BorderLayout}
37176 getLayout : function(){
37177 return this.layout;
37181 * Adds a xtype elements to the layout of the nested panel
37185 xtype : 'ContentPanel',
37192 xtype : 'NestedLayoutPanel',
37198 items : [ ... list of content panels or nested layout panels.. ]
37202 * @param {Object} cfg Xtype definition of item to add.
37204 addxtype : function(cfg) {
37205 return this.layout.addxtype(cfg);
37210 * Ext JS Library 1.1.1
37211 * Copyright(c) 2006-2007, Ext JS, LLC.
37213 * Originally Released Under LGPL - original licence link has changed is not relivant.
37216 * <script type="text/javascript">
37219 * @class Roo.TabPanel
37220 * @extends Roo.util.Observable
37221 * A lightweight tab container.
37225 // basic tabs 1, built from existing content
37226 var tabs = new Roo.TabPanel("tabs1");
37227 tabs.addTab("script", "View Script");
37228 tabs.addTab("markup", "View Markup");
37229 tabs.activate("script");
37231 // more advanced tabs, built from javascript
37232 var jtabs = new Roo.TabPanel("jtabs");
37233 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37235 // set up the UpdateManager
37236 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37237 var updater = tab2.getUpdateManager();
37238 updater.setDefaultUrl("ajax1.htm");
37239 tab2.on('activate', updater.refresh, updater, true);
37241 // Use setUrl for Ajax loading
37242 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37243 tab3.setUrl("ajax2.htm", null, true);
37246 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37249 jtabs.activate("jtabs-1");
37252 * Create a new TabPanel.
37253 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37254 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37256 Roo.bootstrap.panel.Tabs = function(config){
37258 * The container element for this TabPanel.
37259 * @type Roo.Element
37261 this.el = Roo.get(config.el);
37264 if(typeof config == "boolean"){
37265 this.tabPosition = config ? "bottom" : "top";
37267 Roo.apply(this, config);
37271 if(this.tabPosition == "bottom"){
37272 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37273 this.el.addClass("roo-tabs-bottom");
37275 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37276 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37277 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37279 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37281 if(this.tabPosition != "bottom"){
37282 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37283 * @type Roo.Element
37285 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37286 this.el.addClass("roo-tabs-top");
37290 this.bodyEl.setStyle("position", "relative");
37292 this.active = null;
37293 this.activateDelegate = this.activate.createDelegate(this);
37298 * Fires when the active tab changes
37299 * @param {Roo.TabPanel} this
37300 * @param {Roo.TabPanelItem} activePanel The new active tab
37304 * @event beforetabchange
37305 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37306 * @param {Roo.TabPanel} this
37307 * @param {Object} e Set cancel to true on this object to cancel the tab change
37308 * @param {Roo.TabPanelItem} tab The tab being changed to
37310 "beforetabchange" : true
37313 Roo.EventManager.onWindowResize(this.onResize, this);
37314 this.cpad = this.el.getPadding("lr");
37315 this.hiddenCount = 0;
37318 // toolbar on the tabbar support...
37319 if (this.toolbar) {
37320 alert("no toolbar support yet");
37321 this.toolbar = false;
37323 var tcfg = this.toolbar;
37324 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37325 this.toolbar = new Roo.Toolbar(tcfg);
37326 if (Roo.isSafari) {
37327 var tbl = tcfg.container.child('table', true);
37328 tbl.setAttribute('width', '100%');
37336 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37339 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37341 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37343 tabPosition : "top",
37345 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37347 currentTabWidth : 0,
37349 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37353 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37357 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37359 preferredTabWidth : 175,
37361 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37363 resizeTabs : false,
37365 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37367 monitorResize : true,
37369 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37374 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37375 * @param {String} id The id of the div to use <b>or create</b>
37376 * @param {String} text The text for the tab
37377 * @param {String} content (optional) Content to put in the TabPanelItem body
37378 * @param {Boolean} closable (optional) True to create a close icon on the tab
37379 * @return {Roo.TabPanelItem} The created TabPanelItem
37381 addTab : function(id, text, content, closable, tpl)
37383 var item = new Roo.bootstrap.panel.TabItem({
37387 closable : closable,
37390 this.addTabItem(item);
37392 item.setContent(content);
37398 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37399 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37400 * @return {Roo.TabPanelItem}
37402 getTab : function(id){
37403 return this.items[id];
37407 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37408 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37410 hideTab : function(id){
37411 var t = this.items[id];
37414 this.hiddenCount++;
37415 this.autoSizeTabs();
37420 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37421 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37423 unhideTab : function(id){
37424 var t = this.items[id];
37426 t.setHidden(false);
37427 this.hiddenCount--;
37428 this.autoSizeTabs();
37433 * Adds an existing {@link Roo.TabPanelItem}.
37434 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37436 addTabItem : function(item){
37437 this.items[item.id] = item;
37438 this.items.push(item);
37439 // if(this.resizeTabs){
37440 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37441 // this.autoSizeTabs();
37443 // item.autoSize();
37448 * Removes a {@link Roo.TabPanelItem}.
37449 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37451 removeTab : function(id){
37452 var items = this.items;
37453 var tab = items[id];
37454 if(!tab) { return; }
37455 var index = items.indexOf(tab);
37456 if(this.active == tab && items.length > 1){
37457 var newTab = this.getNextAvailable(index);
37462 this.stripEl.dom.removeChild(tab.pnode.dom);
37463 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37464 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37466 items.splice(index, 1);
37467 delete this.items[tab.id];
37468 tab.fireEvent("close", tab);
37469 tab.purgeListeners();
37470 this.autoSizeTabs();
37473 getNextAvailable : function(start){
37474 var items = this.items;
37476 // look for a next tab that will slide over to
37477 // replace the one being removed
37478 while(index < items.length){
37479 var item = items[++index];
37480 if(item && !item.isHidden()){
37484 // if one isn't found select the previous tab (on the left)
37487 var item = items[--index];
37488 if(item && !item.isHidden()){
37496 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37497 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37499 disableTab : function(id){
37500 var tab = this.items[id];
37501 if(tab && this.active != tab){
37507 * Enables a {@link Roo.TabPanelItem} that is disabled.
37508 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37510 enableTab : function(id){
37511 var tab = this.items[id];
37516 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37517 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37518 * @return {Roo.TabPanelItem} The TabPanelItem.
37520 activate : function(id){
37521 var tab = this.items[id];
37525 if(tab == this.active || tab.disabled){
37529 this.fireEvent("beforetabchange", this, e, tab);
37530 if(e.cancel !== true && !tab.disabled){
37532 this.active.hide();
37534 this.active = this.items[id];
37535 this.active.show();
37536 this.fireEvent("tabchange", this, this.active);
37542 * Gets the active {@link Roo.TabPanelItem}.
37543 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37545 getActiveTab : function(){
37546 return this.active;
37550 * Updates the tab body element to fit the height of the container element
37551 * for overflow scrolling
37552 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37554 syncHeight : function(targetHeight){
37555 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37556 var bm = this.bodyEl.getMargins();
37557 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37558 this.bodyEl.setHeight(newHeight);
37562 onResize : function(){
37563 if(this.monitorResize){
37564 this.autoSizeTabs();
37569 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37571 beginUpdate : function(){
37572 this.updating = true;
37576 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37578 endUpdate : function(){
37579 this.updating = false;
37580 this.autoSizeTabs();
37584 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37586 autoSizeTabs : function(){
37587 var count = this.items.length;
37588 var vcount = count - this.hiddenCount;
37589 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37592 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37593 var availWidth = Math.floor(w / vcount);
37594 var b = this.stripBody;
37595 if(b.getWidth() > w){
37596 var tabs = this.items;
37597 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37598 if(availWidth < this.minTabWidth){
37599 /*if(!this.sleft){ // incomplete scrolling code
37600 this.createScrollButtons();
37603 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37606 if(this.currentTabWidth < this.preferredTabWidth){
37607 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37613 * Returns the number of tabs in this TabPanel.
37616 getCount : function(){
37617 return this.items.length;
37621 * Resizes all the tabs to the passed width
37622 * @param {Number} The new width
37624 setTabWidth : function(width){
37625 this.currentTabWidth = width;
37626 for(var i = 0, len = this.items.length; i < len; i++) {
37627 if(!this.items[i].isHidden()) {
37628 this.items[i].setWidth(width);
37634 * Destroys this TabPanel
37635 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37637 destroy : function(removeEl){
37638 Roo.EventManager.removeResizeListener(this.onResize, this);
37639 for(var i = 0, len = this.items.length; i < len; i++){
37640 this.items[i].purgeListeners();
37642 if(removeEl === true){
37643 this.el.update("");
37648 createStrip : function(container)
37650 var strip = document.createElement("nav");
37651 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37652 container.appendChild(strip);
37656 createStripList : function(strip)
37658 // div wrapper for retard IE
37659 // returns the "tr" element.
37660 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37661 //'<div class="x-tabs-strip-wrap">'+
37662 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37663 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37664 return strip.firstChild; //.firstChild.firstChild.firstChild;
37666 createBody : function(container)
37668 var body = document.createElement("div");
37669 Roo.id(body, "tab-body");
37670 //Roo.fly(body).addClass("x-tabs-body");
37671 Roo.fly(body).addClass("tab-content");
37672 container.appendChild(body);
37675 createItemBody :function(bodyEl, id){
37676 var body = Roo.getDom(id);
37678 body = document.createElement("div");
37681 //Roo.fly(body).addClass("x-tabs-item-body");
37682 Roo.fly(body).addClass("tab-pane");
37683 bodyEl.insertBefore(body, bodyEl.firstChild);
37687 createStripElements : function(stripEl, text, closable, tpl)
37689 var td = document.createElement("li"); // was td..
37692 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37695 stripEl.appendChild(td);
37697 td.className = "x-tabs-closable";
37698 if(!this.closeTpl){
37699 this.closeTpl = new Roo.Template(
37700 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37701 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37702 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37705 var el = this.closeTpl.overwrite(td, {"text": text});
37706 var close = el.getElementsByTagName("div")[0];
37707 var inner = el.getElementsByTagName("em")[0];
37708 return {"el": el, "close": close, "inner": inner};
37711 // not sure what this is..
37712 // if(!this.tabTpl){
37713 //this.tabTpl = new Roo.Template(
37714 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37715 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37717 // this.tabTpl = new Roo.Template(
37718 // '<a href="#">' +
37719 // '<span unselectable="on"' +
37720 // (this.disableTooltips ? '' : ' title="{text}"') +
37721 // ' >{text}</span></a>'
37727 var template = tpl || this.tabTpl || false;
37731 template = new Roo.Template(
37733 '<span unselectable="on"' +
37734 (this.disableTooltips ? '' : ' title="{text}"') +
37735 ' >{text}</span></a>'
37739 switch (typeof(template)) {
37743 template = new Roo.Template(template);
37749 var el = template.overwrite(td, {"text": text});
37751 var inner = el.getElementsByTagName("span")[0];
37753 return {"el": el, "inner": inner};
37761 * @class Roo.TabPanelItem
37762 * @extends Roo.util.Observable
37763 * Represents an individual item (tab plus body) in a TabPanel.
37764 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37765 * @param {String} id The id of this TabPanelItem
37766 * @param {String} text The text for the tab of this TabPanelItem
37767 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
37769 Roo.bootstrap.panel.TabItem = function(config){
37771 * The {@link Roo.TabPanel} this TabPanelItem belongs to
37772 * @type Roo.TabPanel
37774 this.tabPanel = config.panel;
37776 * The id for this TabPanelItem
37779 this.id = config.id;
37781 this.disabled = false;
37783 this.text = config.text;
37785 this.loaded = false;
37786 this.closable = config.closable;
37789 * The body element for this TabPanelItem.
37790 * @type Roo.Element
37792 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
37793 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
37794 this.bodyEl.setStyle("display", "block");
37795 this.bodyEl.setStyle("zoom", "1");
37796 //this.hideAction();
37798 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
37800 this.el = Roo.get(els.el);
37801 this.inner = Roo.get(els.inner, true);
37802 this.textEl = Roo.get(this.el.dom.firstChild, true);
37803 this.pnode = Roo.get(els.el.parentNode, true);
37804 // this.el.on("mousedown", this.onTabMouseDown, this);
37805 this.el.on("click", this.onTabClick, this);
37807 if(config.closable){
37808 var c = Roo.get(els.close, true);
37809 c.dom.title = this.closeText;
37810 c.addClassOnOver("close-over");
37811 c.on("click", this.closeClick, this);
37817 * Fires when this tab becomes the active tab.
37818 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37819 * @param {Roo.TabPanelItem} this
37823 * @event beforeclose
37824 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
37825 * @param {Roo.TabPanelItem} this
37826 * @param {Object} e Set cancel to true on this object to cancel the close.
37828 "beforeclose": true,
37831 * Fires when this tab is closed.
37832 * @param {Roo.TabPanelItem} this
37836 * @event deactivate
37837 * Fires when this tab is no longer the active tab.
37838 * @param {Roo.TabPanel} tabPanel The parent TabPanel
37839 * @param {Roo.TabPanelItem} this
37841 "deactivate" : true
37843 this.hidden = false;
37845 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
37848 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
37850 purgeListeners : function(){
37851 Roo.util.Observable.prototype.purgeListeners.call(this);
37852 this.el.removeAllListeners();
37855 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37858 this.pnode.addClass("active");
37861 this.tabPanel.stripWrap.repaint();
37863 this.fireEvent("activate", this.tabPanel, this);
37867 * Returns true if this tab is the active tab.
37868 * @return {Boolean}
37870 isActive : function(){
37871 return this.tabPanel.getActiveTab() == this;
37875 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37878 this.pnode.removeClass("active");
37880 this.fireEvent("deactivate", this.tabPanel, this);
37883 hideAction : function(){
37884 this.bodyEl.hide();
37885 this.bodyEl.setStyle("position", "absolute");
37886 this.bodyEl.setLeft("-20000px");
37887 this.bodyEl.setTop("-20000px");
37890 showAction : function(){
37891 this.bodyEl.setStyle("position", "relative");
37892 this.bodyEl.setTop("");
37893 this.bodyEl.setLeft("");
37894 this.bodyEl.show();
37898 * Set the tooltip for the tab.
37899 * @param {String} tooltip The tab's tooltip
37901 setTooltip : function(text){
37902 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37903 this.textEl.dom.qtip = text;
37904 this.textEl.dom.removeAttribute('title');
37906 this.textEl.dom.title = text;
37910 onTabClick : function(e){
37911 e.preventDefault();
37912 this.tabPanel.activate(this.id);
37915 onTabMouseDown : function(e){
37916 e.preventDefault();
37917 this.tabPanel.activate(this.id);
37920 getWidth : function(){
37921 return this.inner.getWidth();
37924 setWidth : function(width){
37925 var iwidth = width - this.pnode.getPadding("lr");
37926 this.inner.setWidth(iwidth);
37927 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37928 this.pnode.setWidth(width);
37932 * Show or hide the tab
37933 * @param {Boolean} hidden True to hide or false to show.
37935 setHidden : function(hidden){
37936 this.hidden = hidden;
37937 this.pnode.setStyle("display", hidden ? "none" : "");
37941 * Returns true if this tab is "hidden"
37942 * @return {Boolean}
37944 isHidden : function(){
37945 return this.hidden;
37949 * Returns the text for this tab
37952 getText : function(){
37956 autoSize : function(){
37957 //this.el.beginMeasure();
37958 this.textEl.setWidth(1);
37960 * #2804 [new] Tabs in Roojs
37961 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37963 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37964 //this.el.endMeasure();
37968 * Sets the text for the tab (Note: this also sets the tooltip text)
37969 * @param {String} text The tab's text and tooltip
37971 setText : function(text){
37973 this.textEl.update(text);
37974 this.setTooltip(text);
37975 //if(!this.tabPanel.resizeTabs){
37976 // this.autoSize();
37980 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37982 activate : function(){
37983 this.tabPanel.activate(this.id);
37987 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37989 disable : function(){
37990 if(this.tabPanel.active != this){
37991 this.disabled = true;
37992 this.pnode.addClass("disabled");
37997 * Enables this TabPanelItem if it was previously disabled.
37999 enable : function(){
38000 this.disabled = false;
38001 this.pnode.removeClass("disabled");
38005 * Sets the content for this TabPanelItem.
38006 * @param {String} content The content
38007 * @param {Boolean} loadScripts true to look for and load scripts
38009 setContent : function(content, loadScripts){
38010 this.bodyEl.update(content, loadScripts);
38014 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38015 * @return {Roo.UpdateManager} The UpdateManager
38017 getUpdateManager : function(){
38018 return this.bodyEl.getUpdateManager();
38022 * Set a URL to be used to load the content for this TabPanelItem.
38023 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38024 * @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)
38025 * @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)
38026 * @return {Roo.UpdateManager} The UpdateManager
38028 setUrl : function(url, params, loadOnce){
38029 if(this.refreshDelegate){
38030 this.un('activate', this.refreshDelegate);
38032 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38033 this.on("activate", this.refreshDelegate);
38034 return this.bodyEl.getUpdateManager();
38038 _handleRefresh : function(url, params, loadOnce){
38039 if(!loadOnce || !this.loaded){
38040 var updater = this.bodyEl.getUpdateManager();
38041 updater.update(url, params, this._setLoaded.createDelegate(this));
38046 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38047 * Will fail silently if the setUrl method has not been called.
38048 * This does not activate the panel, just updates its content.
38050 refresh : function(){
38051 if(this.refreshDelegate){
38052 this.loaded = false;
38053 this.refreshDelegate();
38058 _setLoaded : function(){
38059 this.loaded = true;
38063 closeClick : function(e){
38066 this.fireEvent("beforeclose", this, o);
38067 if(o.cancel !== true){
38068 this.tabPanel.removeTab(this.id);
38072 * The text displayed in the tooltip for the close icon.
38075 closeText : "Close this tab"
38078 * This script refer to:
38079 * Title: International Telephone Input
38080 * Author: Jack O'Connor
38081 * Code version: v12.1.12
38082 * Availability: https://github.com/jackocnr/intl-tel-input.git
38085 Roo.bootstrap.PhoneInputData = function() {
38088 "Afghanistan (افغانستان)",
38093 "Albania (Shqipëri)",
38098 "Algeria (الجزائر)",
38123 "Antigua and Barbuda",
38133 "Armenia (Հայաստան)",
38149 "Austria (Österreich)",
38154 "Azerbaijan (Azərbaycan)",
38164 "Bahrain (البحرين)",
38169 "Bangladesh (বাংলাদেশ)",
38179 "Belarus (Беларусь)",
38184 "Belgium (België)",
38214 "Bosnia and Herzegovina (Босна и Херцеговина)",
38229 "British Indian Ocean Territory",
38234 "British Virgin Islands",
38244 "Bulgaria (България)",
38254 "Burundi (Uburundi)",
38259 "Cambodia (កម្ពុជា)",
38264 "Cameroon (Cameroun)",
38273 ["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"]
38276 "Cape Verde (Kabu Verdi)",
38281 "Caribbean Netherlands",
38292 "Central African Republic (République centrafricaine)",
38312 "Christmas Island",
38318 "Cocos (Keeling) Islands",
38329 "Comoros (جزر القمر)",
38334 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38339 "Congo (Republic) (Congo-Brazzaville)",
38359 "Croatia (Hrvatska)",
38380 "Czech Republic (Česká republika)",
38385 "Denmark (Danmark)",
38400 "Dominican Republic (República Dominicana)",
38404 ["809", "829", "849"]
38422 "Equatorial Guinea (Guinea Ecuatorial)",
38442 "Falkland Islands (Islas Malvinas)",
38447 "Faroe Islands (Føroyar)",
38468 "French Guiana (Guyane française)",
38473 "French Polynesia (Polynésie française)",
38488 "Georgia (საქართველო)",
38493 "Germany (Deutschland)",
38513 "Greenland (Kalaallit Nunaat)",
38550 "Guinea-Bissau (Guiné Bissau)",
38575 "Hungary (Magyarország)",
38580 "Iceland (Ísland)",
38600 "Iraq (العراق)",
38616 "Israel (ישראל)",
38643 "Jordan (الأردن)",
38648 "Kazakhstan (Казахстан)",
38669 "Kuwait (الكويت)",
38674 "Kyrgyzstan (Кыргызстан)",
38684 "Latvia (Latvija)",
38689 "Lebanon (لبنان)",
38704 "Libya (ليبيا)",
38714 "Lithuania (Lietuva)",
38729 "Macedonia (FYROM) (Македонија)",
38734 "Madagascar (Madagasikara)",
38764 "Marshall Islands",
38774 "Mauritania (موريتانيا)",
38779 "Mauritius (Moris)",
38800 "Moldova (Republica Moldova)",
38810 "Mongolia (Монгол)",
38815 "Montenegro (Crna Gora)",
38825 "Morocco (المغرب)",
38831 "Mozambique (Moçambique)",
38836 "Myanmar (Burma) (မြန်မာ)",
38841 "Namibia (Namibië)",
38856 "Netherlands (Nederland)",
38861 "New Caledonia (Nouvelle-Calédonie)",
38896 "North Korea (조선 민주주의 인민 공화국)",
38901 "Northern Mariana Islands",
38917 "Pakistan (پاکستان)",
38927 "Palestine (فلسطين)",
38937 "Papua New Guinea",
38979 "Réunion (La Réunion)",
38985 "Romania (România)",
39001 "Saint Barthélemy",
39012 "Saint Kitts and Nevis",
39022 "Saint Martin (Saint-Martin (partie française))",
39028 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39033 "Saint Vincent and the Grenadines",
39048 "São Tomé and Príncipe (São Tomé e Príncipe)",
39053 "Saudi Arabia (المملكة العربية السعودية)",
39058 "Senegal (Sénégal)",
39088 "Slovakia (Slovensko)",
39093 "Slovenia (Slovenija)",
39103 "Somalia (Soomaaliya)",
39113 "South Korea (대한민국)",
39118 "South Sudan (جنوب السودان)",
39128 "Sri Lanka (ශ්රී ලංකාව)",
39133 "Sudan (السودان)",
39143 "Svalbard and Jan Mayen",
39154 "Sweden (Sverige)",
39159 "Switzerland (Schweiz)",
39164 "Syria (سوريا)",
39209 "Trinidad and Tobago",
39214 "Tunisia (تونس)",
39219 "Turkey (Türkiye)",
39229 "Turks and Caicos Islands",
39239 "U.S. Virgin Islands",
39249 "Ukraine (Україна)",
39254 "United Arab Emirates (الإمارات العربية المتحدة)",
39276 "Uzbekistan (Oʻzbekiston)",
39286 "Vatican City (Città del Vaticano)",
39297 "Vietnam (Việt Nam)",
39302 "Wallis and Futuna (Wallis-et-Futuna)",
39307 "Western Sahara (الصحراء الغربية)",
39313 "Yemen (اليمن)",
39337 * This script refer to:
39338 * Title: International Telephone Input
39339 * Author: Jack O'Connor
39340 * Code version: v12.1.12
39341 * Availability: https://github.com/jackocnr/intl-tel-input.git
39345 * @class Roo.bootstrap.PhoneInput
39346 * @extends Roo.bootstrap.TriggerField
39347 * An input with International dial-code selection
39349 * @cfg {String} defaultDialCode default '+852'
39350 * @cfg {Array} preferedCountries default []
39353 * Create a new PhoneInput.
39354 * @param {Object} config Configuration options
39357 Roo.bootstrap.PhoneInput = function(config) {
39358 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39361 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39363 listWidth: undefined,
39365 selectedClass: 'active',
39367 invalidClass : "has-warning",
39369 validClass: 'has-success',
39371 allowed: '0123456789',
39374 * @cfg {String} defaultDialCode The default dial code when initializing the input
39376 defaultDialCode: '+852',
39379 * @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
39381 preferedCountries: false,
39383 getAutoCreate : function()
39385 var data = Roo.bootstrap.PhoneInputData();
39386 var align = this.labelAlign || this.parentLabelAlign();
39389 this.allCountries = [];
39390 this.dialCodeMapping = [];
39392 for (var i = 0; i < data.length; i++) {
39394 this.allCountries[i] = {
39398 priority: c[3] || 0,
39399 areaCodes: c[4] || null
39401 this.dialCodeMapping[c[2]] = {
39404 priority: c[3] || 0,
39405 areaCodes: c[4] || null
39417 cls : 'form-control tel-input',
39418 autocomplete: 'new-password'
39421 var hiddenInput = {
39424 cls: 'hidden-tel-input'
39428 hiddenInput.name = this.name;
39431 if (this.disabled) {
39432 input.disabled = true;
39435 var flag_container = {
39452 cls: this.hasFeedback ? 'has-feedback' : '',
39458 cls: 'dial-code-holder',
39465 cls: 'roo-select2-container input-group',
39472 if (this.fieldLabel.length) {
39475 tooltip: 'This field is required'
39481 cls: 'control-label',
39487 html: this.fieldLabel
39490 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39496 if(this.indicatorpos == 'right') {
39497 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39504 if(align == 'left') {
39512 if(this.labelWidth > 12){
39513 label.style = "width: " + this.labelWidth + 'px';
39515 if(this.labelWidth < 13 && this.labelmd == 0){
39516 this.labelmd = this.labelWidth;
39518 if(this.labellg > 0){
39519 label.cls += ' col-lg-' + this.labellg;
39520 input.cls += ' col-lg-' + (12 - this.labellg);
39522 if(this.labelmd > 0){
39523 label.cls += ' col-md-' + this.labelmd;
39524 container.cls += ' col-md-' + (12 - this.labelmd);
39526 if(this.labelsm > 0){
39527 label.cls += ' col-sm-' + this.labelsm;
39528 container.cls += ' col-sm-' + (12 - this.labelsm);
39530 if(this.labelxs > 0){
39531 label.cls += ' col-xs-' + this.labelxs;
39532 container.cls += ' col-xs-' + (12 - this.labelxs);
39542 var settings = this;
39544 ['xs','sm','md','lg'].map(function(size){
39545 if (settings[size]) {
39546 cfg.cls += ' col-' + size + '-' + settings[size];
39550 this.store = new Roo.data.Store({
39551 proxy : new Roo.data.MemoryProxy({}),
39552 reader : new Roo.data.JsonReader({
39563 'name' : 'dialCode',
39567 'name' : 'priority',
39571 'name' : 'areaCodes',
39578 if(!this.preferedCountries) {
39579 this.preferedCountries = [
39586 var p = this.preferedCountries.reverse();
39589 for (var i = 0; i < p.length; i++) {
39590 for (var j = 0; j < this.allCountries.length; j++) {
39591 if(this.allCountries[j].iso2 == p[i]) {
39592 var t = this.allCountries[j];
39593 this.allCountries.splice(j,1);
39594 this.allCountries.unshift(t);
39600 this.store.proxy.data = {
39602 data: this.allCountries
39608 initEvents : function()
39611 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39613 this.indicator = this.indicatorEl();
39614 this.flag = this.flagEl();
39615 this.dialCodeHolder = this.dialCodeHolderEl();
39617 this.trigger = this.el.select('div.flag-box',true).first();
39618 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39623 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39624 _this.list.setWidth(lw);
39627 this.list.on('mouseover', this.onViewOver, this);
39628 this.list.on('mousemove', this.onViewMove, this);
39629 this.inputEl().on("keyup", this.onKeyUp, this);
39631 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39633 this.view = new Roo.View(this.list, this.tpl, {
39634 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39637 this.view.on('click', this.onViewClick, this);
39638 this.setValue(this.defaultDialCode);
39641 onTriggerClick : function(e)
39643 Roo.log('trigger click');
39648 if(this.isExpanded()){
39650 this.hasFocus = false;
39652 this.store.load({});
39653 this.hasFocus = true;
39658 isExpanded : function()
39660 return this.list.isVisible();
39663 collapse : function()
39665 if(!this.isExpanded()){
39669 Roo.get(document).un('mousedown', this.collapseIf, this);
39670 Roo.get(document).un('mousewheel', this.collapseIf, this);
39671 this.fireEvent('collapse', this);
39675 expand : function()
39679 if(this.isExpanded() || !this.hasFocus){
39683 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39684 this.list.setWidth(lw);
39687 this.restrictHeight();
39689 Roo.get(document).on('mousedown', this.collapseIf, this);
39690 Roo.get(document).on('mousewheel', this.collapseIf, this);
39692 this.fireEvent('expand', this);
39695 restrictHeight : function()
39697 this.list.alignTo(this.inputEl(), this.listAlign);
39698 this.list.alignTo(this.inputEl(), this.listAlign);
39701 onViewOver : function(e, t)
39703 if(this.inKeyMode){
39706 var item = this.view.findItemFromChild(t);
39709 var index = this.view.indexOf(item);
39710 this.select(index, false);
39715 onViewClick : function(view, doFocus, el, e)
39717 var index = this.view.getSelectedIndexes()[0];
39719 var r = this.store.getAt(index);
39722 this.onSelect(r, index);
39724 if(doFocus !== false && !this.blockFocus){
39725 this.inputEl().focus();
39729 onViewMove : function(e, t)
39731 this.inKeyMode = false;
39734 select : function(index, scrollIntoView)
39736 this.selectedIndex = index;
39737 this.view.select(index);
39738 if(scrollIntoView !== false){
39739 var el = this.view.getNode(index);
39741 this.list.scrollChildIntoView(el, false);
39746 createList : function()
39748 this.list = Roo.get(document.body).createChild({
39750 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39751 style: 'display:none'
39753 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39756 collapseIf : function(e)
39758 var in_combo = e.within(this.el);
39759 var in_list = e.within(this.list);
39760 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39762 if (in_combo || in_list || is_list) {
39768 onSelect : function(record, index)
39770 if(this.fireEvent('beforeselect', this, record, index) !== false){
39772 this.setFlagClass(record.data.iso2);
39773 this.setDialCode(record.data.dialCode);
39774 this.hasFocus = false;
39776 this.fireEvent('select', this, record, index);
39780 flagEl : function()
39782 var flag = this.el.select('div.flag',true).first();
39789 dialCodeHolderEl : function()
39791 var d = this.el.select('input.dial-code-holder',true).first();
39798 setDialCode : function(v)
39800 this.dialCodeHolder.dom.value = '+'+v;
39803 setFlagClass : function(n)
39805 this.flag.dom.className = 'flag '+n;
39808 getValue : function()
39810 var v = this.inputEl().getValue();
39811 if(this.dialCodeHolder) {
39812 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
39817 setValue : function(v)
39819 var d = this.getDialCode(v);
39821 //invalid dial code
39822 if(v.length == 0 || !d || d.length == 0) {
39824 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
39825 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
39831 this.setFlagClass(this.dialCodeMapping[d].iso2);
39832 this.setDialCode(d);
39833 this.inputEl().dom.value = v.replace('+'+d,'');
39834 this.hiddenEl().dom.value = this.getValue();
39839 getDialCode : function(v = '')
39841 if (v.length == 0) {
39842 return this.dialCodeHolder.dom.value;
39846 if (v.charAt(0) != "+") {
39849 var numericChars = "";
39850 for (var i = 1; i < v.length; i++) {
39851 var c = v.charAt(i);
39854 if (this.dialCodeMapping[numericChars]) {
39855 dialCode = v.substr(1, i);
39857 if (numericChars.length == 4) {
39867 this.setValue(this.defaultDialCode);
39871 hiddenEl : function()
39873 return this.el.select('input.hidden-tel-input',true).first();
39876 onKeyUp : function(e){
39878 var k = e.getKey();
39879 var c = e.getCharCode();
39882 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
39883 this.allowed.indexOf(String.fromCharCode(c)) === -1
39888 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39891 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
39895 this.setValue(this.getValue());
39900 * @class Roo.bootstrap.MoneyField
39901 * @extends Roo.bootstrap.ComboBox
39902 * Bootstrap MoneyField class
39905 * Create a new MoneyField.
39906 * @param {Object} config Configuration options
39909 Roo.bootstrap.MoneyField = function(config) {
39911 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
39915 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
39918 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39920 allowDecimals : true,
39922 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39924 decimalSeparator : ".",
39926 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39928 decimalPrecision : 2,
39930 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39932 allowNegative : true,
39934 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39936 minValue : Number.NEGATIVE_INFINITY,
39938 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39940 maxValue : Number.MAX_VALUE,
39942 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39944 minText : "The minimum value for this field is {0}",
39946 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39948 maxText : "The maximum value for this field is {0}",
39950 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39951 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39953 nanText : "{0} is not a valid number",
39955 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
39966 getAutoCreate : function()
39968 var align = this.labelAlign || this.parentLabelAlign();
39980 cls : 'form-control roo-money-amount-input',
39981 autocomplete: 'new-password'
39985 input.name = this.name;
39988 if (this.disabled) {
39989 input.disabled = true;
39992 var clg = 12 - this.inputlg;
39993 var cmd = 12 - this.inputmd;
39994 var csm = 12 - this.inputsm;
39995 var cxs = 12 - this.inputxs;
39999 cls : 'row roo-money-field',
40003 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40007 cls: 'roo-select2-container input-group',
40011 cls : 'form-control roo-money-currency-input',
40012 autocomplete: 'new-password',
40014 name : this.currencyName
40018 cls : 'input-group-addon',
40032 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40036 cls: this.hasFeedback ? 'has-feedback' : '',
40047 if (this.fieldLabel.length) {
40050 tooltip: 'This field is required'
40056 cls: 'control-label',
40062 html: this.fieldLabel
40065 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40071 if(this.indicatorpos == 'right') {
40072 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40079 if(align == 'left') {
40087 if(this.labelWidth > 12){
40088 label.style = "width: " + this.labelWidth + 'px';
40090 if(this.labelWidth < 13 && this.labelmd == 0){
40091 this.labelmd = this.labelWidth;
40093 if(this.labellg > 0){
40094 label.cls += ' col-lg-' + this.labellg;
40095 input.cls += ' col-lg-' + (12 - this.labellg);
40097 if(this.labelmd > 0){
40098 label.cls += ' col-md-' + this.labelmd;
40099 container.cls += ' col-md-' + (12 - this.labelmd);
40101 if(this.labelsm > 0){
40102 label.cls += ' col-sm-' + this.labelsm;
40103 container.cls += ' col-sm-' + (12 - this.labelsm);
40105 if(this.labelxs > 0){
40106 label.cls += ' col-xs-' + this.labelxs;
40107 container.cls += ' col-xs-' + (12 - this.labelxs);
40117 var settings = this;
40119 ['xs','sm','md','lg'].map(function(size){
40120 if (settings[size]) {
40121 cfg.cls += ' col-' + size + '-' + settings[size];
40129 initEvents : function()
40131 this.indicator = this.indicatorEl();
40133 this.initCurrencyEvent();
40135 this.initNumberEvent();
40139 initCurrencyEvent : function()
40142 throw "can not find store for combo";
40145 this.store = Roo.factory(this.store, Roo.data);
40146 this.store.parent = this;
40150 this.triggerEl = this.el.select('.input-group-addon', true).first();
40152 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40157 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40158 _this.list.setWidth(lw);
40161 this.list.on('mouseover', this.onViewOver, this);
40162 this.list.on('mousemove', this.onViewMove, this);
40163 this.list.on('scroll', this.onViewScroll, this);
40166 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40169 this.view = new Roo.View(this.list, this.tpl, {
40170 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40173 this.view.on('click', this.onViewClick, this);
40175 this.store.on('beforeload', this.onBeforeLoad, this);
40176 this.store.on('load', this.onLoad, this);
40177 this.store.on('loadexception', this.onLoadException, this);
40179 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40180 "up" : function(e){
40181 this.inKeyMode = true;
40185 "down" : function(e){
40186 if(!this.isExpanded()){
40187 this.onTriggerClick();
40189 this.inKeyMode = true;
40194 "enter" : function(e){
40197 if(this.fireEvent("specialkey", this, e)){
40198 this.onViewClick(false);
40204 "esc" : function(e){
40208 "tab" : function(e){
40211 if(this.fireEvent("specialkey", this, e)){
40212 this.onViewClick(false);
40220 doRelay : function(foo, bar, hname){
40221 if(hname == 'down' || this.scope.isExpanded()){
40222 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40230 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40234 initNumberEvent : function(e)
40236 this.inputEl().on("keydown" , this.fireKey, this);
40237 this.inputEl().on("focus", this.onFocus, this);
40238 this.inputEl().on("blur", this.onBlur, this);
40240 this.inputEl().relayEvent('keyup', this);
40242 if(this.indicator){
40243 this.indicator.addClass('invisible');
40246 this.originalValue = this.getValue();
40248 if(this.validationEvent == 'keyup'){
40249 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40250 this.inputEl().on('keyup', this.filterValidation, this);
40252 else if(this.validationEvent !== false){
40253 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40256 if(this.selectOnFocus){
40257 this.on("focus", this.preFocus, this);
40260 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40261 this.inputEl().on("keypress", this.filterKeys, this);
40263 this.inputEl().relayEvent('keypress', this);
40266 var allowed = "0123456789";
40268 if(this.allowDecimals){
40269 allowed += this.decimalSeparator;
40272 if(this.allowNegative){
40276 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40278 var keyPress = function(e){
40280 var k = e.getKey();
40282 var c = e.getCharCode();
40285 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40286 allowed.indexOf(String.fromCharCode(c)) === -1
40292 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40296 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40301 this.inputEl().on("keypress", keyPress, this);
40305 onTriggerClick : function(e)
40312 this.loadNext = false;
40314 if(this.isExpanded()){
40319 this.hasFocus = true;
40321 if(this.triggerAction == 'all') {
40322 this.doQuery(this.allQuery, true);
40326 this.doQuery(this.getRawValue());
40329 getCurrency : function()
40331 var v = this.currencyEl().getValue();
40336 restrictHeight : function()
40338 this.list.alignTo(this.currencyEl(), this.listAlign);
40339 this.list.alignTo(this.currencyEl(), this.listAlign);
40342 onViewClick : function(view, doFocus, el, e)
40344 var index = this.view.getSelectedIndexes()[0];
40346 var r = this.store.getAt(index);
40349 this.onSelect(r, index);
40353 onSelect : function(record, index){
40355 if(this.fireEvent('beforeselect', this, record, index) !== false){
40357 this.setFromCurrencyData(index > -1 ? record.data : false);
40361 this.fireEvent('select', this, record, index);
40365 setFromCurrencyData : function(o)
40369 this.lastCurrency = o;
40371 if (this.currencyField) {
40372 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40374 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40377 this.lastSelectionText = currency;
40379 this.setCurrency(currency);
40382 setFromData : function(o)
40386 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40388 this.setFromCurrencyData(c);
40393 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40395 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40398 this.setValue(value);
40402 setCurrency : function(v)
40404 this.currencyValue = v;
40407 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40412 setValue : function(v)
40414 v = this.fixPrecision(v);
40416 v = String(v).replace(".", this.decimalSeparator);
40421 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40426 getRawValue : function()
40428 var v = this.inputEl().getValue();
40433 getValue : function()
40435 return this.fixPrecision(this.parseValue(this.getRawValue()));
40438 parseValue : function(value)
40440 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40441 return isNaN(value) ? '' : value;
40444 fixPrecision : function(value)
40446 var nan = isNaN(value);
40448 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40449 return nan ? '' : value;
40452 return parseFloat(value).toFixed(this.decimalPrecision);
40455 decimalPrecisionFcn : function(v)
40457 return Math.floor(v);
40460 validateValue : function(value)
40462 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40466 var num = this.parseValue(value);
40469 this.markInvalid(String.format(this.nanText, value));
40473 if(num < this.minValue){
40474 this.markInvalid(String.format(this.minText, this.minValue));
40478 if(num > this.maxValue){
40479 this.markInvalid(String.format(this.maxText, this.maxValue));
40486 validate : function()
40488 if(this.disabled || this.allowBlank){
40493 var currency = this.getCurrency();
40495 if(this.validateValue(this.getRawValue()) && currency.length){
40500 this.markInvalid();
40504 getName: function()
40509 beforeBlur : function()
40515 var v = this.parseValue(this.getRawValue());
40522 onBlur : function()
40526 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40527 //this.el.removeClass(this.focusClass);
40530 this.hasFocus = false;
40532 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40536 var v = this.getValue();
40538 if(String(v) !== String(this.startValue)){
40539 this.fireEvent('change', this, v, this.startValue);
40542 this.fireEvent("blur", this);
40545 inputEl : function()
40547 return this.el.select('.roo-money-amount-input', true).first();
40550 currencyEl : function()
40552 return this.el.select('.roo-money-currency-input', true).first();