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)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @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)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme default
564 * @cfg {Boolean} inverse
565 * @cfg {Boolean} toggle
566 * @cfg {String} ontext text for on toggle state
567 * @cfg {String} offtext text for off toggle state
568 * @cfg {Boolean} defaulton
569 * @cfg {Boolean} preventDefault default true
570 * @cfg {Boolean} removeClass remove the standard class..
571 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
574 * Create a new button
575 * @param {Object} config The config object
579 Roo.bootstrap.Button = function(config){
580 Roo.bootstrap.Button.superclass.constructor.call(this, config);
581 this.weightClass = ["btn-default",
593 * When a butotn is pressed
594 * @param {Roo.bootstrap.Button} this
595 * @param {Roo.EventObject} e
600 * After the button has been toggles
601 * @param {Roo.EventObject} e
602 * @param {boolean} pressed (also available as button.pressed)
608 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
626 preventDefault: true,
635 getAutoCreate : function(){
643 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
651 if (this.toggle == true) {
654 cls: 'slider-frame roo-button',
659 'data-off-text':'OFF',
660 cls: 'slider-button',
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' '+this.weight;
676 cfg["aria-hidden"] = true;
678 cfg.html = "×";
684 if (this.theme==='default') {
685 cfg.cls = 'btn roo-button';
687 //if (this.parentType != 'Navbar') {
688 this.weight = this.weight.length ? this.weight : 'default';
690 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
692 cfg.cls += ' btn-' + this.weight;
694 } else if (this.theme==='glow') {
697 cfg.cls = 'btn-glow roo-button';
699 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' ' + this.weight;
707 this.cls += ' inverse';
712 cfg.cls += ' active';
716 cfg.disabled = 'disabled';
720 Roo.log('changing to ul' );
722 this.glyphicon = 'caret';
725 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
727 //gsRoo.log(this.parentType);
728 if (this.parentType === 'Navbar' && !this.parent().bar) {
729 Roo.log('changing to li?');
738 href : this.href || '#'
741 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
742 cfg.cls += ' dropdown';
749 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
751 if (this.glyphicon) {
752 cfg.html = ' ' + cfg.html;
757 cls: 'glyphicon glyphicon-' + this.glyphicon
767 // cfg.cls='btn roo-button';
771 var value = cfg.html;
776 cls: 'glyphicon glyphicon-' + this.glyphicon,
795 cfg.cls += ' dropdown';
796 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
799 if (cfg.tag !== 'a' && this.href !== '') {
800 throw "Tag must be a to set href.";
801 } else if (this.href.length > 0) {
802 cfg.href = this.href;
805 if(this.removeClass){
810 cfg.target = this.target;
815 initEvents: function() {
816 // Roo.log('init events?');
817 // Roo.log(this.el.dom);
820 if (typeof (this.menu) != 'undefined') {
821 this.menu.parentType = this.xtype;
822 this.menu.triggerEl = this.el;
823 this.addxtype(Roo.apply({}, this.menu));
827 if (this.el.hasClass('roo-button')) {
828 this.el.on('click', this.onClick, this);
830 this.el.select('.roo-button').on('click', this.onClick, this);
833 if(this.removeClass){
834 this.el.on('click', this.onClick, this);
837 this.el.enableDisplayMode();
840 onClick : function(e)
847 Roo.log('button on click ');
848 if(this.preventDefault){
851 if (this.pressed === true || this.pressed === false) {
852 this.pressed = !this.pressed;
853 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
854 this.fireEvent('toggle', this, e, this.pressed);
858 this.fireEvent('click', this, e);
862 * Enables this button
866 this.disabled = false;
867 this.el.removeClass('disabled');
871 * Disable this button
875 this.disabled = true;
876 this.el.addClass('disabled');
879 * sets the active state on/off,
880 * @param {Boolean} state (optional) Force a particular state
882 setActive : function(v) {
884 this.el[v ? 'addClass' : 'removeClass']('active');
887 * toggles the current active state
889 toggleActive : function()
891 var active = this.el.hasClass('active');
892 this.setActive(!active);
896 setText : function(str)
898 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
902 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
913 setWeight : function(str)
915 this.el.removeClass(this.weightClass);
916 this.el.addClass('btn-' + str);
930 * @class Roo.bootstrap.Column
931 * @extends Roo.bootstrap.Component
932 * Bootstrap Column class
933 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
934 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
935 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
936 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
937 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
938 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
939 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
940 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
943 * @cfg {Boolean} hidden (true|false) hide the element
944 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
945 * @cfg {String} fa (ban|check|...) font awesome icon
946 * @cfg {Number} fasize (1|2|....) font awsome size
948 * @cfg {String} icon (info-sign|check|...) glyphicon name
950 * @cfg {String} html content of column.
953 * Create a new Column
954 * @param {Object} config The config object
957 Roo.bootstrap.Column = function(config){
958 Roo.bootstrap.Column.superclass.constructor.call(this, config);
961 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
979 getAutoCreate : function(){
980 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
988 ['xs','sm','md','lg'].map(function(size){
989 //Roo.log( size + ':' + settings[size]);
991 if (settings[size+'off'] !== false) {
992 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
995 if (settings[size] === false) {
999 if (!settings[size]) { // 0 = hidden
1000 cfg.cls += ' hidden-' + size;
1003 cfg.cls += ' col-' + size + '-' + settings[size];
1008 cfg.cls += ' hidden';
1011 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1012 cfg.cls +=' alert alert-' + this.alert;
1016 if (this.html.length) {
1017 cfg.html = this.html;
1021 if (this.fasize > 1) {
1022 fasize = ' fa-' + this.fasize + 'x';
1024 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1029 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1048 * @class Roo.bootstrap.Container
1049 * @extends Roo.bootstrap.Component
1050 * Bootstrap Container class
1051 * @cfg {Boolean} jumbotron is it a jumbotron element
1052 * @cfg {String} html content of element
1053 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1054 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1055 * @cfg {String} header content of header (for panel)
1056 * @cfg {String} footer content of footer (for panel)
1057 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1058 * @cfg {String} tag (header|aside|section) type of HTML tag.
1059 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1060 * @cfg {String} fa font awesome icon
1061 * @cfg {String} icon (info-sign|check|...) glyphicon name
1062 * @cfg {Boolean} hidden (true|false) hide the element
1063 * @cfg {Boolean} expandable (true|false) default false
1064 * @cfg {Boolean} expanded (true|false) default true
1065 * @cfg {String} rheader contet on the right of header
1066 * @cfg {Boolean} clickable (true|false) default false
1070 * Create a new Container
1071 * @param {Object} config The config object
1074 Roo.bootstrap.Container = function(config){
1075 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1081 * After the panel has been expand
1083 * @param {Roo.bootstrap.Container} this
1088 * After the panel has been collapsed
1090 * @param {Roo.bootstrap.Container} this
1095 * When a element is chick
1096 * @param {Roo.bootstrap.Container} this
1097 * @param {Roo.EventObject} e
1103 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1121 getChildContainer : function() {
1127 if (this.panel.length) {
1128 return this.el.select('.panel-body',true).first();
1135 getAutoCreate : function(){
1138 tag : this.tag || 'div',
1142 if (this.jumbotron) {
1143 cfg.cls = 'jumbotron';
1148 // - this is applied by the parent..
1150 // cfg.cls = this.cls + '';
1153 if (this.sticky.length) {
1155 var bd = Roo.get(document.body);
1156 if (!bd.hasClass('bootstrap-sticky')) {
1157 bd.addClass('bootstrap-sticky');
1158 Roo.select('html',true).setStyle('height', '100%');
1161 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1165 if (this.well.length) {
1166 switch (this.well) {
1169 cfg.cls +=' well well-' +this.well;
1178 cfg.cls += ' hidden';
1182 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1183 cfg.cls +=' alert alert-' + this.alert;
1188 if (this.panel.length) {
1189 cfg.cls += ' panel panel-' + this.panel;
1191 if (this.header.length) {
1195 if(this.expandable){
1197 cfg.cls = cfg.cls + ' expandable';
1201 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1209 cls : 'panel-title',
1210 html : (this.expandable ? ' ' : '') + this.header
1214 cls: 'panel-header-right',
1220 cls : 'panel-heading',
1221 style : this.expandable ? 'cursor: pointer' : '',
1229 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1234 if (this.footer.length) {
1236 cls : 'panel-footer',
1245 body.html = this.html || cfg.html;
1246 // prefix with the icons..
1248 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1251 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1256 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1257 cfg.cls = 'container';
1263 initEvents: function()
1265 if(this.expandable){
1266 var headerEl = this.headerEl();
1269 headerEl.on('click', this.onToggleClick, this);
1274 this.el.on('click', this.onClick, this);
1279 onToggleClick : function()
1281 var headerEl = this.headerEl();
1297 if(this.fireEvent('expand', this)) {
1299 this.expanded = true;
1301 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1303 this.el.select('.panel-body',true).first().removeClass('hide');
1305 var toggleEl = this.toggleEl();
1311 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1316 collapse : function()
1318 if(this.fireEvent('collapse', this)) {
1320 this.expanded = false;
1322 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1323 this.el.select('.panel-body',true).first().addClass('hide');
1325 var toggleEl = this.toggleEl();
1331 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1335 toggleEl : function()
1337 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1341 return this.el.select('.panel-heading .fa',true).first();
1344 headerEl : function()
1346 if(!this.el || !this.panel.length || !this.header.length){
1350 return this.el.select('.panel-heading',true).first()
1355 if(!this.el || !this.panel.length){
1359 return this.el.select('.panel-body',true).first()
1362 titleEl : function()
1364 if(!this.el || !this.panel.length || !this.header.length){
1368 return this.el.select('.panel-title',true).first();
1371 setTitle : function(v)
1373 var titleEl = this.titleEl();
1379 titleEl.dom.innerHTML = v;
1382 getTitle : function()
1385 var titleEl = this.titleEl();
1391 return titleEl.dom.innerHTML;
1394 setRightTitle : function(v)
1396 var t = this.el.select('.panel-header-right',true).first();
1402 t.dom.innerHTML = v;
1405 onClick : function(e)
1409 this.fireEvent('click', this, e);
1422 * @class Roo.bootstrap.Img
1423 * @extends Roo.bootstrap.Component
1424 * Bootstrap Img class
1425 * @cfg {Boolean} imgResponsive false | true
1426 * @cfg {String} border rounded | circle | thumbnail
1427 * @cfg {String} src image source
1428 * @cfg {String} alt image alternative text
1429 * @cfg {String} href a tag href
1430 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1431 * @cfg {String} xsUrl xs image source
1432 * @cfg {String} smUrl sm image source
1433 * @cfg {String} mdUrl md image source
1434 * @cfg {String} lgUrl lg image source
1437 * Create a new Input
1438 * @param {Object} config The config object
1441 Roo.bootstrap.Img = function(config){
1442 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1448 * The img click event for the img.
1449 * @param {Roo.EventObject} e
1455 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1457 imgResponsive: true,
1467 getAutoCreate : function()
1469 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1470 return this.createSingleImg();
1475 cls: 'roo-image-responsive-group',
1480 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1482 if(!_this[size + 'Url']){
1488 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1489 html: _this.html || cfg.html,
1490 src: _this[size + 'Url']
1493 img.cls += ' roo-image-responsive-' + size;
1495 var s = ['xs', 'sm', 'md', 'lg'];
1497 s.splice(s.indexOf(size), 1);
1499 Roo.each(s, function(ss){
1500 img.cls += ' hidden-' + ss;
1503 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1504 cfg.cls += ' img-' + _this.border;
1508 cfg.alt = _this.alt;
1521 a.target = _this.target;
1525 cfg.cn.push((_this.href) ? a : img);
1532 createSingleImg : function()
1536 cls: (this.imgResponsive) ? 'img-responsive' : '',
1538 src : 'about:blank' // just incase src get's set to undefined?!?
1541 cfg.html = this.html || cfg.html;
1543 cfg.src = this.src || cfg.src;
1545 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1546 cfg.cls += ' img-' + this.border;
1563 a.target = this.target;
1568 return (this.href) ? a : cfg;
1571 initEvents: function()
1574 this.el.on('click', this.onClick, this);
1579 onClick : function(e)
1581 Roo.log('img onclick');
1582 this.fireEvent('click', this, e);
1585 * Sets the url of the image - used to update it
1586 * @param {String} url the url of the image
1589 setSrc : function(url)
1593 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1594 this.el.dom.src = url;
1598 this.el.select('img', true).first().dom.src = url;
1614 * @class Roo.bootstrap.Link
1615 * @extends Roo.bootstrap.Component
1616 * Bootstrap Link Class
1617 * @cfg {String} alt image alternative text
1618 * @cfg {String} href a tag href
1619 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1620 * @cfg {String} html the content of the link.
1621 * @cfg {String} anchor name for the anchor link
1622 * @cfg {String} fa - favicon
1624 * @cfg {Boolean} preventDefault (true | false) default false
1628 * Create a new Input
1629 * @param {Object} config The config object
1632 Roo.bootstrap.Link = function(config){
1633 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1639 * The img click event for the img.
1640 * @param {Roo.EventObject} e
1646 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1650 preventDefault: false,
1656 getAutoCreate : function()
1658 var html = this.html || '';
1660 if (this.fa !== false) {
1661 html = '<i class="fa fa-' + this.fa + '"></i>';
1666 // anchor's do not require html/href...
1667 if (this.anchor === false) {
1669 cfg.href = this.href || '#';
1671 cfg.name = this.anchor;
1672 if (this.html !== false || this.fa !== false) {
1675 if (this.href !== false) {
1676 cfg.href = this.href;
1680 if(this.alt !== false){
1685 if(this.target !== false) {
1686 cfg.target = this.target;
1692 initEvents: function() {
1694 if(!this.href || this.preventDefault){
1695 this.el.on('click', this.onClick, this);
1699 onClick : function(e)
1701 if(this.preventDefault){
1704 //Roo.log('img onclick');
1705 this.fireEvent('click', this, e);
1718 * @class Roo.bootstrap.Header
1719 * @extends Roo.bootstrap.Component
1720 * Bootstrap Header class
1721 * @cfg {String} html content of header
1722 * @cfg {Number} level (1|2|3|4|5|6) default 1
1725 * Create a new Header
1726 * @param {Object} config The config object
1730 Roo.bootstrap.Header = function(config){
1731 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1734 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1742 getAutoCreate : function(){
1747 tag: 'h' + (1 *this.level),
1748 html: this.html || ''
1760 * Ext JS Library 1.1.1
1761 * Copyright(c) 2006-2007, Ext JS, LLC.
1763 * Originally Released Under LGPL - original licence link has changed is not relivant.
1766 * <script type="text/javascript">
1770 * @class Roo.bootstrap.MenuMgr
1771 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1774 Roo.bootstrap.MenuMgr = function(){
1775 var menus, active, groups = {}, attached = false, lastShow = new Date();
1777 // private - called when first menu is created
1780 active = new Roo.util.MixedCollection();
1781 Roo.get(document).addKeyListener(27, function(){
1782 if(active.length > 0){
1790 if(active && active.length > 0){
1791 var c = active.clone();
1801 if(active.length < 1){
1802 Roo.get(document).un("mouseup", onMouseDown);
1810 var last = active.last();
1811 lastShow = new Date();
1814 Roo.get(document).on("mouseup", onMouseDown);
1819 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1820 m.parentMenu.activeChild = m;
1821 }else if(last && last.isVisible()){
1822 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1827 function onBeforeHide(m){
1829 m.activeChild.hide();
1831 if(m.autoHideTimer){
1832 clearTimeout(m.autoHideTimer);
1833 delete m.autoHideTimer;
1838 function onBeforeShow(m){
1839 var pm = m.parentMenu;
1840 if(!pm && !m.allowOtherMenus){
1842 }else if(pm && pm.activeChild && active != m){
1843 pm.activeChild.hide();
1847 // private this should really trigger on mouseup..
1848 function onMouseDown(e){
1849 Roo.log("on Mouse Up");
1851 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1852 Roo.log("MenuManager hideAll");
1861 function onBeforeCheck(mi, state){
1863 var g = groups[mi.group];
1864 for(var i = 0, l = g.length; i < l; i++){
1866 g[i].setChecked(false);
1875 * Hides all menus that are currently visible
1877 hideAll : function(){
1882 register : function(menu){
1886 menus[menu.id] = menu;
1887 menu.on("beforehide", onBeforeHide);
1888 menu.on("hide", onHide);
1889 menu.on("beforeshow", onBeforeShow);
1890 menu.on("show", onShow);
1892 if(g && menu.events["checkchange"]){
1896 groups[g].push(menu);
1897 menu.on("checkchange", onCheck);
1902 * Returns a {@link Roo.menu.Menu} object
1903 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1904 * be used to generate and return a new Menu instance.
1906 get : function(menu){
1907 if(typeof menu == "string"){ // menu id
1909 }else if(menu.events){ // menu instance
1912 /*else if(typeof menu.length == 'number'){ // array of menu items?
1913 return new Roo.bootstrap.Menu({items:menu});
1914 }else{ // otherwise, must be a config
1915 return new Roo.bootstrap.Menu(menu);
1922 unregister : function(menu){
1923 delete menus[menu.id];
1924 menu.un("beforehide", onBeforeHide);
1925 menu.un("hide", onHide);
1926 menu.un("beforeshow", onBeforeShow);
1927 menu.un("show", onShow);
1929 if(g && menu.events["checkchange"]){
1930 groups[g].remove(menu);
1931 menu.un("checkchange", onCheck);
1936 registerCheckable : function(menuItem){
1937 var g = menuItem.group;
1942 groups[g].push(menuItem);
1943 menuItem.on("beforecheckchange", onBeforeCheck);
1948 unregisterCheckable : function(menuItem){
1949 var g = menuItem.group;
1951 groups[g].remove(menuItem);
1952 menuItem.un("beforecheckchange", onBeforeCheck);
1964 * @class Roo.bootstrap.Menu
1965 * @extends Roo.bootstrap.Component
1966 * Bootstrap Menu class - container for MenuItems
1967 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1968 * @cfg {bool} hidden if the menu should be hidden when rendered.
1969 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1970 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1974 * @param {Object} config The config object
1978 Roo.bootstrap.Menu = function(config){
1979 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1980 if (this.registerMenu && this.type != 'treeview') {
1981 Roo.bootstrap.MenuMgr.register(this);
1986 * Fires before this menu is displayed
1987 * @param {Roo.menu.Menu} this
1992 * Fires before this menu is hidden
1993 * @param {Roo.menu.Menu} this
1998 * Fires after this menu is displayed
1999 * @param {Roo.menu.Menu} this
2004 * Fires after this menu is hidden
2005 * @param {Roo.menu.Menu} this
2010 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2011 * @param {Roo.menu.Menu} this
2012 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2013 * @param {Roo.EventObject} e
2018 * Fires when the mouse is hovering over this menu
2019 * @param {Roo.menu.Menu} this
2020 * @param {Roo.EventObject} e
2021 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2026 * Fires when the mouse exits this menu
2027 * @param {Roo.menu.Menu} this
2028 * @param {Roo.EventObject} e
2029 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2034 * Fires when a menu item contained in this menu is clicked
2035 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2036 * @param {Roo.EventObject} e
2040 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2043 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2047 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2050 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2052 registerMenu : true,
2054 menuItems :false, // stores the menu items..
2064 getChildContainer : function() {
2068 getAutoCreate : function(){
2070 //if (['right'].indexOf(this.align)!==-1) {
2071 // cfg.cn[1].cls += ' pull-right'
2077 cls : 'dropdown-menu' ,
2078 style : 'z-index:1000'
2082 if (this.type === 'submenu') {
2083 cfg.cls = 'submenu active';
2085 if (this.type === 'treeview') {
2086 cfg.cls = 'treeview-menu';
2091 initEvents : function() {
2093 // Roo.log("ADD event");
2094 // Roo.log(this.triggerEl.dom);
2096 this.triggerEl.on('click', this.onTriggerClick, this);
2098 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2100 this.triggerEl.addClass('dropdown-toggle');
2103 this.el.on('touchstart' , this.onTouch, this);
2105 this.el.on('click' , this.onClick, this);
2107 this.el.on("mouseover", this.onMouseOver, this);
2108 this.el.on("mouseout", this.onMouseOut, this);
2112 findTargetItem : function(e)
2114 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2118 //Roo.log(t); Roo.log(t.id);
2120 //Roo.log(this.menuitems);
2121 return this.menuitems.get(t.id);
2123 //return this.items.get(t.menuItemId);
2129 onTouch : function(e)
2131 Roo.log("menu.onTouch");
2132 //e.stopEvent(); this make the user popdown broken
2136 onClick : function(e)
2138 Roo.log("menu.onClick");
2140 var t = this.findTargetItem(e);
2141 if(!t || t.isContainer){
2146 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2147 if(t == this.activeItem && t.shouldDeactivate(e)){
2148 this.activeItem.deactivate();
2149 delete this.activeItem;
2153 this.setActiveItem(t, true);
2161 Roo.log('pass click event');
2165 this.fireEvent("click", this, t, e);
2169 if(!t.href.length || t.href == '#'){
2170 (function() { _this.hide(); }).defer(100);
2175 onMouseOver : function(e){
2176 var t = this.findTargetItem(e);
2179 // if(t.canActivate && !t.disabled){
2180 // this.setActiveItem(t, true);
2184 this.fireEvent("mouseover", this, e, t);
2186 isVisible : function(){
2187 return !this.hidden;
2189 onMouseOut : function(e){
2190 var t = this.findTargetItem(e);
2193 // if(t == this.activeItem && t.shouldDeactivate(e)){
2194 // this.activeItem.deactivate();
2195 // delete this.activeItem;
2198 this.fireEvent("mouseout", this, e, t);
2203 * Displays this menu relative to another element
2204 * @param {String/HTMLElement/Roo.Element} element The element to align to
2205 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2206 * the element (defaults to this.defaultAlign)
2207 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2209 show : function(el, pos, parentMenu){
2210 this.parentMenu = parentMenu;
2214 this.fireEvent("beforeshow", this);
2215 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2218 * Displays this menu at a specific xy position
2219 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2220 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2222 showAt : function(xy, parentMenu, /* private: */_e){
2223 this.parentMenu = parentMenu;
2228 this.fireEvent("beforeshow", this);
2229 //xy = this.el.adjustForConstraints(xy);
2233 this.hideMenuItems();
2234 this.hidden = false;
2235 this.triggerEl.addClass('open');
2237 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2238 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2241 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2246 this.fireEvent("show", this);
2252 this.doFocus.defer(50, this);
2256 doFocus : function(){
2258 this.focusEl.focus();
2263 * Hides this menu and optionally all parent menus
2264 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2266 hide : function(deep)
2269 this.hideMenuItems();
2270 if(this.el && this.isVisible()){
2271 this.fireEvent("beforehide", this);
2272 if(this.activeItem){
2273 this.activeItem.deactivate();
2274 this.activeItem = null;
2276 this.triggerEl.removeClass('open');;
2278 this.fireEvent("hide", this);
2280 if(deep === true && this.parentMenu){
2281 this.parentMenu.hide(true);
2285 onTriggerClick : function(e)
2287 Roo.log('trigger click');
2289 var target = e.getTarget();
2291 Roo.log(target.nodeName.toLowerCase());
2293 if(target.nodeName.toLowerCase() === 'i'){
2299 onTriggerPress : function(e)
2301 Roo.log('trigger press');
2302 //Roo.log(e.getTarget());
2303 // Roo.log(this.triggerEl.dom);
2305 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2306 var pel = Roo.get(e.getTarget());
2307 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2308 Roo.log('is treeview or dropdown?');
2312 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2316 if (this.isVisible()) {
2321 this.show(this.triggerEl, false, false);
2324 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2331 hideMenuItems : function()
2333 Roo.log("hide Menu Items");
2337 //$(backdrop).remove()
2338 this.el.select('.open',true).each(function(aa) {
2340 aa.removeClass('open');
2341 //var parent = getParent($(this))
2342 //var relatedTarget = { relatedTarget: this }
2344 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2345 //if (e.isDefaultPrevented()) return
2346 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2349 addxtypeChild : function (tree, cntr) {
2350 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2352 this.menuitems.add(comp);
2364 this.getEl().dom.innerHTML = '';
2365 this.menuitems.clear();
2379 * @class Roo.bootstrap.MenuItem
2380 * @extends Roo.bootstrap.Component
2381 * Bootstrap MenuItem class
2382 * @cfg {String} html the menu label
2383 * @cfg {String} href the link
2384 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2385 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2386 * @cfg {Boolean} active used on sidebars to highlight active itesm
2387 * @cfg {String} fa favicon to show on left of menu item.
2388 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2392 * Create a new MenuItem
2393 * @param {Object} config The config object
2397 Roo.bootstrap.MenuItem = function(config){
2398 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2403 * The raw click event for the entire grid.
2404 * @param {Roo.bootstrap.MenuItem} this
2405 * @param {Roo.EventObject} e
2411 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2415 preventDefault: false,
2416 isContainer : false,
2420 getAutoCreate : function(){
2422 if(this.isContainer){
2425 cls: 'dropdown-menu-item'
2439 if (this.fa !== false) {
2442 cls : 'fa fa-' + this.fa
2451 cls: 'dropdown-menu-item',
2454 if (this.parent().type == 'treeview') {
2455 cfg.cls = 'treeview-menu';
2458 cfg.cls += ' active';
2463 anc.href = this.href || cfg.cn[0].href ;
2464 ctag.html = this.html || cfg.cn[0].html ;
2468 initEvents: function()
2470 if (this.parent().type == 'treeview') {
2471 this.el.select('a').on('click', this.onClick, this);
2475 this.menu.parentType = this.xtype;
2476 this.menu.triggerEl = this.el;
2477 this.menu = this.addxtype(Roo.apply({}, this.menu));
2481 onClick : function(e)
2483 Roo.log('item on click ');
2485 if(this.preventDefault){
2488 //this.parent().hideMenuItems();
2490 this.fireEvent('click', this, e);
2509 * @class Roo.bootstrap.MenuSeparator
2510 * @extends Roo.bootstrap.Component
2511 * Bootstrap MenuSeparator class
2514 * Create a new MenuItem
2515 * @param {Object} config The config object
2519 Roo.bootstrap.MenuSeparator = function(config){
2520 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2523 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2525 getAutoCreate : function(){
2544 * @class Roo.bootstrap.Modal
2545 * @extends Roo.bootstrap.Component
2546 * Bootstrap Modal class
2547 * @cfg {String} title Title of dialog
2548 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2549 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2550 * @cfg {Boolean} specificTitle default false
2551 * @cfg {Array} buttons Array of buttons or standard button set..
2552 * @cfg {String} buttonPosition (left|right|center) default right
2553 * @cfg {Boolean} animate default true
2554 * @cfg {Boolean} allow_close default true
2555 * @cfg {Boolean} fitwindow default false
2556 * @cfg {String} size (sm|lg) default empty
2560 * Create a new Modal Dialog
2561 * @param {Object} config The config object
2564 Roo.bootstrap.Modal = function(config){
2565 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2570 * The raw btnclick event for the button
2571 * @param {Roo.EventObject} e
2576 * Fire when dialog resize
2577 * @param {Roo.bootstrap.Modal} this
2578 * @param {Roo.EventObject} e
2582 this.buttons = this.buttons || [];
2585 this.tmpl = Roo.factory(this.tmpl);
2590 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2592 title : 'test dialog',
2602 specificTitle: false,
2604 buttonPosition: 'right',
2623 onRender : function(ct, position)
2625 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2628 var cfg = Roo.apply({}, this.getAutoCreate());
2631 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2633 //if (!cfg.name.length) {
2637 cfg.cls += ' ' + this.cls;
2640 cfg.style = this.style;
2642 this.el = Roo.get(document.body).createChild(cfg, position);
2644 //var type = this.el.dom.type;
2647 if(this.tabIndex !== undefined){
2648 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2651 this.dialogEl = this.el.select('.modal-dialog',true).first();
2652 this.bodyEl = this.el.select('.modal-body',true).first();
2653 this.closeEl = this.el.select('.modal-header .close', true).first();
2654 this.headerEl = this.el.select('.modal-header',true).first();
2655 this.titleEl = this.el.select('.modal-title',true).first();
2656 this.footerEl = this.el.select('.modal-footer',true).first();
2658 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2659 this.maskEl.enableDisplayMode("block");
2661 //this.el.addClass("x-dlg-modal");
2663 if (this.buttons.length) {
2664 Roo.each(this.buttons, function(bb) {
2665 var b = Roo.apply({}, bb);
2666 b.xns = b.xns || Roo.bootstrap;
2667 b.xtype = b.xtype || 'Button';
2668 if (typeof(b.listeners) == 'undefined') {
2669 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2672 var btn = Roo.factory(b);
2674 btn.render(this.el.select('.modal-footer div').first());
2678 // render the children.
2681 if(typeof(this.items) != 'undefined'){
2682 var items = this.items;
2685 for(var i =0;i < items.length;i++) {
2686 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2690 this.items = nitems;
2692 // where are these used - they used to be body/close/footer
2696 //this.el.addClass([this.fieldClass, this.cls]);
2700 getAutoCreate : function(){
2705 html : this.html || ''
2710 cls : 'modal-title',
2714 if(this.specificTitle){
2720 if (this.allow_close) {
2732 if(this.size.length){
2733 size = 'modal-' + this.size;
2738 style : 'display: none',
2741 cls: "modal-dialog " + size,
2744 cls : "modal-content",
2747 cls : 'modal-header',
2752 cls : 'modal-footer',
2756 cls: 'btn-' + this.buttonPosition
2773 modal.cls += ' fade';
2779 getChildContainer : function() {
2784 getButtonContainer : function() {
2785 return this.el.select('.modal-footer div',true).first();
2788 initEvents : function()
2790 if (this.allow_close) {
2791 this.closeEl.on('click', this.hide, this);
2793 Roo.EventManager.onWindowResize(this.resize, this, true);
2800 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2801 if (this.fitwindow) {
2802 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2803 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2808 setSize : function(w,h)
2818 if (!this.rendered) {
2822 this.el.setStyle('display', 'block');
2824 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2827 this.el.addClass('in');
2830 this.el.addClass('in');
2834 // not sure how we can show data in here..
2836 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2839 Roo.get(document.body).addClass("x-body-masked");
2841 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2842 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2847 this.fireEvent('show', this);
2849 // set zindex here - otherwise it appears to be ignored...
2850 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2853 this.items.forEach( function(e) {
2854 e.layout ? e.layout() : false;
2862 if(this.fireEvent("beforehide", this) !== false){
2864 Roo.get(document.body).removeClass("x-body-masked");
2865 this.el.removeClass('in');
2866 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2868 if(this.animate){ // why
2870 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2872 this.el.setStyle('display', 'none');
2874 this.fireEvent('hide', this);
2878 addButton : function(str, cb)
2882 var b = Roo.apply({}, { html : str } );
2883 b.xns = b.xns || Roo.bootstrap;
2884 b.xtype = b.xtype || 'Button';
2885 if (typeof(b.listeners) == 'undefined') {
2886 b.listeners = { click : cb.createDelegate(this) };
2889 var btn = Roo.factory(b);
2891 btn.render(this.el.select('.modal-footer div').first());
2897 setDefaultButton : function(btn)
2899 //this.el.select('.modal-footer').()
2903 resizeTo: function(w,h)
2907 this.dialogEl.setWidth(w);
2908 if (this.diff === false) {
2909 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2912 this.bodyEl.setHeight(h-this.diff);
2914 this.fireEvent('resize', this);
2917 setContentSize : function(w, h)
2921 onButtonClick: function(btn,e)
2924 this.fireEvent('btnclick', btn.name, e);
2927 * Set the title of the Dialog
2928 * @param {String} str new Title
2930 setTitle: function(str) {
2931 this.titleEl.dom.innerHTML = str;
2934 * Set the body of the Dialog
2935 * @param {String} str new Title
2937 setBody: function(str) {
2938 this.bodyEl.dom.innerHTML = str;
2941 * Set the body of the Dialog using the template
2942 * @param {Obj} data - apply this data to the template and replace the body contents.
2944 applyBody: function(obj)
2947 Roo.log("Error - using apply Body without a template");
2950 this.tmpl.overwrite(this.bodyEl, obj);
2956 Roo.apply(Roo.bootstrap.Modal, {
2958 * Button config that displays a single OK button
2967 * Button config that displays Yes and No buttons
2983 * Button config that displays OK and Cancel buttons
2998 * Button config that displays Yes, No and Cancel buttons
3022 * messagebox - can be used as a replace
3026 * @class Roo.MessageBox
3027 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3031 Roo.Msg.alert('Status', 'Changes saved successfully.');
3033 // Prompt for user data:
3034 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3036 // process text value...
3040 // Show a dialog using config options:
3042 title:'Save Changes?',
3043 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3044 buttons: Roo.Msg.YESNOCANCEL,
3051 Roo.bootstrap.MessageBox = function(){
3052 var dlg, opt, mask, waitTimer;
3053 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3054 var buttons, activeTextEl, bwidth;
3058 var handleButton = function(button){
3060 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3064 var handleHide = function(){
3066 dlg.el.removeClass(opt.cls);
3069 // Roo.TaskMgr.stop(waitTimer);
3070 // waitTimer = null;
3075 var updateButtons = function(b){
3078 buttons["ok"].hide();
3079 buttons["cancel"].hide();
3080 buttons["yes"].hide();
3081 buttons["no"].hide();
3082 //dlg.footer.dom.style.display = 'none';
3085 dlg.footerEl.dom.style.display = '';
3086 for(var k in buttons){
3087 if(typeof buttons[k] != "function"){
3090 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3091 width += buttons[k].el.getWidth()+15;
3101 var handleEsc = function(d, k, e){
3102 if(opt && opt.closable !== false){
3112 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3113 * @return {Roo.BasicDialog} The BasicDialog element
3115 getDialog : function(){
3117 dlg = new Roo.bootstrap.Modal( {
3120 //constraintoviewport:false,
3122 //collapsible : false,
3127 //buttonAlign:"center",
3128 closeClick : function(){
3129 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3132 handleButton("cancel");
3137 dlg.on("hide", handleHide);
3139 //dlg.addKeyListener(27, handleEsc);
3141 this.buttons = buttons;
3142 var bt = this.buttonText;
3143 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3144 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3145 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3146 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3148 bodyEl = dlg.bodyEl.createChild({
3150 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3151 '<textarea class="roo-mb-textarea"></textarea>' +
3152 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3154 msgEl = bodyEl.dom.firstChild;
3155 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3156 textboxEl.enableDisplayMode();
3157 textboxEl.addKeyListener([10,13], function(){
3158 if(dlg.isVisible() && opt && opt.buttons){
3161 }else if(opt.buttons.yes){
3162 handleButton("yes");
3166 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3167 textareaEl.enableDisplayMode();
3168 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3169 progressEl.enableDisplayMode();
3171 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3172 var pf = progressEl.dom.firstChild;
3174 pp = Roo.get(pf.firstChild);
3175 pp.setHeight(pf.offsetHeight);
3183 * Updates the message box body text
3184 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3185 * the XHTML-compliant non-breaking space character '&#160;')
3186 * @return {Roo.MessageBox} This message box
3188 updateText : function(text)
3190 if(!dlg.isVisible() && !opt.width){
3191 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3192 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3194 msgEl.innerHTML = text || ' ';
3196 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3197 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3199 Math.min(opt.width || cw , this.maxWidth),
3200 Math.max(opt.minWidth || this.minWidth, bwidth)
3203 activeTextEl.setWidth(w);
3205 if(dlg.isVisible()){
3206 dlg.fixedcenter = false;
3208 // to big, make it scroll. = But as usual stupid IE does not support
3211 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3212 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3213 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3215 bodyEl.dom.style.height = '';
3216 bodyEl.dom.style.overflowY = '';
3219 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3221 bodyEl.dom.style.overflowX = '';
3224 dlg.setContentSize(w, bodyEl.getHeight());
3225 if(dlg.isVisible()){
3226 dlg.fixedcenter = true;
3232 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3233 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3234 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3235 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3236 * @return {Roo.MessageBox} This message box
3238 updateProgress : function(value, text){
3240 this.updateText(text);
3243 if (pp) { // weird bug on my firefox - for some reason this is not defined
3244 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3245 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3251 * Returns true if the message box is currently displayed
3252 * @return {Boolean} True if the message box is visible, else false
3254 isVisible : function(){
3255 return dlg && dlg.isVisible();
3259 * Hides the message box if it is displayed
3262 if(this.isVisible()){
3268 * Displays a new message box, or reinitializes an existing message box, based on the config options
3269 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3270 * The following config object properties are supported:
3272 Property Type Description
3273 ---------- --------------- ------------------------------------------------------------------------------------
3274 animEl String/Element An id or Element from which the message box should animate as it opens and
3275 closes (defaults to undefined)
3276 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3277 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3278 closable Boolean False to hide the top-right close button (defaults to true). Note that
3279 progress and wait dialogs will ignore this property and always hide the
3280 close button as they can only be closed programmatically.
3281 cls String A custom CSS class to apply to the message box element
3282 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3283 displayed (defaults to 75)
3284 fn Function A callback function to execute after closing the dialog. The arguments to the
3285 function will be btn (the name of the button that was clicked, if applicable,
3286 e.g. "ok"), and text (the value of the active text field, if applicable).
3287 Progress and wait dialogs will ignore this option since they do not respond to
3288 user actions and can only be closed programmatically, so any required function
3289 should be called by the same code after it closes the dialog.
3290 icon String A CSS class that provides a background image to be used as an icon for
3291 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3292 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3293 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3294 modal Boolean False to allow user interaction with the page while the message box is
3295 displayed (defaults to true)
3296 msg String A string that will replace the existing message box body text (defaults
3297 to the XHTML-compliant non-breaking space character ' ')
3298 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3299 progress Boolean True to display a progress bar (defaults to false)
3300 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3301 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3302 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3303 title String The title text
3304 value String The string value to set into the active textbox element if displayed
3305 wait Boolean True to display a progress bar (defaults to false)
3306 width Number The width of the dialog in pixels
3313 msg: 'Please enter your address:',
3315 buttons: Roo.MessageBox.OKCANCEL,
3318 animEl: 'addAddressBtn'
3321 * @param {Object} config Configuration options
3322 * @return {Roo.MessageBox} This message box
3324 show : function(options)
3327 // this causes nightmares if you show one dialog after another
3328 // especially on callbacks..
3330 if(this.isVisible()){
3333 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3334 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3335 Roo.log("New Dialog Message:" + options.msg )
3336 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3337 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3340 var d = this.getDialog();
3342 d.setTitle(opt.title || " ");
3343 d.closeEl.setDisplayed(opt.closable !== false);
3344 activeTextEl = textboxEl;
3345 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3350 textareaEl.setHeight(typeof opt.multiline == "number" ?
3351 opt.multiline : this.defaultTextHeight);
3352 activeTextEl = textareaEl;
3361 progressEl.setDisplayed(opt.progress === true);
3362 this.updateProgress(0);
3363 activeTextEl.dom.value = opt.value || "";
3365 dlg.setDefaultButton(activeTextEl);
3367 var bs = opt.buttons;
3371 }else if(bs && bs.yes){
3372 db = buttons["yes"];
3374 dlg.setDefaultButton(db);
3376 bwidth = updateButtons(opt.buttons);
3377 this.updateText(opt.msg);
3379 d.el.addClass(opt.cls);
3381 d.proxyDrag = opt.proxyDrag === true;
3382 d.modal = opt.modal !== false;
3383 d.mask = opt.modal !== false ? mask : false;
3385 // force it to the end of the z-index stack so it gets a cursor in FF
3386 document.body.appendChild(dlg.el.dom);
3387 d.animateTarget = null;
3388 d.show(options.animEl);
3394 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3395 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3396 * and closing the message box when the process is complete.
3397 * @param {String} title The title bar text
3398 * @param {String} msg The message box body text
3399 * @return {Roo.MessageBox} This message box
3401 progress : function(title, msg){
3408 minWidth: this.minProgressWidth,
3415 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3416 * If a callback function is passed it will be called after the user clicks the button, and the
3417 * id of the button that was clicked will be passed as the only parameter to the callback
3418 * (could also be the top-right close button).
3419 * @param {String} title The title bar text
3420 * @param {String} msg The message box body text
3421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3422 * @param {Object} scope (optional) The scope of the callback function
3423 * @return {Roo.MessageBox} This message box
3425 alert : function(title, msg, fn, scope)
3440 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3441 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3442 * You are responsible for closing the message box when the process is complete.
3443 * @param {String} msg The message box body text
3444 * @param {String} title (optional) The title bar text
3445 * @return {Roo.MessageBox} This message box
3447 wait : function(msg, title){
3458 waitTimer = Roo.TaskMgr.start({
3460 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3468 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3469 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3470 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3471 * @param {String} title The title bar text
3472 * @param {String} msg The message box body text
3473 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3474 * @param {Object} scope (optional) The scope of the callback function
3475 * @return {Roo.MessageBox} This message box
3477 confirm : function(title, msg, fn, scope){
3481 buttons: this.YESNO,
3490 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3491 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3492 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3493 * (could also be the top-right close button) and the text that was entered will be passed as the two
3494 * parameters to the callback.
3495 * @param {String} title The title bar text
3496 * @param {String} msg The message box body text
3497 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3498 * @param {Object} scope (optional) The scope of the callback function
3499 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3500 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3501 * @return {Roo.MessageBox} This message box
3503 prompt : function(title, msg, fn, scope, multiline){
3507 buttons: this.OKCANCEL,
3512 multiline: multiline,
3519 * Button config that displays a single OK button
3524 * Button config that displays Yes and No buttons
3527 YESNO : {yes:true, no:true},
3529 * Button config that displays OK and Cancel buttons
3532 OKCANCEL : {ok:true, cancel:true},
3534 * Button config that displays Yes, No and Cancel buttons
3537 YESNOCANCEL : {yes:true, no:true, cancel:true},
3540 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3543 defaultTextHeight : 75,
3545 * The maximum width in pixels of the message box (defaults to 600)
3550 * The minimum width in pixels of the message box (defaults to 100)
3555 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3556 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3559 minProgressWidth : 250,
3561 * An object containing the default button text strings that can be overriden for localized language support.
3562 * Supported properties are: ok, cancel, yes and no.
3563 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3576 * Shorthand for {@link Roo.MessageBox}
3578 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3579 Roo.Msg = Roo.Msg || Roo.MessageBox;
3588 * @class Roo.bootstrap.Navbar
3589 * @extends Roo.bootstrap.Component
3590 * Bootstrap Navbar class
3593 * Create a new Navbar
3594 * @param {Object} config The config object
3598 Roo.bootstrap.Navbar = function(config){
3599 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3603 * @event beforetoggle
3604 * Fire before toggle the menu
3605 * @param {Roo.EventObject} e
3607 "beforetoggle" : true
3611 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3620 getAutoCreate : function(){
3623 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3627 initEvents :function ()
3629 //Roo.log(this.el.select('.navbar-toggle',true));
3630 this.el.select('.navbar-toggle',true).on('click', function() {
3631 if(this.fireEvent('beforetoggle', this) !== false){
3632 this.el.select('.navbar-collapse',true).toggleClass('in');
3642 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3644 var size = this.el.getSize();
3645 this.maskEl.setSize(size.width, size.height);
3646 this.maskEl.enableDisplayMode("block");
3655 getChildContainer : function()
3657 if (this.el.select('.collapse').getCount()) {
3658 return this.el.select('.collapse',true).first();
3691 * @class Roo.bootstrap.NavSimplebar
3692 * @extends Roo.bootstrap.Navbar
3693 * Bootstrap Sidebar class
3695 * @cfg {Boolean} inverse is inverted color
3697 * @cfg {String} type (nav | pills | tabs)
3698 * @cfg {Boolean} arrangement stacked | justified
3699 * @cfg {String} align (left | right) alignment
3701 * @cfg {Boolean} main (true|false) main nav bar? default false
3702 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3704 * @cfg {String} tag (header|footer|nav|div) default is nav
3710 * Create a new Sidebar
3711 * @param {Object} config The config object
3715 Roo.bootstrap.NavSimplebar = function(config){
3716 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3719 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3735 getAutoCreate : function(){
3739 tag : this.tag || 'div',
3752 this.type = this.type || 'nav';
3753 if (['tabs','pills'].indexOf(this.type)!==-1) {
3754 cfg.cn[0].cls += ' nav-' + this.type
3758 if (this.type!=='nav') {
3759 Roo.log('nav type must be nav/tabs/pills')
3761 cfg.cn[0].cls += ' navbar-nav'
3767 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3768 cfg.cn[0].cls += ' nav-' + this.arrangement;
3772 if (this.align === 'right') {
3773 cfg.cn[0].cls += ' navbar-right';
3777 cfg.cls += ' navbar-inverse';
3804 * @class Roo.bootstrap.NavHeaderbar
3805 * @extends Roo.bootstrap.NavSimplebar
3806 * Bootstrap Sidebar class
3808 * @cfg {String} brand what is brand
3809 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3810 * @cfg {String} brand_href href of the brand
3811 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3812 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3813 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3814 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3817 * Create a new Sidebar
3818 * @param {Object} config The config object
3822 Roo.bootstrap.NavHeaderbar = function(config){
3823 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3827 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3834 desktopCenter : false,
3837 getAutoCreate : function(){
3840 tag: this.nav || 'nav',
3847 if (this.desktopCenter) {
3848 cn.push({cls : 'container', cn : []});
3855 cls: 'navbar-header',
3860 cls: 'navbar-toggle',
3861 'data-toggle': 'collapse',
3866 html: 'Toggle navigation'
3888 cls: 'collapse navbar-collapse',
3892 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3894 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3895 cfg.cls += ' navbar-' + this.position;
3897 // tag can override this..
3899 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3902 if (this.brand !== '') {
3905 href: this.brand_href ? this.brand_href : '#',
3906 cls: 'navbar-brand',
3914 cfg.cls += ' main-nav';
3922 getHeaderChildContainer : function()
3924 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3925 return this.el.select('.navbar-header',true).first();
3928 return this.getChildContainer();
3932 initEvents : function()
3934 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3936 if (this.autohide) {
3941 Roo.get(document).on('scroll',function(e) {
3942 var ns = Roo.get(document).getScroll().top;
3943 var os = prevScroll;
3947 ft.removeClass('slideDown');
3948 ft.addClass('slideUp');
3951 ft.removeClass('slideUp');
3952 ft.addClass('slideDown');
3973 * @class Roo.bootstrap.NavSidebar
3974 * @extends Roo.bootstrap.Navbar
3975 * Bootstrap Sidebar class
3978 * Create a new Sidebar
3979 * @param {Object} config The config object
3983 Roo.bootstrap.NavSidebar = function(config){
3984 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3987 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3989 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3991 getAutoCreate : function(){
3996 cls: 'sidebar sidebar-nav'
4018 * @class Roo.bootstrap.NavGroup
4019 * @extends Roo.bootstrap.Component
4020 * Bootstrap NavGroup class
4021 * @cfg {String} align (left|right)
4022 * @cfg {Boolean} inverse
4023 * @cfg {String} type (nav|pills|tab) default nav
4024 * @cfg {String} navId - reference Id for navbar.
4028 * Create a new nav group
4029 * @param {Object} config The config object
4032 Roo.bootstrap.NavGroup = function(config){
4033 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4036 Roo.bootstrap.NavGroup.register(this);
4040 * Fires when the active item changes
4041 * @param {Roo.bootstrap.NavGroup} this
4042 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4043 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4050 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4061 getAutoCreate : function()
4063 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4070 if (['tabs','pills'].indexOf(this.type)!==-1) {
4071 cfg.cls += ' nav-' + this.type
4073 if (this.type!=='nav') {
4074 Roo.log('nav type must be nav/tabs/pills')
4076 cfg.cls += ' navbar-nav'
4079 if (this.parent() && this.parent().sidebar) {
4082 cls: 'dashboard-menu sidebar-menu'
4088 if (this.form === true) {
4094 if (this.align === 'right') {
4095 cfg.cls += ' navbar-right';
4097 cfg.cls += ' navbar-left';
4101 if (this.align === 'right') {
4102 cfg.cls += ' navbar-right';
4106 cfg.cls += ' navbar-inverse';
4114 * sets the active Navigation item
4115 * @param {Roo.bootstrap.NavItem} the new current navitem
4117 setActiveItem : function(item)
4120 Roo.each(this.navItems, function(v){
4125 v.setActive(false, true);
4132 item.setActive(true, true);
4133 this.fireEvent('changed', this, item, prev);
4138 * gets the active Navigation item
4139 * @return {Roo.bootstrap.NavItem} the current navitem
4141 getActive : function()
4145 Roo.each(this.navItems, function(v){
4156 indexOfNav : function()
4160 Roo.each(this.navItems, function(v,i){
4171 * adds a Navigation item
4172 * @param {Roo.bootstrap.NavItem} the navitem to add
4174 addItem : function(cfg)
4176 var cn = new Roo.bootstrap.NavItem(cfg);
4178 cn.parentId = this.id;
4179 cn.onRender(this.el, null);
4183 * register a Navigation item
4184 * @param {Roo.bootstrap.NavItem} the navitem to add
4186 register : function(item)
4188 this.navItems.push( item);
4189 item.navId = this.navId;
4194 * clear all the Navigation item
4197 clearAll : function()
4200 this.el.dom.innerHTML = '';
4203 getNavItem: function(tabId)
4206 Roo.each(this.navItems, function(e) {
4207 if (e.tabId == tabId) {
4217 setActiveNext : function()
4219 var i = this.indexOfNav(this.getActive());
4220 if (i > this.navItems.length) {
4223 this.setActiveItem(this.navItems[i+1]);
4225 setActivePrev : function()
4227 var i = this.indexOfNav(this.getActive());
4231 this.setActiveItem(this.navItems[i-1]);
4233 clearWasActive : function(except) {
4234 Roo.each(this.navItems, function(e) {
4235 if (e.tabId != except.tabId && e.was_active) {
4236 e.was_active = false;
4243 getWasActive : function ()
4246 Roo.each(this.navItems, function(e) {
4261 Roo.apply(Roo.bootstrap.NavGroup, {
4265 * register a Navigation Group
4266 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4268 register : function(navgrp)
4270 this.groups[navgrp.navId] = navgrp;
4274 * fetch a Navigation Group based on the navigation ID
4275 * @param {string} the navgroup to add
4276 * @returns {Roo.bootstrap.NavGroup} the navgroup
4278 get: function(navId) {
4279 if (typeof(this.groups[navId]) == 'undefined') {
4281 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4283 return this.groups[navId] ;
4298 * @class Roo.bootstrap.NavItem
4299 * @extends Roo.bootstrap.Component
4300 * Bootstrap Navbar.NavItem class
4301 * @cfg {String} href link to
4302 * @cfg {String} html content of button
4303 * @cfg {String} badge text inside badge
4304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4305 * @cfg {String} glyphicon name of glyphicon
4306 * @cfg {String} icon name of font awesome icon
4307 * @cfg {Boolean} active Is item active
4308 * @cfg {Boolean} disabled Is item disabled
4310 * @cfg {Boolean} preventDefault (true | false) default false
4311 * @cfg {String} tabId the tab that this item activates.
4312 * @cfg {String} tagtype (a|span) render as a href or span?
4313 * @cfg {Boolean} animateRef (true|false) link to element default false
4316 * Create a new Navbar Item
4317 * @param {Object} config The config object
4319 Roo.bootstrap.NavItem = function(config){
4320 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4325 * The raw click event for the entire grid.
4326 * @param {Roo.EventObject} e
4331 * Fires when the active item active state changes
4332 * @param {Roo.bootstrap.NavItem} this
4333 * @param {boolean} state the new state
4339 * Fires when scroll to element
4340 * @param {Roo.bootstrap.NavItem} this
4341 * @param {Object} options
4342 * @param {Roo.EventObject} e
4350 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4358 preventDefault : false,
4365 getAutoCreate : function(){
4374 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4376 if (this.disabled) {
4377 cfg.cls += ' disabled';
4380 if (this.href || this.html || this.glyphicon || this.icon) {
4384 href : this.href || "#",
4385 html: this.html || ''
4390 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4393 if(this.glyphicon) {
4394 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4399 cfg.cn[0].html += " <span class='caret'></span>";
4403 if (this.badge !== '') {
4405 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4413 initEvents: function()
4415 if (typeof (this.menu) != 'undefined') {
4416 this.menu.parentType = this.xtype;
4417 this.menu.triggerEl = this.el;
4418 this.menu = this.addxtype(Roo.apply({}, this.menu));
4421 this.el.select('a',true).on('click', this.onClick, this);
4423 if(this.tagtype == 'span'){
4424 this.el.select('span',true).on('click', this.onClick, this);
4427 // at this point parent should be available..
4428 this.parent().register(this);
4431 onClick : function(e)
4433 if (e.getTarget('.dropdown-menu-item')) {
4434 // did you click on a menu itemm.... - then don't trigger onclick..
4439 this.preventDefault ||
4442 Roo.log("NavItem - prevent Default?");
4446 if (this.disabled) {
4450 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4451 if (tg && tg.transition) {
4452 Roo.log("waiting for the transitionend");
4458 //Roo.log("fire event clicked");
4459 if(this.fireEvent('click', this, e) === false){
4463 if(this.tagtype == 'span'){
4467 //Roo.log(this.href);
4468 var ael = this.el.select('a',true).first();
4471 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4472 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4473 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4474 return; // ignore... - it's a 'hash' to another page.
4476 Roo.log("NavItem - prevent Default?");
4478 this.scrollToElement(e);
4482 var p = this.parent();
4484 if (['tabs','pills'].indexOf(p.type)!==-1) {
4485 if (typeof(p.setActiveItem) !== 'undefined') {
4486 p.setActiveItem(this);
4490 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4491 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4492 // remove the collapsed menu expand...
4493 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4497 isActive: function () {
4500 setActive : function(state, fire, is_was_active)
4502 if (this.active && !state && this.navId) {
4503 this.was_active = true;
4504 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4506 nv.clearWasActive(this);
4510 this.active = state;
4513 this.el.removeClass('active');
4514 } else if (!this.el.hasClass('active')) {
4515 this.el.addClass('active');
4518 this.fireEvent('changed', this, state);
4521 // show a panel if it's registered and related..
4523 if (!this.navId || !this.tabId || !state || is_was_active) {
4527 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4531 var pan = tg.getPanelByName(this.tabId);
4535 // if we can not flip to new panel - go back to old nav highlight..
4536 if (false == tg.showPanel(pan)) {
4537 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4539 var onav = nv.getWasActive();
4541 onav.setActive(true, false, true);
4550 // this should not be here...
4551 setDisabled : function(state)
4553 this.disabled = state;
4555 this.el.removeClass('disabled');
4556 } else if (!this.el.hasClass('disabled')) {
4557 this.el.addClass('disabled');
4563 * Fetch the element to display the tooltip on.
4564 * @return {Roo.Element} defaults to this.el
4566 tooltipEl : function()
4568 return this.el.select('' + this.tagtype + '', true).first();
4571 scrollToElement : function(e)
4573 var c = document.body;
4576 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4578 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4579 c = document.documentElement;
4582 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4588 var o = target.calcOffsetsTo(c);
4595 this.fireEvent('scrollto', this, options, e);
4597 Roo.get(c).scrollTo('top', options.value, true);
4610 * <span> icon </span>
4611 * <span> text </span>
4612 * <span>badge </span>
4616 * @class Roo.bootstrap.NavSidebarItem
4617 * @extends Roo.bootstrap.NavItem
4618 * Bootstrap Navbar.NavSidebarItem class
4619 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4620 * {Boolean} open is the menu open
4621 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4622 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4623 * {String} buttonSize (sm|md|lg)the extra classes for the button
4624 * {Boolean} showArrow show arrow next to the text (default true)
4626 * Create a new Navbar Button
4627 * @param {Object} config The config object
4629 Roo.bootstrap.NavSidebarItem = function(config){
4630 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4635 * The raw click event for the entire grid.
4636 * @param {Roo.EventObject} e
4641 * Fires when the active item active state changes
4642 * @param {Roo.bootstrap.NavSidebarItem} this
4643 * @param {boolean} state the new state
4651 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4653 badgeWeight : 'default',
4659 buttonWeight : 'default',
4665 getAutoCreate : function(){
4670 href : this.href || '#',
4676 if(this.buttonView){
4679 href : this.href || '#',
4680 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4693 cfg.cls += ' active';
4696 if (this.disabled) {
4697 cfg.cls += ' disabled';
4700 cfg.cls += ' open x-open';
4703 if (this.glyphicon || this.icon) {
4704 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4705 a.cn.push({ tag : 'i', cls : c }) ;
4708 if(!this.buttonView){
4711 html : this.html || ''
4718 if (this.badge !== '') {
4719 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4725 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4728 a.cls += ' dropdown-toggle treeview' ;
4734 initEvents : function()
4736 if (typeof (this.menu) != 'undefined') {
4737 this.menu.parentType = this.xtype;
4738 this.menu.triggerEl = this.el;
4739 this.menu = this.addxtype(Roo.apply({}, this.menu));
4742 this.el.on('click', this.onClick, this);
4744 if(this.badge !== ''){
4745 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4750 onClick : function(e)
4757 if(this.preventDefault){
4761 this.fireEvent('click', this);
4764 disable : function()
4766 this.setDisabled(true);
4771 this.setDisabled(false);
4774 setDisabled : function(state)
4776 if(this.disabled == state){
4780 this.disabled = state;
4783 this.el.addClass('disabled');
4787 this.el.removeClass('disabled');
4792 setActive : function(state)
4794 if(this.active == state){
4798 this.active = state;
4801 this.el.addClass('active');
4805 this.el.removeClass('active');
4810 isActive: function ()
4815 setBadge : function(str)
4821 this.badgeEl.dom.innerHTML = str;
4838 * @class Roo.bootstrap.Row
4839 * @extends Roo.bootstrap.Component
4840 * Bootstrap Row class (contains columns...)
4844 * @param {Object} config The config object
4847 Roo.bootstrap.Row = function(config){
4848 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4851 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4853 getAutoCreate : function(){
4872 * @class Roo.bootstrap.Element
4873 * @extends Roo.bootstrap.Component
4874 * Bootstrap Element class
4875 * @cfg {String} html contents of the element
4876 * @cfg {String} tag tag of the element
4877 * @cfg {String} cls class of the element
4878 * @cfg {Boolean} preventDefault (true|false) default false
4879 * @cfg {Boolean} clickable (true|false) default false
4882 * Create a new Element
4883 * @param {Object} config The config object
4886 Roo.bootstrap.Element = function(config){
4887 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4893 * When a element is chick
4894 * @param {Roo.bootstrap.Element} this
4895 * @param {Roo.EventObject} e
4901 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4906 preventDefault: false,
4909 getAutoCreate : function(){
4913 // cls: this.cls, double assign in parent class Component.js :: onRender
4920 initEvents: function()
4922 Roo.bootstrap.Element.superclass.initEvents.call(this);
4925 this.el.on('click', this.onClick, this);
4930 onClick : function(e)
4932 if(this.preventDefault){
4936 this.fireEvent('click', this, e);
4939 getValue : function()
4941 return this.el.dom.innerHTML;
4944 setValue : function(value)
4946 this.el.dom.innerHTML = value;
4961 * @class Roo.bootstrap.Pagination
4962 * @extends Roo.bootstrap.Component
4963 * Bootstrap Pagination class
4964 * @cfg {String} size xs | sm | md | lg
4965 * @cfg {Boolean} inverse false | true
4968 * Create a new Pagination
4969 * @param {Object} config The config object
4972 Roo.bootstrap.Pagination = function(config){
4973 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4976 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4982 getAutoCreate : function(){
4988 cfg.cls += ' inverse';
4994 cfg.cls += " " + this.cls;
5012 * @class Roo.bootstrap.PaginationItem
5013 * @extends Roo.bootstrap.Component
5014 * Bootstrap PaginationItem class
5015 * @cfg {String} html text
5016 * @cfg {String} href the link
5017 * @cfg {Boolean} preventDefault (true | false) default true
5018 * @cfg {Boolean} active (true | false) default false
5019 * @cfg {Boolean} disabled default false
5023 * Create a new PaginationItem
5024 * @param {Object} config The config object
5028 Roo.bootstrap.PaginationItem = function(config){
5029 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5034 * The raw click event for the entire grid.
5035 * @param {Roo.EventObject} e
5041 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5045 preventDefault: true,
5050 getAutoCreate : function(){
5056 href : this.href ? this.href : '#',
5057 html : this.html ? this.html : ''
5067 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5071 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5077 initEvents: function() {
5079 this.el.on('click', this.onClick, this);
5082 onClick : function(e)
5084 Roo.log('PaginationItem on click ');
5085 if(this.preventDefault){
5093 this.fireEvent('click', this, e);
5109 * @class Roo.bootstrap.Slider
5110 * @extends Roo.bootstrap.Component
5111 * Bootstrap Slider class
5114 * Create a new Slider
5115 * @param {Object} config The config object
5118 Roo.bootstrap.Slider = function(config){
5119 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5122 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5124 getAutoCreate : function(){
5128 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5132 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5144 * Ext JS Library 1.1.1
5145 * Copyright(c) 2006-2007, Ext JS, LLC.
5147 * Originally Released Under LGPL - original licence link has changed is not relivant.
5150 * <script type="text/javascript">
5155 * @class Roo.grid.ColumnModel
5156 * @extends Roo.util.Observable
5157 * This is the default implementation of a ColumnModel used by the Grid. It defines
5158 * the columns in the grid.
5161 var colModel = new Roo.grid.ColumnModel([
5162 {header: "Ticker", width: 60, sortable: true, locked: true},
5163 {header: "Company Name", width: 150, sortable: true},
5164 {header: "Market Cap.", width: 100, sortable: true},
5165 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5166 {header: "Employees", width: 100, sortable: true, resizable: false}
5171 * The config options listed for this class are options which may appear in each
5172 * individual column definition.
5173 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5175 * @param {Object} config An Array of column config objects. See this class's
5176 * config objects for details.
5178 Roo.grid.ColumnModel = function(config){
5180 * The config passed into the constructor
5182 this.config = config;
5185 // if no id, create one
5186 // if the column does not have a dataIndex mapping,
5187 // map it to the order it is in the config
5188 for(var i = 0, len = config.length; i < len; i++){
5190 if(typeof c.dataIndex == "undefined"){
5193 if(typeof c.renderer == "string"){
5194 c.renderer = Roo.util.Format[c.renderer];
5196 if(typeof c.id == "undefined"){
5199 if(c.editor && c.editor.xtype){
5200 c.editor = Roo.factory(c.editor, Roo.grid);
5202 if(c.editor && c.editor.isFormField){
5203 c.editor = new Roo.grid.GridEditor(c.editor);
5205 this.lookup[c.id] = c;
5209 * The width of columns which have no width specified (defaults to 100)
5212 this.defaultWidth = 100;
5215 * Default sortable of columns which have no sortable specified (defaults to false)
5218 this.defaultSortable = false;
5222 * @event widthchange
5223 * Fires when the width of a column changes.
5224 * @param {ColumnModel} this
5225 * @param {Number} columnIndex The column index
5226 * @param {Number} newWidth The new width
5228 "widthchange": true,
5230 * @event headerchange
5231 * Fires when the text of a header changes.
5232 * @param {ColumnModel} this
5233 * @param {Number} columnIndex The column index
5234 * @param {Number} newText The new header text
5236 "headerchange": true,
5238 * @event hiddenchange
5239 * Fires when a column is hidden or "unhidden".
5240 * @param {ColumnModel} this
5241 * @param {Number} columnIndex The column index
5242 * @param {Boolean} hidden true if hidden, false otherwise
5244 "hiddenchange": true,
5246 * @event columnmoved
5247 * Fires when a column is moved.
5248 * @param {ColumnModel} this
5249 * @param {Number} oldIndex
5250 * @param {Number} newIndex
5252 "columnmoved" : true,
5254 * @event columlockchange
5255 * Fires when a column's locked state is changed
5256 * @param {ColumnModel} this
5257 * @param {Number} colIndex
5258 * @param {Boolean} locked true if locked
5260 "columnlockchange" : true
5262 Roo.grid.ColumnModel.superclass.constructor.call(this);
5264 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5266 * @cfg {String} header The header text to display in the Grid view.
5269 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5270 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5271 * specified, the column's index is used as an index into the Record's data Array.
5274 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5275 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5278 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5279 * Defaults to the value of the {@link #defaultSortable} property.
5280 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5283 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5286 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5289 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5292 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5295 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5296 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5297 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5298 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5301 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5304 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5307 * @cfg {String} cursor (Optional)
5310 * @cfg {String} tooltip (Optional)
5313 * @cfg {Number} xs (Optional)
5316 * @cfg {Number} sm (Optional)
5319 * @cfg {Number} md (Optional)
5322 * @cfg {Number} lg (Optional)
5325 * Returns the id of the column at the specified index.
5326 * @param {Number} index The column index
5327 * @return {String} the id
5329 getColumnId : function(index){
5330 return this.config[index].id;
5334 * Returns the column for a specified id.
5335 * @param {String} id The column id
5336 * @return {Object} the column
5338 getColumnById : function(id){
5339 return this.lookup[id];
5344 * Returns the column for a specified dataIndex.
5345 * @param {String} dataIndex The column dataIndex
5346 * @return {Object|Boolean} the column or false if not found
5348 getColumnByDataIndex: function(dataIndex){
5349 var index = this.findColumnIndex(dataIndex);
5350 return index > -1 ? this.config[index] : false;
5354 * Returns the index for a specified column id.
5355 * @param {String} id The column id
5356 * @return {Number} the index, or -1 if not found
5358 getIndexById : function(id){
5359 for(var i = 0, len = this.config.length; i < len; i++){
5360 if(this.config[i].id == id){
5368 * Returns the index for a specified column dataIndex.
5369 * @param {String} dataIndex The column dataIndex
5370 * @return {Number} the index, or -1 if not found
5373 findColumnIndex : function(dataIndex){
5374 for(var i = 0, len = this.config.length; i < len; i++){
5375 if(this.config[i].dataIndex == dataIndex){
5383 moveColumn : function(oldIndex, newIndex){
5384 var c = this.config[oldIndex];
5385 this.config.splice(oldIndex, 1);
5386 this.config.splice(newIndex, 0, c);
5387 this.dataMap = null;
5388 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5391 isLocked : function(colIndex){
5392 return this.config[colIndex].locked === true;
5395 setLocked : function(colIndex, value, suppressEvent){
5396 if(this.isLocked(colIndex) == value){
5399 this.config[colIndex].locked = value;
5401 this.fireEvent("columnlockchange", this, colIndex, value);
5405 getTotalLockedWidth : function(){
5407 for(var i = 0; i < this.config.length; i++){
5408 if(this.isLocked(i) && !this.isHidden(i)){
5409 this.totalWidth += this.getColumnWidth(i);
5415 getLockedCount : function(){
5416 for(var i = 0, len = this.config.length; i < len; i++){
5417 if(!this.isLocked(i)){
5422 return this.config.length;
5426 * Returns the number of columns.
5429 getColumnCount : function(visibleOnly){
5430 if(visibleOnly === true){
5432 for(var i = 0, len = this.config.length; i < len; i++){
5433 if(!this.isHidden(i)){
5439 return this.config.length;
5443 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5444 * @param {Function} fn
5445 * @param {Object} scope (optional)
5446 * @return {Array} result
5448 getColumnsBy : function(fn, scope){
5450 for(var i = 0, len = this.config.length; i < len; i++){
5451 var c = this.config[i];
5452 if(fn.call(scope||this, c, i) === true){
5460 * Returns true if the specified column is sortable.
5461 * @param {Number} col The column index
5464 isSortable : function(col){
5465 if(typeof this.config[col].sortable == "undefined"){
5466 return this.defaultSortable;
5468 return this.config[col].sortable;
5472 * Returns the rendering (formatting) function defined for the column.
5473 * @param {Number} col The column index.
5474 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5476 getRenderer : function(col){
5477 if(!this.config[col].renderer){
5478 return Roo.grid.ColumnModel.defaultRenderer;
5480 return this.config[col].renderer;
5484 * Sets the rendering (formatting) function for a column.
5485 * @param {Number} col The column index
5486 * @param {Function} fn The function to use to process the cell's raw data
5487 * to return HTML markup for the grid view. The render function is called with
5488 * the following parameters:<ul>
5489 * <li>Data value.</li>
5490 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5491 * <li>css A CSS style string to apply to the table cell.</li>
5492 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5493 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5494 * <li>Row index</li>
5495 * <li>Column index</li>
5496 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5498 setRenderer : function(col, fn){
5499 this.config[col].renderer = fn;
5503 * Returns the width for the specified column.
5504 * @param {Number} col The column index
5507 getColumnWidth : function(col){
5508 return this.config[col].width * 1 || this.defaultWidth;
5512 * Sets the width for a column.
5513 * @param {Number} col The column index
5514 * @param {Number} width The new width
5516 setColumnWidth : function(col, width, suppressEvent){
5517 this.config[col].width = width;
5518 this.totalWidth = null;
5520 this.fireEvent("widthchange", this, col, width);
5525 * Returns the total width of all columns.
5526 * @param {Boolean} includeHidden True to include hidden column widths
5529 getTotalWidth : function(includeHidden){
5530 if(!this.totalWidth){
5531 this.totalWidth = 0;
5532 for(var i = 0, len = this.config.length; i < len; i++){
5533 if(includeHidden || !this.isHidden(i)){
5534 this.totalWidth += this.getColumnWidth(i);
5538 return this.totalWidth;
5542 * Returns the header for the specified column.
5543 * @param {Number} col The column index
5546 getColumnHeader : function(col){
5547 return this.config[col].header;
5551 * Sets the header for a column.
5552 * @param {Number} col The column index
5553 * @param {String} header The new header
5555 setColumnHeader : function(col, header){
5556 this.config[col].header = header;
5557 this.fireEvent("headerchange", this, col, header);
5561 * Returns the tooltip for the specified column.
5562 * @param {Number} col The column index
5565 getColumnTooltip : function(col){
5566 return this.config[col].tooltip;
5569 * Sets the tooltip for a column.
5570 * @param {Number} col The column index
5571 * @param {String} tooltip The new tooltip
5573 setColumnTooltip : function(col, tooltip){
5574 this.config[col].tooltip = tooltip;
5578 * Returns the dataIndex for the specified column.
5579 * @param {Number} col The column index
5582 getDataIndex : function(col){
5583 return this.config[col].dataIndex;
5587 * Sets the dataIndex for a column.
5588 * @param {Number} col The column index
5589 * @param {Number} dataIndex The new dataIndex
5591 setDataIndex : function(col, dataIndex){
5592 this.config[col].dataIndex = dataIndex;
5598 * Returns true if the cell is editable.
5599 * @param {Number} colIndex The column index
5600 * @param {Number} rowIndex The row index - this is nto actually used..?
5603 isCellEditable : function(colIndex, rowIndex){
5604 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5608 * Returns the editor defined for the cell/column.
5609 * return false or null to disable editing.
5610 * @param {Number} colIndex The column index
5611 * @param {Number} rowIndex The row index
5614 getCellEditor : function(colIndex, rowIndex){
5615 return this.config[colIndex].editor;
5619 * Sets if a column is editable.
5620 * @param {Number} col The column index
5621 * @param {Boolean} editable True if the column is editable
5623 setEditable : function(col, editable){
5624 this.config[col].editable = editable;
5629 * Returns true if the column is hidden.
5630 * @param {Number} colIndex The column index
5633 isHidden : function(colIndex){
5634 return this.config[colIndex].hidden;
5639 * Returns true if the column width cannot be changed
5641 isFixed : function(colIndex){
5642 return this.config[colIndex].fixed;
5646 * Returns true if the column can be resized
5649 isResizable : function(colIndex){
5650 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5653 * Sets if a column is hidden.
5654 * @param {Number} colIndex The column index
5655 * @param {Boolean} hidden True if the column is hidden
5657 setHidden : function(colIndex, hidden){
5658 this.config[colIndex].hidden = hidden;
5659 this.totalWidth = null;
5660 this.fireEvent("hiddenchange", this, colIndex, hidden);
5664 * Sets the editor for a column.
5665 * @param {Number} col The column index
5666 * @param {Object} editor The editor object
5668 setEditor : function(col, editor){
5669 this.config[col].editor = editor;
5673 Roo.grid.ColumnModel.defaultRenderer = function(value)
5675 if(typeof value == "object") {
5678 if(typeof value == "string" && value.length < 1){
5682 return String.format("{0}", value);
5685 // Alias for backwards compatibility
5686 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5689 * Ext JS Library 1.1.1
5690 * Copyright(c) 2006-2007, Ext JS, LLC.
5692 * Originally Released Under LGPL - original licence link has changed is not relivant.
5695 * <script type="text/javascript">
5699 * @class Roo.LoadMask
5700 * A simple utility class for generically masking elements while loading data. If the element being masked has
5701 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5702 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5703 * element's UpdateManager load indicator and will be destroyed after the initial load.
5705 * Create a new LoadMask
5706 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5707 * @param {Object} config The config object
5709 Roo.LoadMask = function(el, config){
5710 this.el = Roo.get(el);
5711 Roo.apply(this, config);
5713 this.store.on('beforeload', this.onBeforeLoad, this);
5714 this.store.on('load', this.onLoad, this);
5715 this.store.on('loadexception', this.onLoadException, this);
5716 this.removeMask = false;
5718 var um = this.el.getUpdateManager();
5719 um.showLoadIndicator = false; // disable the default indicator
5720 um.on('beforeupdate', this.onBeforeLoad, this);
5721 um.on('update', this.onLoad, this);
5722 um.on('failure', this.onLoad, this);
5723 this.removeMask = true;
5727 Roo.LoadMask.prototype = {
5729 * @cfg {Boolean} removeMask
5730 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5731 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5735 * The text to display in a centered loading message box (defaults to 'Loading...')
5739 * @cfg {String} msgCls
5740 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5742 msgCls : 'x-mask-loading',
5745 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5751 * Disables the mask to prevent it from being displayed
5753 disable : function(){
5754 this.disabled = true;
5758 * Enables the mask so that it can be displayed
5760 enable : function(){
5761 this.disabled = false;
5764 onLoadException : function()
5768 if (typeof(arguments[3]) != 'undefined') {
5769 Roo.MessageBox.alert("Error loading",arguments[3]);
5773 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5774 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5781 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5786 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5790 onBeforeLoad : function(){
5792 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5797 destroy : function(){
5799 this.store.un('beforeload', this.onBeforeLoad, this);
5800 this.store.un('load', this.onLoad, this);
5801 this.store.un('loadexception', this.onLoadException, this);
5803 var um = this.el.getUpdateManager();
5804 um.un('beforeupdate', this.onBeforeLoad, this);
5805 um.un('update', this.onLoad, this);
5806 um.un('failure', this.onLoad, this);
5817 * @class Roo.bootstrap.Table
5818 * @extends Roo.bootstrap.Component
5819 * Bootstrap Table class
5820 * @cfg {String} cls table class
5821 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5822 * @cfg {String} bgcolor Specifies the background color for a table
5823 * @cfg {Number} border Specifies whether the table cells should have borders or not
5824 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5825 * @cfg {Number} cellspacing Specifies the space between cells
5826 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5827 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5828 * @cfg {String} sortable Specifies that the table should be sortable
5829 * @cfg {String} summary Specifies a summary of the content of a table
5830 * @cfg {Number} width Specifies the width of a table
5831 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5833 * @cfg {boolean} striped Should the rows be alternative striped
5834 * @cfg {boolean} bordered Add borders to the table
5835 * @cfg {boolean} hover Add hover highlighting
5836 * @cfg {boolean} condensed Format condensed
5837 * @cfg {boolean} responsive Format condensed
5838 * @cfg {Boolean} loadMask (true|false) default false
5839 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5840 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5841 * @cfg {Boolean} rowSelection (true|false) default false
5842 * @cfg {Boolean} cellSelection (true|false) default false
5843 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5844 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5845 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5849 * Create a new Table
5850 * @param {Object} config The config object
5853 Roo.bootstrap.Table = function(config){
5854 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5859 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5860 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5861 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5862 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5864 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5866 this.sm.grid = this;
5867 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5868 this.sm = this.selModel;
5869 this.sm.xmodule = this.xmodule || false;
5872 if (this.cm && typeof(this.cm.config) == 'undefined') {
5873 this.colModel = new Roo.grid.ColumnModel(this.cm);
5874 this.cm = this.colModel;
5875 this.cm.xmodule = this.xmodule || false;
5878 this.store= Roo.factory(this.store, Roo.data);
5879 this.ds = this.store;
5880 this.ds.xmodule = this.xmodule || false;
5883 if (this.footer && this.store) {
5884 this.footer.dataSource = this.ds;
5885 this.footer = Roo.factory(this.footer);
5892 * Fires when a cell is clicked
5893 * @param {Roo.bootstrap.Table} this
5894 * @param {Roo.Element} el
5895 * @param {Number} rowIndex
5896 * @param {Number} columnIndex
5897 * @param {Roo.EventObject} e
5901 * @event celldblclick
5902 * Fires when a cell is double clicked
5903 * @param {Roo.bootstrap.Table} this
5904 * @param {Roo.Element} el
5905 * @param {Number} rowIndex
5906 * @param {Number} columnIndex
5907 * @param {Roo.EventObject} e
5909 "celldblclick" : true,
5912 * Fires when a row is clicked
5913 * @param {Roo.bootstrap.Table} this
5914 * @param {Roo.Element} el
5915 * @param {Number} rowIndex
5916 * @param {Roo.EventObject} e
5920 * @event rowdblclick
5921 * Fires when a row is double clicked
5922 * @param {Roo.bootstrap.Table} this
5923 * @param {Roo.Element} el
5924 * @param {Number} rowIndex
5925 * @param {Roo.EventObject} e
5927 "rowdblclick" : true,
5930 * Fires when a mouseover occur
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Number} columnIndex
5935 * @param {Roo.EventObject} e
5940 * Fires when a mouseout occur
5941 * @param {Roo.bootstrap.Table} this
5942 * @param {Roo.Element} el
5943 * @param {Number} rowIndex
5944 * @param {Number} columnIndex
5945 * @param {Roo.EventObject} e
5950 * Fires when a row is rendered, so you can change add a style to it.
5951 * @param {Roo.bootstrap.Table} this
5952 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5956 * @event rowsrendered
5957 * Fires when all the rows have been rendered
5958 * @param {Roo.bootstrap.Table} this
5960 'rowsrendered' : true,
5962 * @event contextmenu
5963 * The raw contextmenu event for the entire grid.
5964 * @param {Roo.EventObject} e
5966 "contextmenu" : true,
5968 * @event rowcontextmenu
5969 * Fires when a row is right clicked
5970 * @param {Roo.bootstrap.Table} this
5971 * @param {Number} rowIndex
5972 * @param {Roo.EventObject} e
5974 "rowcontextmenu" : true,
5976 * @event cellcontextmenu
5977 * Fires when a cell is right clicked
5978 * @param {Roo.bootstrap.Table} this
5979 * @param {Number} rowIndex
5980 * @param {Number} cellIndex
5981 * @param {Roo.EventObject} e
5983 "cellcontextmenu" : true,
5985 * @event headercontextmenu
5986 * Fires when a header is right clicked
5987 * @param {Roo.bootstrap.Table} this
5988 * @param {Number} columnIndex
5989 * @param {Roo.EventObject} e
5991 "headercontextmenu" : true
5995 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6021 rowSelection : false,
6022 cellSelection : false,
6025 // Roo.Element - the tbody
6027 // Roo.Element - thead element
6030 container: false, // used by gridpanel...
6034 getAutoCreate : function()
6036 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6043 if (this.scrollBody) {
6044 cfg.cls += ' table-body-fixed';
6047 cfg.cls += ' table-striped';
6051 cfg.cls += ' table-hover';
6053 if (this.bordered) {
6054 cfg.cls += ' table-bordered';
6056 if (this.condensed) {
6057 cfg.cls += ' table-condensed';
6059 if (this.responsive) {
6060 cfg.cls += ' table-responsive';
6064 cfg.cls+= ' ' +this.cls;
6067 // this lot should be simplifed...
6070 cfg.align=this.align;
6073 cfg.bgcolor=this.bgcolor;
6076 cfg.border=this.border;
6078 if (this.cellpadding) {
6079 cfg.cellpadding=this.cellpadding;
6081 if (this.cellspacing) {
6082 cfg.cellspacing=this.cellspacing;
6085 cfg.frame=this.frame;
6088 cfg.rules=this.rules;
6090 if (this.sortable) {
6091 cfg.sortable=this.sortable;
6094 cfg.summary=this.summary;
6097 cfg.width=this.width;
6100 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6103 if(this.store || this.cm){
6104 if(this.headerShow){
6105 cfg.cn.push(this.renderHeader());
6108 cfg.cn.push(this.renderBody());
6110 if(this.footerShow){
6111 cfg.cn.push(this.renderFooter());
6113 // where does this come from?
6114 //cfg.cls+= ' TableGrid';
6117 return { cn : [ cfg ] };
6120 initEvents : function()
6122 if(!this.store || !this.cm){
6125 if (this.selModel) {
6126 this.selModel.initEvents();
6130 //Roo.log('initEvents with ds!!!!');
6132 this.mainBody = this.el.select('tbody', true).first();
6133 this.mainHead = this.el.select('thead', true).first();
6140 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6141 e.on('click', _this.sort, _this);
6144 this.mainBody.on("click", this.onClick, this);
6145 this.mainBody.on("dblclick", this.onDblClick, this);
6147 // why is this done????? = it breaks dialogs??
6148 //this.parent().el.setStyle('position', 'relative');
6152 this.footer.parentId = this.id;
6153 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6156 this.el.select('tfoot tr td').first().addClass('hide');
6160 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6162 this.store.on('load', this.onLoad, this);
6163 this.store.on('beforeload', this.onBeforeLoad, this);
6164 this.store.on('update', this.onUpdate, this);
6165 this.store.on('add', this.onAdd, this);
6166 this.store.on("clear", this.clear, this);
6168 this.el.on("contextmenu", this.onContextMenu, this);
6170 this.mainBody.on('scroll', this.onBodyScroll, this);
6172 this.cm.on("headerchange", this.onHeaderChange, this);
6174 this.cm.on("hiddenchange", this.onHiddenChange, this);
6178 onContextMenu : function(e, t)
6180 this.processEvent("contextmenu", e);
6183 processEvent : function(name, e)
6185 if (name != 'touchstart' ) {
6186 this.fireEvent(name, e);
6189 var t = e.getTarget();
6191 var cell = Roo.get(t);
6197 if(cell.findParent('tfoot', false, true)){
6201 if(cell.findParent('thead', false, true)){
6203 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6204 cell = Roo.get(t).findParent('th', false, true);
6206 Roo.log("failed to find th in thead?");
6207 Roo.log(e.getTarget());
6212 var cellIndex = cell.dom.cellIndex;
6214 var ename = name == 'touchstart' ? 'click' : name;
6215 this.fireEvent("header" + ename, this, cellIndex, e);
6220 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6221 cell = Roo.get(t).findParent('td', false, true);
6223 Roo.log("failed to find th in tbody?");
6224 Roo.log(e.getTarget());
6229 var row = cell.findParent('tr', false, true);
6230 var cellIndex = cell.dom.cellIndex;
6231 var rowIndex = row.dom.rowIndex - 1;
6235 this.fireEvent("row" + name, this, rowIndex, e);
6239 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6245 onMouseover : function(e, el)
6247 var cell = Roo.get(el);
6253 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6254 cell = cell.findParent('td', false, true);
6257 var row = cell.findParent('tr', false, true);
6258 var cellIndex = cell.dom.cellIndex;
6259 var rowIndex = row.dom.rowIndex - 1; // start from 0
6261 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6265 onMouseout : function(e, el)
6267 var cell = Roo.get(el);
6273 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6274 cell = cell.findParent('td', false, true);
6277 var row = cell.findParent('tr', false, true);
6278 var cellIndex = cell.dom.cellIndex;
6279 var rowIndex = row.dom.rowIndex - 1; // start from 0
6281 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6285 onClick : function(e, el)
6287 var cell = Roo.get(el);
6289 if(!cell || (!this.cellSelection && !this.rowSelection)){
6293 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6294 cell = cell.findParent('td', false, true);
6297 if(!cell || typeof(cell) == 'undefined'){
6301 var row = cell.findParent('tr', false, true);
6303 if(!row || typeof(row) == 'undefined'){
6307 var cellIndex = cell.dom.cellIndex;
6308 var rowIndex = this.getRowIndex(row);
6310 // why??? - should these not be based on SelectionModel?
6311 if(this.cellSelection){
6312 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6315 if(this.rowSelection){
6316 this.fireEvent('rowclick', this, row, rowIndex, e);
6322 onDblClick : function(e,el)
6324 var cell = Roo.get(el);
6326 if(!cell || (!this.cellSelection && !this.rowSelection)){
6330 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6331 cell = cell.findParent('td', false, true);
6334 if(!cell || typeof(cell) == 'undefined'){
6338 var row = cell.findParent('tr', false, true);
6340 if(!row || typeof(row) == 'undefined'){
6344 var cellIndex = cell.dom.cellIndex;
6345 var rowIndex = this.getRowIndex(row);
6347 if(this.cellSelection){
6348 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6351 if(this.rowSelection){
6352 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6356 sort : function(e,el)
6358 var col = Roo.get(el);
6360 if(!col.hasClass('sortable')){
6364 var sort = col.attr('sort');
6367 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6371 this.store.sortInfo = {field : sort, direction : dir};
6374 Roo.log("calling footer first");
6375 this.footer.onClick('first');
6378 this.store.load({ params : { start : 0 } });
6382 renderHeader : function()
6390 this.totalWidth = 0;
6392 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6394 var config = cm.config[i];
6399 html: cm.getColumnHeader(i)
6404 if(typeof(config.sortable) != 'undefined' && config.sortable){
6406 c.html = '<i class="glyphicon"></i>' + c.html;
6409 if(typeof(config.lgHeader) != 'undefined'){
6410 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6413 if(typeof(config.mdHeader) != 'undefined'){
6414 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6417 if(typeof(config.smHeader) != 'undefined'){
6418 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6421 if(typeof(config.xsHeader) != 'undefined'){
6422 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6429 if(typeof(config.tooltip) != 'undefined'){
6430 c.tooltip = config.tooltip;
6433 if(typeof(config.colspan) != 'undefined'){
6434 c.colspan = config.colspan;
6437 if(typeof(config.hidden) != 'undefined' && config.hidden){
6438 c.style += ' display:none;';
6441 if(typeof(config.dataIndex) != 'undefined'){
6442 c.sort = config.dataIndex;
6447 if(typeof(config.align) != 'undefined' && config.align.length){
6448 c.style += ' text-align:' + config.align + ';';
6451 if(typeof(config.width) != 'undefined'){
6452 c.style += ' width:' + config.width + 'px;';
6453 this.totalWidth += config.width;
6455 this.totalWidth += 100; // assume minimum of 100 per column?
6458 if(typeof(config.cls) != 'undefined'){
6459 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6462 ['xs','sm','md','lg'].map(function(size){
6464 if(typeof(config[size]) == 'undefined'){
6468 if (!config[size]) { // 0 = hidden
6469 c.cls += ' hidden-' + size;
6473 c.cls += ' col-' + size + '-' + config[size];
6487 renderBody : function()
6497 colspan : this.cm.getColumnCount()
6507 renderFooter : function()
6517 colspan : this.cm.getColumnCount()
6531 // Roo.log('ds onload');
6536 var ds = this.store;
6538 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6539 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6540 if (_this.store.sortInfo) {
6542 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6543 e.select('i', true).addClass(['glyphicon-arrow-up']);
6546 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6547 e.select('i', true).addClass(['glyphicon-arrow-down']);
6552 var tbody = this.mainBody;
6554 if(ds.getCount() > 0){
6555 ds.data.each(function(d,rowIndex){
6556 var row = this.renderRow(cm, ds, rowIndex);
6558 tbody.createChild(row);
6562 if(row.cellObjects.length){
6563 Roo.each(row.cellObjects, function(r){
6564 _this.renderCellObject(r);
6571 Roo.each(this.el.select('tbody td', true).elements, function(e){
6572 e.on('mouseover', _this.onMouseover, _this);
6575 Roo.each(this.el.select('tbody td', true).elements, function(e){
6576 e.on('mouseout', _this.onMouseout, _this);
6578 this.fireEvent('rowsrendered', this);
6579 //if(this.loadMask){
6580 // this.maskEl.hide();
6587 onUpdate : function(ds,record)
6589 this.refreshRow(record);
6593 onRemove : function(ds, record, index, isUpdate){
6594 if(isUpdate !== true){
6595 this.fireEvent("beforerowremoved", this, index, record);
6597 var bt = this.mainBody.dom;
6599 var rows = this.el.select('tbody > tr', true).elements;
6601 if(typeof(rows[index]) != 'undefined'){
6602 bt.removeChild(rows[index].dom);
6605 // if(bt.rows[index]){
6606 // bt.removeChild(bt.rows[index]);
6609 if(isUpdate !== true){
6610 //this.stripeRows(index);
6611 //this.syncRowHeights(index, index);
6613 this.fireEvent("rowremoved", this, index, record);
6617 onAdd : function(ds, records, rowIndex)
6619 //Roo.log('on Add called');
6620 // - note this does not handle multiple adding very well..
6621 var bt = this.mainBody.dom;
6622 for (var i =0 ; i < records.length;i++) {
6623 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6624 //Roo.log(records[i]);
6625 //Roo.log(this.store.getAt(rowIndex+i));
6626 this.insertRow(this.store, rowIndex + i, false);
6633 refreshRow : function(record){
6634 var ds = this.store, index;
6635 if(typeof record == 'number'){
6637 record = ds.getAt(index);
6639 index = ds.indexOf(record);
6641 this.insertRow(ds, index, true);
6643 this.onRemove(ds, record, index+1, true);
6645 //this.syncRowHeights(index, index);
6647 this.fireEvent("rowupdated", this, index, record);
6650 insertRow : function(dm, rowIndex, isUpdate){
6653 this.fireEvent("beforerowsinserted", this, rowIndex);
6655 //var s = this.getScrollState();
6656 var row = this.renderRow(this.cm, this.store, rowIndex);
6657 // insert before rowIndex..
6658 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6662 if(row.cellObjects.length){
6663 Roo.each(row.cellObjects, function(r){
6664 _this.renderCellObject(r);
6669 this.fireEvent("rowsinserted", this, rowIndex);
6670 //this.syncRowHeights(firstRow, lastRow);
6671 //this.stripeRows(firstRow);
6678 getRowDom : function(rowIndex)
6680 var rows = this.el.select('tbody > tr', true).elements;
6682 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6685 // returns the object tree for a tr..
6688 renderRow : function(cm, ds, rowIndex)
6691 var d = ds.getAt(rowIndex);
6698 var cellObjects = [];
6700 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6701 var config = cm.config[i];
6703 var renderer = cm.getRenderer(i);
6707 if(typeof(renderer) !== 'undefined'){
6708 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6710 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6711 // and are rendered into the cells after the row is rendered - using the id for the element.
6713 if(typeof(value) === 'object'){
6723 rowIndex : rowIndex,
6728 this.fireEvent('rowclass', this, rowcfg);
6732 cls : rowcfg.rowClass,
6734 html: (typeof(value) === 'object') ? '' : value
6741 if(typeof(config.colspan) != 'undefined'){
6742 td.colspan = config.colspan;
6745 if(typeof(config.hidden) != 'undefined' && config.hidden){
6746 td.style += ' display:none;';
6749 if(typeof(config.align) != 'undefined' && config.align.length){
6750 td.style += ' text-align:' + config.align + ';';
6753 if(typeof(config.width) != 'undefined'){
6754 td.style += ' width:' + config.width + 'px;';
6757 if(typeof(config.cursor) != 'undefined'){
6758 td.style += ' cursor:' + config.cursor + ';';
6761 if(typeof(config.cls) != 'undefined'){
6762 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6765 ['xs','sm','md','lg'].map(function(size){
6767 if(typeof(config[size]) == 'undefined'){
6771 if (!config[size]) { // 0 = hidden
6772 td.cls += ' hidden-' + size;
6776 td.cls += ' col-' + size + '-' + config[size];
6781 td.cls += ' hidden';
6788 row.cellObjects = cellObjects;
6796 onBeforeLoad : function()
6798 //Roo.log('ds onBeforeLoad');
6802 //if(this.loadMask){
6803 // this.maskEl.show();
6811 this.el.select('tbody', true).first().dom.innerHTML = '';
6814 * Show or hide a row.
6815 * @param {Number} rowIndex to show or hide
6816 * @param {Boolean} state hide
6818 setRowVisibility : function(rowIndex, state)
6820 var bt = this.mainBody.dom;
6822 var rows = this.el.select('tbody > tr', true).elements;
6824 if(typeof(rows[rowIndex]) == 'undefined'){
6827 rows[rowIndex].dom.style.display = state ? '' : 'none';
6831 getSelectionModel : function(){
6833 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6835 return this.selModel;
6838 * Render the Roo.bootstrap object from renderder
6840 renderCellObject : function(r)
6844 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6846 var t = r.cfg.render(r.container);
6849 Roo.each(r.cfg.cn, function(c){
6851 container: t.getChildContainer(),
6854 _this.renderCellObject(child);
6859 getRowIndex : function(row)
6863 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6874 * Returns the grid's underlying element = used by panel.Grid
6875 * @return {Element} The element
6877 getGridEl : function(){
6881 * Forces a resize - used by panel.Grid
6882 * @return {Element} The element
6884 autoSize : function()
6886 //var ctr = Roo.get(this.container.dom.parentElement);
6887 var ctr = Roo.get(this.el.dom);
6889 var thd = this.getGridEl().select('thead',true).first();
6890 var tbd = this.getGridEl().select('tbody', true).first();
6891 var tfd = this.getGridEl().select('tfoot', true).first();
6893 var cw = ctr.getWidth();
6897 tbd.setSize(ctr.getWidth(),
6898 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6900 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6903 cw = Math.max(cw, this.totalWidth);
6904 this.getGridEl().select('tr',true).setWidth(cw);
6905 // resize 'expandable coloumn?
6907 return; // we doe not have a view in this design..
6910 onBodyScroll: function()
6912 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6914 this.mainHead.setStyle({
6915 'position' : 'relative',
6916 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6922 var scrollHeight = this.mainBody.dom.scrollHeight;
6924 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6926 var height = this.mainBody.getHeight();
6928 if(scrollHeight - height == scrollTop) {
6930 var total = this.ds.getTotalCount();
6932 if(this.footer.cursor + this.footer.pageSize < total){
6934 this.footer.ds.load({
6936 start : this.footer.cursor + this.footer.pageSize,
6937 limit : this.footer.pageSize
6947 onHeaderChange : function()
6950 var header = this.renderHeader();
6951 var table = this.el.select('table', true).first();
6953 this.mainHead.remove();
6954 this.mainHead = table.createChild(header, this.mainBody, false);
6957 onHiddenChange : function()
6959 this.onHeaderChange();
6975 * @class Roo.bootstrap.TableCell
6976 * @extends Roo.bootstrap.Component
6977 * Bootstrap TableCell class
6978 * @cfg {String} html cell contain text
6979 * @cfg {String} cls cell class
6980 * @cfg {String} tag cell tag (td|th) default td
6981 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6982 * @cfg {String} align Aligns the content in a cell
6983 * @cfg {String} axis Categorizes cells
6984 * @cfg {String} bgcolor Specifies the background color of a cell
6985 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6986 * @cfg {Number} colspan Specifies the number of columns a cell should span
6987 * @cfg {String} headers Specifies one or more header cells a cell is related to
6988 * @cfg {Number} height Sets the height of a cell
6989 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6990 * @cfg {Number} rowspan Sets the number of rows a cell should span
6991 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6992 * @cfg {String} valign Vertical aligns the content in a cell
6993 * @cfg {Number} width Specifies the width of a cell
6996 * Create a new TableCell
6997 * @param {Object} config The config object
7000 Roo.bootstrap.TableCell = function(config){
7001 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7004 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7024 getAutoCreate : function(){
7025 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7045 cfg.align=this.align
7051 cfg.bgcolor=this.bgcolor
7054 cfg.charoff=this.charoff
7057 cfg.colspan=this.colspan
7060 cfg.headers=this.headers
7063 cfg.height=this.height
7066 cfg.nowrap=this.nowrap
7069 cfg.rowspan=this.rowspan
7072 cfg.scope=this.scope
7075 cfg.valign=this.valign
7078 cfg.width=this.width
7097 * @class Roo.bootstrap.TableRow
7098 * @extends Roo.bootstrap.Component
7099 * Bootstrap TableRow class
7100 * @cfg {String} cls row class
7101 * @cfg {String} align Aligns the content in a table row
7102 * @cfg {String} bgcolor Specifies a background color for a table row
7103 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7104 * @cfg {String} valign Vertical aligns the content in a table row
7107 * Create a new TableRow
7108 * @param {Object} config The config object
7111 Roo.bootstrap.TableRow = function(config){
7112 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7115 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7123 getAutoCreate : function(){
7124 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7134 cfg.align = this.align;
7137 cfg.bgcolor = this.bgcolor;
7140 cfg.charoff = this.charoff;
7143 cfg.valign = this.valign;
7161 * @class Roo.bootstrap.TableBody
7162 * @extends Roo.bootstrap.Component
7163 * Bootstrap TableBody class
7164 * @cfg {String} cls element class
7165 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7166 * @cfg {String} align Aligns the content inside the element
7167 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7168 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7171 * Create a new TableBody
7172 * @param {Object} config The config object
7175 Roo.bootstrap.TableBody = function(config){
7176 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7179 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7187 getAutoCreate : function(){
7188 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7202 cfg.align = this.align;
7205 cfg.charoff = this.charoff;
7208 cfg.valign = this.valign;
7215 // initEvents : function()
7222 // this.store = Roo.factory(this.store, Roo.data);
7223 // this.store.on('load', this.onLoad, this);
7225 // this.store.load();
7229 // onLoad: function ()
7231 // this.fireEvent('load', this);
7241 * Ext JS Library 1.1.1
7242 * Copyright(c) 2006-2007, Ext JS, LLC.
7244 * Originally Released Under LGPL - original licence link has changed is not relivant.
7247 * <script type="text/javascript">
7250 // as we use this in bootstrap.
7251 Roo.namespace('Roo.form');
7253 * @class Roo.form.Action
7254 * Internal Class used to handle form actions
7256 * @param {Roo.form.BasicForm} el The form element or its id
7257 * @param {Object} config Configuration options
7262 // define the action interface
7263 Roo.form.Action = function(form, options){
7265 this.options = options || {};
7268 * Client Validation Failed
7271 Roo.form.Action.CLIENT_INVALID = 'client';
7273 * Server Validation Failed
7276 Roo.form.Action.SERVER_INVALID = 'server';
7278 * Connect to Server Failed
7281 Roo.form.Action.CONNECT_FAILURE = 'connect';
7283 * Reading Data from Server Failed
7286 Roo.form.Action.LOAD_FAILURE = 'load';
7288 Roo.form.Action.prototype = {
7290 failureType : undefined,
7291 response : undefined,
7295 run : function(options){
7300 success : function(response){
7305 handleResponse : function(response){
7309 // default connection failure
7310 failure : function(response){
7312 this.response = response;
7313 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7314 this.form.afterAction(this, false);
7317 processResponse : function(response){
7318 this.response = response;
7319 if(!response.responseText){
7322 this.result = this.handleResponse(response);
7326 // utility functions used internally
7327 getUrl : function(appendParams){
7328 var url = this.options.url || this.form.url || this.form.el.dom.action;
7330 var p = this.getParams();
7332 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7338 getMethod : function(){
7339 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7342 getParams : function(){
7343 var bp = this.form.baseParams;
7344 var p = this.options.params;
7346 if(typeof p == "object"){
7347 p = Roo.urlEncode(Roo.applyIf(p, bp));
7348 }else if(typeof p == 'string' && bp){
7349 p += '&' + Roo.urlEncode(bp);
7352 p = Roo.urlEncode(bp);
7357 createCallback : function(){
7359 success: this.success,
7360 failure: this.failure,
7362 timeout: (this.form.timeout*1000),
7363 upload: this.form.fileUpload ? this.success : undefined
7368 Roo.form.Action.Submit = function(form, options){
7369 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7372 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7375 haveProgress : false,
7376 uploadComplete : false,
7378 // uploadProgress indicator.
7379 uploadProgress : function()
7381 if (!this.form.progressUrl) {
7385 if (!this.haveProgress) {
7386 Roo.MessageBox.progress("Uploading", "Uploading");
7388 if (this.uploadComplete) {
7389 Roo.MessageBox.hide();
7393 this.haveProgress = true;
7395 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7397 var c = new Roo.data.Connection();
7399 url : this.form.progressUrl,
7404 success : function(req){
7405 //console.log(data);
7409 rdata = Roo.decode(req.responseText)
7411 Roo.log("Invalid data from server..");
7415 if (!rdata || !rdata.success) {
7417 Roo.MessageBox.alert(Roo.encode(rdata));
7420 var data = rdata.data;
7422 if (this.uploadComplete) {
7423 Roo.MessageBox.hide();
7428 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7429 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7432 this.uploadProgress.defer(2000,this);
7435 failure: function(data) {
7436 Roo.log('progress url failed ');
7447 // run get Values on the form, so it syncs any secondary forms.
7448 this.form.getValues();
7450 var o = this.options;
7451 var method = this.getMethod();
7452 var isPost = method == 'POST';
7453 if(o.clientValidation === false || this.form.isValid()){
7455 if (this.form.progressUrl) {
7456 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7457 (new Date() * 1) + '' + Math.random());
7462 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7463 form:this.form.el.dom,
7464 url:this.getUrl(!isPost),
7466 params:isPost ? this.getParams() : null,
7467 isUpload: this.form.fileUpload
7470 this.uploadProgress();
7472 }else if (o.clientValidation !== false){ // client validation failed
7473 this.failureType = Roo.form.Action.CLIENT_INVALID;
7474 this.form.afterAction(this, false);
7478 success : function(response)
7480 this.uploadComplete= true;
7481 if (this.haveProgress) {
7482 Roo.MessageBox.hide();
7486 var result = this.processResponse(response);
7487 if(result === true || result.success){
7488 this.form.afterAction(this, true);
7492 this.form.markInvalid(result.errors);
7493 this.failureType = Roo.form.Action.SERVER_INVALID;
7495 this.form.afterAction(this, false);
7497 failure : function(response)
7499 this.uploadComplete= true;
7500 if (this.haveProgress) {
7501 Roo.MessageBox.hide();
7504 this.response = response;
7505 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7506 this.form.afterAction(this, false);
7509 handleResponse : function(response){
7510 if(this.form.errorReader){
7511 var rs = this.form.errorReader.read(response);
7514 for(var i = 0, len = rs.records.length; i < len; i++) {
7515 var r = rs.records[i];
7519 if(errors.length < 1){
7523 success : rs.success,
7529 ret = Roo.decode(response.responseText);
7533 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7543 Roo.form.Action.Load = function(form, options){
7544 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7545 this.reader = this.form.reader;
7548 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7553 Roo.Ajax.request(Roo.apply(
7554 this.createCallback(), {
7555 method:this.getMethod(),
7556 url:this.getUrl(false),
7557 params:this.getParams()
7561 success : function(response){
7563 var result = this.processResponse(response);
7564 if(result === true || !result.success || !result.data){
7565 this.failureType = Roo.form.Action.LOAD_FAILURE;
7566 this.form.afterAction(this, false);
7569 this.form.clearInvalid();
7570 this.form.setValues(result.data);
7571 this.form.afterAction(this, true);
7574 handleResponse : function(response){
7575 if(this.form.reader){
7576 var rs = this.form.reader.read(response);
7577 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7579 success : rs.success,
7583 return Roo.decode(response.responseText);
7587 Roo.form.Action.ACTION_TYPES = {
7588 'load' : Roo.form.Action.Load,
7589 'submit' : Roo.form.Action.Submit
7598 * @class Roo.bootstrap.Form
7599 * @extends Roo.bootstrap.Component
7600 * Bootstrap Form class
7601 * @cfg {String} method GET | POST (default POST)
7602 * @cfg {String} labelAlign top | left (default top)
7603 * @cfg {String} align left | right - for navbars
7604 * @cfg {Boolean} loadMask load mask when submit (default true)
7609 * @param {Object} config The config object
7613 Roo.bootstrap.Form = function(config){
7615 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7617 Roo.bootstrap.Form.popover.apply();
7621 * @event clientvalidation
7622 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7623 * @param {Form} this
7624 * @param {Boolean} valid true if the form has passed client-side validation
7626 clientvalidation: true,
7628 * @event beforeaction
7629 * Fires before any action is performed. Return false to cancel the action.
7630 * @param {Form} this
7631 * @param {Action} action The action to be performed
7635 * @event actionfailed
7636 * Fires when an action fails.
7637 * @param {Form} this
7638 * @param {Action} action The action that failed
7640 actionfailed : true,
7642 * @event actioncomplete
7643 * Fires when an action is completed.
7644 * @param {Form} this
7645 * @param {Action} action The action that completed
7647 actioncomplete : true
7651 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7654 * @cfg {String} method
7655 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7660 * The URL to use for form actions if one isn't supplied in the action options.
7663 * @cfg {Boolean} fileUpload
7664 * Set to true if this form is a file upload.
7668 * @cfg {Object} baseParams
7669 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7673 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7677 * @cfg {Sting} align (left|right) for navbar forms
7682 activeAction : null,
7685 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7686 * element by passing it or its id or mask the form itself by passing in true.
7689 waitMsgTarget : false,
7694 * @cfg {Boolean} errorMask (true|false) default false
7699 * @cfg {Number} maskOffset Default 100
7704 * @cfg {Boolean} maskBody
7708 getAutoCreate : function(){
7712 method : this.method || 'POST',
7713 id : this.id || Roo.id(),
7716 if (this.parent().xtype.match(/^Nav/)) {
7717 cfg.cls = 'navbar-form navbar-' + this.align;
7721 if (this.labelAlign == 'left' ) {
7722 cfg.cls += ' form-horizontal';
7728 initEvents : function()
7730 this.el.on('submit', this.onSubmit, this);
7731 // this was added as random key presses on the form where triggering form submit.
7732 this.el.on('keypress', function(e) {
7733 if (e.getCharCode() != 13) {
7736 // we might need to allow it for textareas.. and some other items.
7737 // check e.getTarget().
7739 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7743 Roo.log("keypress blocked");
7751 onSubmit : function(e){
7756 * Returns true if client-side validation on the form is successful.
7759 isValid : function(){
7760 var items = this.getItems();
7764 items.each(function(f){
7770 if(!target && f.el.isVisible(true)){
7776 if(this.errorMask && !valid){
7777 Roo.bootstrap.Form.popover.mask(this, target);
7784 * Returns true if any fields in this form have changed since their original load.
7787 isDirty : function(){
7789 var items = this.getItems();
7790 items.each(function(f){
7800 * Performs a predefined action (submit or load) or custom actions you define on this form.
7801 * @param {String} actionName The name of the action type
7802 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7803 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7804 * accept other config options):
7806 Property Type Description
7807 ---------------- --------------- ----------------------------------------------------------------------------------
7808 url String The url for the action (defaults to the form's url)
7809 method String The form method to use (defaults to the form's method, or POST if not defined)
7810 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7811 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7812 validate the form on the client (defaults to false)
7814 * @return {BasicForm} this
7816 doAction : function(action, options){
7817 if(typeof action == 'string'){
7818 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7820 if(this.fireEvent('beforeaction', this, action) !== false){
7821 this.beforeAction(action);
7822 action.run.defer(100, action);
7828 beforeAction : function(action){
7829 var o = action.options;
7834 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7836 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7839 // not really supported yet.. ??
7841 //if(this.waitMsgTarget === true){
7842 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7843 //}else if(this.waitMsgTarget){
7844 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7845 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7847 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7853 afterAction : function(action, success){
7854 this.activeAction = null;
7855 var o = action.options;
7860 Roo.get(document.body).unmask();
7866 //if(this.waitMsgTarget === true){
7867 // this.el.unmask();
7868 //}else if(this.waitMsgTarget){
7869 // this.waitMsgTarget.unmask();
7871 // Roo.MessageBox.updateProgress(1);
7872 // Roo.MessageBox.hide();
7879 Roo.callback(o.success, o.scope, [this, action]);
7880 this.fireEvent('actioncomplete', this, action);
7884 // failure condition..
7885 // we have a scenario where updates need confirming.
7886 // eg. if a locking scenario exists..
7887 // we look for { errors : { needs_confirm : true }} in the response.
7889 (typeof(action.result) != 'undefined') &&
7890 (typeof(action.result.errors) != 'undefined') &&
7891 (typeof(action.result.errors.needs_confirm) != 'undefined')
7894 Roo.log("not supported yet");
7897 Roo.MessageBox.confirm(
7898 "Change requires confirmation",
7899 action.result.errorMsg,
7904 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7914 Roo.callback(o.failure, o.scope, [this, action]);
7915 // show an error message if no failed handler is set..
7916 if (!this.hasListener('actionfailed')) {
7917 Roo.log("need to add dialog support");
7919 Roo.MessageBox.alert("Error",
7920 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7921 action.result.errorMsg :
7922 "Saving Failed, please check your entries or try again"
7927 this.fireEvent('actionfailed', this, action);
7932 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7933 * @param {String} id The value to search for
7936 findField : function(id){
7937 var items = this.getItems();
7938 var field = items.get(id);
7940 items.each(function(f){
7941 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7948 return field || null;
7951 * Mark fields in this form invalid in bulk.
7952 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7953 * @return {BasicForm} this
7955 markInvalid : function(errors){
7956 if(errors instanceof Array){
7957 for(var i = 0, len = errors.length; i < len; i++){
7958 var fieldError = errors[i];
7959 var f = this.findField(fieldError.id);
7961 f.markInvalid(fieldError.msg);
7967 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7968 field.markInvalid(errors[id]);
7972 //Roo.each(this.childForms || [], function (f) {
7973 // f.markInvalid(errors);
7980 * Set values for fields in this form in bulk.
7981 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7982 * @return {BasicForm} this
7984 setValues : function(values){
7985 if(values instanceof Array){ // array of objects
7986 for(var i = 0, len = values.length; i < len; i++){
7988 var f = this.findField(v.id);
7990 f.setValue(v.value);
7991 if(this.trackResetOnLoad){
7992 f.originalValue = f.getValue();
7996 }else{ // object hash
7999 if(typeof values[id] != 'function' && (field = this.findField(id))){
8001 if (field.setFromData &&
8003 field.displayField &&
8004 // combos' with local stores can
8005 // be queried via setValue()
8006 // to set their value..
8007 (field.store && !field.store.isLocal)
8011 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8012 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8013 field.setFromData(sd);
8015 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8017 field.setFromData(values);
8020 field.setValue(values[id]);
8024 if(this.trackResetOnLoad){
8025 field.originalValue = field.getValue();
8031 //Roo.each(this.childForms || [], function (f) {
8032 // f.setValues(values);
8039 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8040 * they are returned as an array.
8041 * @param {Boolean} asString
8044 getValues : function(asString){
8045 //if (this.childForms) {
8046 // copy values from the child forms
8047 // Roo.each(this.childForms, function (f) {
8048 // this.setValues(f.getValues());
8054 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8055 if(asString === true){
8058 return Roo.urlDecode(fs);
8062 * Returns the fields in this form as an object with key/value pairs.
8063 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8066 getFieldValues : function(with_hidden)
8068 var items = this.getItems();
8070 items.each(function(f){
8076 var v = f.getValue();
8078 if (f.inputType =='radio') {
8079 if (typeof(ret[f.getName()]) == 'undefined') {
8080 ret[f.getName()] = ''; // empty..
8083 if (!f.el.dom.checked) {
8091 if(f.xtype == 'MoneyField'){
8092 ret[f.currencyName] = f.getCurrency();
8095 // not sure if this supported any more..
8096 if ((typeof(v) == 'object') && f.getRawValue) {
8097 v = f.getRawValue() ; // dates..
8099 // combo boxes where name != hiddenName...
8100 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8101 ret[f.name] = f.getRawValue();
8103 ret[f.getName()] = v;
8110 * Clears all invalid messages in this form.
8111 * @return {BasicForm} this
8113 clearInvalid : function(){
8114 var items = this.getItems();
8116 items.each(function(f){
8125 * @return {BasicForm} this
8128 var items = this.getItems();
8129 items.each(function(f){
8133 Roo.each(this.childForms || [], function (f) {
8141 getItems : function()
8143 var r=new Roo.util.MixedCollection(false, function(o){
8144 return o.id || (o.id = Roo.id());
8146 var iter = function(el) {
8153 Roo.each(el.items,function(e) {
8162 hideFields : function(items)
8164 Roo.each(items, function(i){
8166 var f = this.findField(i);
8172 if(f.xtype == 'DateField'){
8173 f.setVisible(false);
8182 showFields : function(items)
8184 Roo.each(items, function(i){
8186 var f = this.findField(i);
8192 if(f.xtype == 'DateField'){
8204 Roo.apply(Roo.bootstrap.Form, {
8231 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8232 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8233 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8234 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8237 this.maskEl.top.enableDisplayMode("block");
8238 this.maskEl.left.enableDisplayMode("block");
8239 this.maskEl.bottom.enableDisplayMode("block");
8240 this.maskEl.right.enableDisplayMode("block");
8242 this.toolTip = new Roo.bootstrap.Tooltip({
8243 cls : 'roo-form-error-popover',
8245 'left' : ['r-l', [-2,0], 'right'],
8246 'right' : ['l-r', [2,0], 'left'],
8247 'bottom' : ['tl-bl', [0,2], 'top'],
8248 'top' : [ 'bl-tl', [0,-2], 'bottom']
8252 this.toolTip.render(Roo.get(document.body));
8254 this.toolTip.el.enableDisplayMode("block");
8256 Roo.get(document.body).on('click', function(){
8260 Roo.get(document.body).on('touchstart', function(){
8264 this.isApplied = true
8267 mask : function(form, target)
8271 this.target = target;
8273 if(!this.form.errorMask || !target.el){
8277 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8279 Roo.log(scrollable);
8281 var ot = this.target.el.calcOffsetsTo(scrollable);
8283 var scrollTo = ot[1] - this.form.maskOffset;
8285 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8287 scrollable.scrollTo('top', scrollTo);
8289 var box = this.target.el.getBox();
8291 var zIndex = Roo.bootstrap.Modal.zIndex++;
8294 this.maskEl.top.setStyle('position', 'absolute');
8295 this.maskEl.top.setStyle('z-index', zIndex);
8296 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8297 this.maskEl.top.setLeft(0);
8298 this.maskEl.top.setTop(0);
8299 this.maskEl.top.show();
8301 this.maskEl.left.setStyle('position', 'absolute');
8302 this.maskEl.left.setStyle('z-index', zIndex);
8303 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8304 this.maskEl.left.setLeft(0);
8305 this.maskEl.left.setTop(box.y - this.padding);
8306 this.maskEl.left.show();
8308 this.maskEl.bottom.setStyle('position', 'absolute');
8309 this.maskEl.bottom.setStyle('z-index', zIndex);
8310 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8311 this.maskEl.bottom.setLeft(0);
8312 this.maskEl.bottom.setTop(box.bottom + this.padding);
8313 this.maskEl.bottom.show();
8315 this.maskEl.right.setStyle('position', 'absolute');
8316 this.maskEl.right.setStyle('z-index', zIndex);
8317 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8318 this.maskEl.right.setLeft(box.right + this.padding);
8319 this.maskEl.right.setTop(box.y - this.padding);
8320 this.maskEl.right.show();
8322 this.toolTip.bindEl = this.target.el;
8324 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8326 var tip = this.target.blankText;
8328 if(this.target.getValue() !== '' ) {
8330 if (this.target.invalidText.length) {
8331 tip = this.target.invalidText;
8332 } else if (this.target.regexText.length){
8333 tip = this.target.regexText;
8337 this.toolTip.show(tip);
8339 this.intervalID = window.setInterval(function() {
8340 Roo.bootstrap.Form.popover.unmask();
8343 window.onwheel = function(){ return false;};
8345 (function(){ this.isMasked = true; }).defer(500, this);
8351 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8355 this.maskEl.top.setStyle('position', 'absolute');
8356 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8357 this.maskEl.top.hide();
8359 this.maskEl.left.setStyle('position', 'absolute');
8360 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8361 this.maskEl.left.hide();
8363 this.maskEl.bottom.setStyle('position', 'absolute');
8364 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8365 this.maskEl.bottom.hide();
8367 this.maskEl.right.setStyle('position', 'absolute');
8368 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8369 this.maskEl.right.hide();
8371 this.toolTip.hide();
8373 this.toolTip.el.hide();
8375 window.onwheel = function(){ return true;};
8377 if(this.intervalID){
8378 window.clearInterval(this.intervalID);
8379 this.intervalID = false;
8382 this.isMasked = false;
8392 * Ext JS Library 1.1.1
8393 * Copyright(c) 2006-2007, Ext JS, LLC.
8395 * Originally Released Under LGPL - original licence link has changed is not relivant.
8398 * <script type="text/javascript">
8401 * @class Roo.form.VTypes
8402 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8405 Roo.form.VTypes = function(){
8406 // closure these in so they are only created once.
8407 var alpha = /^[a-zA-Z_]+$/;
8408 var alphanum = /^[a-zA-Z0-9_]+$/;
8409 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8410 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8412 // All these messages and functions are configurable
8415 * The function used to validate email addresses
8416 * @param {String} value The email address
8418 'email' : function(v){
8419 return email.test(v);
8422 * The error text to display when the email validation function returns false
8425 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8427 * The keystroke filter mask to be applied on email input
8430 'emailMask' : /[a-z0-9_\.\-@]/i,
8433 * The function used to validate URLs
8434 * @param {String} value The URL
8436 'url' : function(v){
8440 * The error text to display when the url validation function returns false
8443 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8446 * The function used to validate alpha values
8447 * @param {String} value The value
8449 'alpha' : function(v){
8450 return alpha.test(v);
8453 * The error text to display when the alpha validation function returns false
8456 'alphaText' : 'This field should only contain letters and _',
8458 * The keystroke filter mask to be applied on alpha input
8461 'alphaMask' : /[a-z_]/i,
8464 * The function used to validate alphanumeric values
8465 * @param {String} value The value
8467 'alphanum' : function(v){
8468 return alphanum.test(v);
8471 * The error text to display when the alphanumeric validation function returns false
8474 'alphanumText' : 'This field should only contain letters, numbers and _',
8476 * The keystroke filter mask to be applied on alphanumeric input
8479 'alphanumMask' : /[a-z0-9_]/i
8489 * @class Roo.bootstrap.Input
8490 * @extends Roo.bootstrap.Component
8491 * Bootstrap Input class
8492 * @cfg {Boolean} disabled is it disabled
8493 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8494 * @cfg {String} name name of the input
8495 * @cfg {string} fieldLabel - the label associated
8496 * @cfg {string} placeholder - placeholder to put in text.
8497 * @cfg {string} before - input group add on before
8498 * @cfg {string} after - input group add on after
8499 * @cfg {string} size - (lg|sm) or leave empty..
8500 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8501 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8502 * @cfg {Number} md colspan out of 12 for computer-sized screens
8503 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8504 * @cfg {string} value default value of the input
8505 * @cfg {Number} labelWidth set the width of label
8506 * @cfg {Number} labellg set the width of label (1-12)
8507 * @cfg {Number} labelmd set the width of label (1-12)
8508 * @cfg {Number} labelsm set the width of label (1-12)
8509 * @cfg {Number} labelxs set the width of label (1-12)
8510 * @cfg {String} labelAlign (top|left)
8511 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8512 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8513 * @cfg {String} indicatorpos (left|right) default left
8515 * @cfg {String} align (left|center|right) Default left
8516 * @cfg {Boolean} forceFeedback (true|false) Default false
8519 * Create a new Input
8520 * @param {Object} config The config object
8523 Roo.bootstrap.Input = function(config){
8525 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8530 * Fires when this field receives input focus.
8531 * @param {Roo.form.Field} this
8536 * Fires when this field loses input focus.
8537 * @param {Roo.form.Field} this
8542 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8543 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8544 * @param {Roo.form.Field} this
8545 * @param {Roo.EventObject} e The event object
8550 * Fires just before the field blurs if the field value has changed.
8551 * @param {Roo.form.Field} this
8552 * @param {Mixed} newValue The new value
8553 * @param {Mixed} oldValue The original value
8558 * Fires after the field has been marked as invalid.
8559 * @param {Roo.form.Field} this
8560 * @param {String} msg The validation message
8565 * Fires after the field has been validated with no errors.
8566 * @param {Roo.form.Field} this
8571 * Fires after the key up
8572 * @param {Roo.form.Field} this
8573 * @param {Roo.EventObject} e The event Object
8579 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8581 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8582 automatic validation (defaults to "keyup").
8584 validationEvent : "keyup",
8586 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8588 validateOnBlur : true,
8590 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8592 validationDelay : 250,
8594 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8596 focusClass : "x-form-focus", // not needed???
8600 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8602 invalidClass : "has-warning",
8605 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8607 validClass : "has-success",
8610 * @cfg {Boolean} hasFeedback (true|false) default true
8615 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8617 invalidFeedbackClass : "glyphicon-warning-sign",
8620 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8622 validFeedbackClass : "glyphicon-ok",
8625 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8627 selectOnFocus : false,
8630 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8634 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8639 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8641 disableKeyFilter : false,
8644 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8648 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8652 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8654 blankText : "Please complete this mandatory field",
8657 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8661 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8663 maxLength : Number.MAX_VALUE,
8665 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8667 minLengthText : "The minimum length for this field is {0}",
8669 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8671 maxLengthText : "The maximum length for this field is {0}",
8675 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8676 * If available, this function will be called only after the basic validators all return true, and will be passed the
8677 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8681 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8682 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8683 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8687 * @cfg {String} regexText -- Depricated - use Invalid Text
8692 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8698 autocomplete: false,
8717 formatedValue : false,
8718 forceFeedback : false,
8720 indicatorpos : 'left',
8727 parentLabelAlign : function()
8730 while (parent.parent()) {
8731 parent = parent.parent();
8732 if (typeof(parent.labelAlign) !='undefined') {
8733 return parent.labelAlign;
8740 getAutoCreate : function()
8742 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8748 if(this.inputType != 'hidden'){
8749 cfg.cls = 'form-group' //input-group
8755 type : this.inputType,
8757 cls : 'form-control',
8758 placeholder : this.placeholder || '',
8759 autocomplete : this.autocomplete || 'new-password'
8763 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8766 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8767 input.maxLength = this.maxLength;
8770 if (this.disabled) {
8771 input.disabled=true;
8774 if (this.readOnly) {
8775 input.readonly=true;
8779 input.name = this.name;
8783 input.cls += ' input-' + this.size;
8787 ['xs','sm','md','lg'].map(function(size){
8788 if (settings[size]) {
8789 cfg.cls += ' col-' + size + '-' + settings[size];
8793 var inputblock = input;
8797 cls: 'glyphicon form-control-feedback'
8800 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8803 cls : 'has-feedback',
8811 if (this.before || this.after) {
8814 cls : 'input-group',
8818 if (this.before && typeof(this.before) == 'string') {
8820 inputblock.cn.push({
8822 cls : 'roo-input-before input-group-addon',
8826 if (this.before && typeof(this.before) == 'object') {
8827 this.before = Roo.factory(this.before);
8829 inputblock.cn.push({
8831 cls : 'roo-input-before input-group-' +
8832 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8836 inputblock.cn.push(input);
8838 if (this.after && typeof(this.after) == 'string') {
8839 inputblock.cn.push({
8841 cls : 'roo-input-after input-group-addon',
8845 if (this.after && typeof(this.after) == 'object') {
8846 this.after = Roo.factory(this.after);
8848 inputblock.cn.push({
8850 cls : 'roo-input-after input-group-' +
8851 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8855 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8856 inputblock.cls += ' has-feedback';
8857 inputblock.cn.push(feedback);
8861 if (align ==='left' && this.fieldLabel.length) {
8863 cfg.cls += ' roo-form-group-label-left';
8868 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8869 tooltip : 'This field is required'
8874 cls : 'control-label',
8875 html : this.fieldLabel
8886 var labelCfg = cfg.cn[1];
8887 var contentCfg = cfg.cn[2];
8889 if(this.indicatorpos == 'right'){
8894 cls : 'control-label',
8898 html : this.fieldLabel
8902 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8903 tooltip : 'This field is required'
8916 labelCfg = cfg.cn[0];
8917 contentCfg = cfg.cn[1];
8921 if(this.labelWidth > 12){
8922 labelCfg.style = "width: " + this.labelWidth + 'px';
8925 if(this.labelWidth < 13 && this.labelmd == 0){
8926 this.labelmd = this.labelWidth;
8929 if(this.labellg > 0){
8930 labelCfg.cls += ' col-lg-' + this.labellg;
8931 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8934 if(this.labelmd > 0){
8935 labelCfg.cls += ' col-md-' + this.labelmd;
8936 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8939 if(this.labelsm > 0){
8940 labelCfg.cls += ' col-sm-' + this.labelsm;
8941 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8944 if(this.labelxs > 0){
8945 labelCfg.cls += ' col-xs-' + this.labelxs;
8946 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8950 } else if ( this.fieldLabel.length) {
8955 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8956 tooltip : 'This field is required'
8960 //cls : 'input-group-addon',
8961 html : this.fieldLabel
8969 if(this.indicatorpos == 'right'){
8974 //cls : 'input-group-addon',
8975 html : this.fieldLabel
8980 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8981 tooltip : 'This field is required'
9001 if (this.parentType === 'Navbar' && this.parent().bar) {
9002 cfg.cls += ' navbar-form';
9005 if (this.parentType === 'NavGroup') {
9006 cfg.cls += ' navbar-form';
9014 * return the real input element.
9016 inputEl: function ()
9018 return this.el.select('input.form-control',true).first();
9021 tooltipEl : function()
9023 return this.inputEl();
9026 indicatorEl : function()
9028 var indicator = this.el.select('i.roo-required-indicator',true).first();
9038 setDisabled : function(v)
9040 var i = this.inputEl().dom;
9042 i.removeAttribute('disabled');
9046 i.setAttribute('disabled','true');
9048 initEvents : function()
9051 this.inputEl().on("keydown" , this.fireKey, this);
9052 this.inputEl().on("focus", this.onFocus, this);
9053 this.inputEl().on("blur", this.onBlur, this);
9055 this.inputEl().relayEvent('keyup', this);
9057 this.indicator = this.indicatorEl();
9060 this.indicator.addClass('invisible');
9063 // reference to original value for reset
9064 this.originalValue = this.getValue();
9065 //Roo.form.TextField.superclass.initEvents.call(this);
9066 if(this.validationEvent == 'keyup'){
9067 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9068 this.inputEl().on('keyup', this.filterValidation, this);
9070 else if(this.validationEvent !== false){
9071 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9074 if(this.selectOnFocus){
9075 this.on("focus", this.preFocus, this);
9078 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9079 this.inputEl().on("keypress", this.filterKeys, this);
9081 this.inputEl().relayEvent('keypress', this);
9084 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9085 this.el.on("click", this.autoSize, this);
9088 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9089 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9092 if (typeof(this.before) == 'object') {
9093 this.before.render(this.el.select('.roo-input-before',true).first());
9095 if (typeof(this.after) == 'object') {
9096 this.after.render(this.el.select('.roo-input-after',true).first());
9101 filterValidation : function(e){
9102 if(!e.isNavKeyPress()){
9103 this.validationTask.delay(this.validationDelay);
9107 * Validates the field value
9108 * @return {Boolean} True if the value is valid, else false
9110 validate : function(){
9111 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9112 if(this.disabled || this.validateValue(this.getRawValue())){
9123 * Validates a value according to the field's validation rules and marks the field as invalid
9124 * if the validation fails
9125 * @param {Mixed} value The value to validate
9126 * @return {Boolean} True if the value is valid, else false
9128 validateValue : function(value)
9130 if(this.getVisibilityEl().hasClass('hidden')){
9134 if(value.length < 1) { // if it's blank
9135 if(this.allowBlank){
9141 if(value.length < this.minLength){
9144 if(value.length > this.maxLength){
9148 var vt = Roo.form.VTypes;
9149 if(!vt[this.vtype](value, this)){
9153 if(typeof this.validator == "function"){
9154 var msg = this.validator(value);
9158 if (typeof(msg) == 'string') {
9159 this.invalidText = msg;
9163 if(this.regex && !this.regex.test(value)){
9171 fireKey : function(e){
9172 //Roo.log('field ' + e.getKey());
9173 if(e.isNavKeyPress()){
9174 this.fireEvent("specialkey", this, e);
9177 focus : function (selectText){
9179 this.inputEl().focus();
9180 if(selectText === true){
9181 this.inputEl().dom.select();
9187 onFocus : function(){
9188 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9189 // this.el.addClass(this.focusClass);
9192 this.hasFocus = true;
9193 this.startValue = this.getValue();
9194 this.fireEvent("focus", this);
9198 beforeBlur : Roo.emptyFn,
9202 onBlur : function(){
9204 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9205 //this.el.removeClass(this.focusClass);
9207 this.hasFocus = false;
9208 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9211 var v = this.getValue();
9212 if(String(v) !== String(this.startValue)){
9213 this.fireEvent('change', this, v, this.startValue);
9215 this.fireEvent("blur", this);
9219 * Resets the current field value to the originally loaded value and clears any validation messages
9222 this.setValue(this.originalValue);
9226 * Returns the name of the field
9227 * @return {Mixed} name The name field
9229 getName: function(){
9233 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9234 * @return {Mixed} value The field value
9236 getValue : function(){
9238 var v = this.inputEl().getValue();
9243 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9244 * @return {Mixed} value The field value
9246 getRawValue : function(){
9247 var v = this.inputEl().getValue();
9253 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9254 * @param {Mixed} value The value to set
9256 setRawValue : function(v){
9257 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9260 selectText : function(start, end){
9261 var v = this.getRawValue();
9263 start = start === undefined ? 0 : start;
9264 end = end === undefined ? v.length : end;
9265 var d = this.inputEl().dom;
9266 if(d.setSelectionRange){
9267 d.setSelectionRange(start, end);
9268 }else if(d.createTextRange){
9269 var range = d.createTextRange();
9270 range.moveStart("character", start);
9271 range.moveEnd("character", v.length-end);
9278 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9279 * @param {Mixed} value The value to set
9281 setValue : function(v){
9284 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9290 processValue : function(value){
9291 if(this.stripCharsRe){
9292 var newValue = value.replace(this.stripCharsRe, '');
9293 if(newValue !== value){
9294 this.setRawValue(newValue);
9301 preFocus : function(){
9303 if(this.selectOnFocus){
9304 this.inputEl().dom.select();
9307 filterKeys : function(e){
9309 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9312 var c = e.getCharCode(), cc = String.fromCharCode(c);
9313 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9316 if(!this.maskRe.test(cc)){
9321 * Clear any invalid styles/messages for this field
9323 clearInvalid : function(){
9325 if(!this.el || this.preventMark){ // not rendered
9330 this.el.removeClass(this.invalidClass);
9332 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9334 var feedback = this.el.select('.form-control-feedback', true).first();
9337 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9342 this.fireEvent('valid', this);
9346 * Mark this field as valid
9348 markValid : function()
9350 if(!this.el || this.preventMark){ // not rendered...
9354 this.el.removeClass([this.invalidClass, this.validClass]);
9356 var feedback = this.el.select('.form-control-feedback', true).first();
9359 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9363 this.indicator.removeClass('visible');
9364 this.indicator.addClass('invisible');
9371 if(this.allowBlank && !this.getRawValue().length){
9375 this.el.addClass(this.validClass);
9377 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9379 var feedback = this.el.select('.form-control-feedback', true).first();
9382 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9383 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9388 this.fireEvent('valid', this);
9392 * Mark this field as invalid
9393 * @param {String} msg The validation message
9395 markInvalid : function(msg)
9397 if(!this.el || this.preventMark){ // not rendered
9401 this.el.removeClass([this.invalidClass, this.validClass]);
9403 var feedback = this.el.select('.form-control-feedback', true).first();
9406 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9413 if(this.allowBlank && !this.getRawValue().length){
9418 this.indicator.removeClass('invisible');
9419 this.indicator.addClass('visible');
9422 this.el.addClass(this.invalidClass);
9424 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9426 var feedback = this.el.select('.form-control-feedback', true).first();
9429 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9431 if(this.getValue().length || this.forceFeedback){
9432 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9439 this.fireEvent('invalid', this, msg);
9442 SafariOnKeyDown : function(event)
9444 // this is a workaround for a password hang bug on chrome/ webkit.
9445 if (this.inputEl().dom.type != 'password') {
9449 var isSelectAll = false;
9451 if(this.inputEl().dom.selectionEnd > 0){
9452 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9454 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9455 event.preventDefault();
9460 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9462 event.preventDefault();
9463 // this is very hacky as keydown always get's upper case.
9465 var cc = String.fromCharCode(event.getCharCode());
9466 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9470 adjustWidth : function(tag, w){
9471 tag = tag.toLowerCase();
9472 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9473 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9477 if(tag == 'textarea'){
9480 }else if(Roo.isOpera){
9484 if(tag == 'textarea'){
9492 setFieldLabel : function(v)
9499 var ar = this.el.select('label > span',true);
9501 if (ar.elements.length) {
9502 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9503 this.fieldLabel = v;
9507 var br = this.el.select('label',true);
9509 if(br.elements.length) {
9510 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9511 this.fieldLabel = v;
9515 Roo.log('Cannot Found any of label > span || label in input');
9519 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9520 this.fieldLabel = v;
9535 * @class Roo.bootstrap.TextArea
9536 * @extends Roo.bootstrap.Input
9537 * Bootstrap TextArea class
9538 * @cfg {Number} cols Specifies the visible width of a text area
9539 * @cfg {Number} rows Specifies the visible number of lines in a text area
9540 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9541 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9542 * @cfg {string} html text
9545 * Create a new TextArea
9546 * @param {Object} config The config object
9549 Roo.bootstrap.TextArea = function(config){
9550 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9554 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9564 getAutoCreate : function(){
9566 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9572 if(this.inputType != 'hidden'){
9573 cfg.cls = 'form-group' //input-group
9581 value : this.value || '',
9582 html: this.html || '',
9583 cls : 'form-control',
9584 placeholder : this.placeholder || ''
9588 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9589 input.maxLength = this.maxLength;
9593 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9597 input.cols = this.cols;
9600 if (this.readOnly) {
9601 input.readonly = true;
9605 input.name = this.name;
9609 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9613 ['xs','sm','md','lg'].map(function(size){
9614 if (settings[size]) {
9615 cfg.cls += ' col-' + size + '-' + settings[size];
9619 var inputblock = input;
9621 if(this.hasFeedback && !this.allowBlank){
9625 cls: 'glyphicon form-control-feedback'
9629 cls : 'has-feedback',
9638 if (this.before || this.after) {
9641 cls : 'input-group',
9645 inputblock.cn.push({
9647 cls : 'input-group-addon',
9652 inputblock.cn.push(input);
9654 if(this.hasFeedback && !this.allowBlank){
9655 inputblock.cls += ' has-feedback';
9656 inputblock.cn.push(feedback);
9660 inputblock.cn.push({
9662 cls : 'input-group-addon',
9669 if (align ==='left' && this.fieldLabel.length) {
9674 cls : 'control-label',
9675 html : this.fieldLabel
9686 if(this.labelWidth > 12){
9687 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9690 if(this.labelWidth < 13 && this.labelmd == 0){
9691 this.labelmd = this.labelWidth;
9694 if(this.labellg > 0){
9695 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9696 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9699 if(this.labelmd > 0){
9700 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9701 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9704 if(this.labelsm > 0){
9705 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9706 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9709 if(this.labelxs > 0){
9710 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9711 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9714 } else if ( this.fieldLabel.length) {
9719 //cls : 'input-group-addon',
9720 html : this.fieldLabel
9738 if (this.disabled) {
9739 input.disabled=true;
9746 * return the real textarea element.
9748 inputEl: function ()
9750 return this.el.select('textarea.form-control',true).first();
9754 * Clear any invalid styles/messages for this field
9756 clearInvalid : function()
9759 if(!this.el || this.preventMark){ // not rendered
9763 var label = this.el.select('label', true).first();
9764 var icon = this.el.select('i.fa-star', true).first();
9770 this.el.removeClass(this.invalidClass);
9772 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9774 var feedback = this.el.select('.form-control-feedback', true).first();
9777 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9782 this.fireEvent('valid', this);
9786 * Mark this field as valid
9788 markValid : function()
9790 if(!this.el || this.preventMark){ // not rendered
9794 this.el.removeClass([this.invalidClass, this.validClass]);
9796 var feedback = this.el.select('.form-control-feedback', true).first();
9799 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9802 if(this.disabled || this.allowBlank){
9806 var label = this.el.select('label', true).first();
9807 var icon = this.el.select('i.fa-star', true).first();
9813 this.el.addClass(this.validClass);
9815 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9817 var feedback = this.el.select('.form-control-feedback', true).first();
9820 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9821 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9826 this.fireEvent('valid', this);
9830 * Mark this field as invalid
9831 * @param {String} msg The validation message
9833 markInvalid : function(msg)
9835 if(!this.el || this.preventMark){ // not rendered
9839 this.el.removeClass([this.invalidClass, this.validClass]);
9841 var feedback = this.el.select('.form-control-feedback', true).first();
9844 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9847 if(this.disabled || this.allowBlank){
9851 var label = this.el.select('label', true).first();
9852 var icon = this.el.select('i.fa-star', true).first();
9854 if(!this.getValue().length && label && !icon){
9855 this.el.createChild({
9857 cls : 'text-danger fa fa-lg fa-star',
9858 tooltip : 'This field is required',
9859 style : 'margin-right:5px;'
9863 this.el.addClass(this.invalidClass);
9865 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9867 var feedback = this.el.select('.form-control-feedback', true).first();
9870 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9872 if(this.getValue().length || this.forceFeedback){
9873 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9880 this.fireEvent('invalid', this, msg);
9888 * trigger field - base class for combo..
9893 * @class Roo.bootstrap.TriggerField
9894 * @extends Roo.bootstrap.Input
9895 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9896 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9897 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9898 * for which you can provide a custom implementation. For example:
9900 var trigger = new Roo.bootstrap.TriggerField();
9901 trigger.onTriggerClick = myTriggerFn;
9902 trigger.applyTo('my-field');
9905 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9906 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9907 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9908 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9909 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9912 * Create a new TriggerField.
9913 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9914 * to the base TextField)
9916 Roo.bootstrap.TriggerField = function(config){
9917 this.mimicing = false;
9918 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9921 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9923 * @cfg {String} triggerClass A CSS class to apply to the trigger
9926 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9931 * @cfg {Boolean} removable (true|false) special filter default false
9935 /** @cfg {Boolean} grow @hide */
9936 /** @cfg {Number} growMin @hide */
9937 /** @cfg {Number} growMax @hide */
9943 autoSize: Roo.emptyFn,
9950 actionMode : 'wrap',
9955 getAutoCreate : function(){
9957 var align = this.labelAlign || this.parentLabelAlign();
9962 cls: 'form-group' //input-group
9969 type : this.inputType,
9970 cls : 'form-control',
9971 autocomplete: 'new-password',
9972 placeholder : this.placeholder || ''
9976 input.name = this.name;
9979 input.cls += ' input-' + this.size;
9982 if (this.disabled) {
9983 input.disabled=true;
9986 var inputblock = input;
9988 if(this.hasFeedback && !this.allowBlank){
9992 cls: 'glyphicon form-control-feedback'
9995 if(this.removable && !this.editable && !this.tickable){
9997 cls : 'has-feedback',
10003 cls : 'roo-combo-removable-btn close'
10010 cls : 'has-feedback',
10019 if(this.removable && !this.editable && !this.tickable){
10021 cls : 'roo-removable',
10027 cls : 'roo-combo-removable-btn close'
10034 if (this.before || this.after) {
10037 cls : 'input-group',
10041 inputblock.cn.push({
10043 cls : 'input-group-addon',
10048 inputblock.cn.push(input);
10050 if(this.hasFeedback && !this.allowBlank){
10051 inputblock.cls += ' has-feedback';
10052 inputblock.cn.push(feedback);
10056 inputblock.cn.push({
10058 cls : 'input-group-addon',
10071 cls: 'form-hidden-field'
10085 cls: 'form-hidden-field'
10089 cls: 'roo-select2-choices',
10093 cls: 'roo-select2-search-field',
10106 cls: 'roo-select2-container input-group',
10111 // cls: 'typeahead typeahead-long dropdown-menu',
10112 // style: 'display:none'
10117 if(!this.multiple && this.showToggleBtn){
10123 if (this.caret != false) {
10126 cls: 'fa fa-' + this.caret
10133 cls : 'input-group-addon btn dropdown-toggle',
10138 cls: 'combobox-clear',
10152 combobox.cls += ' roo-select2-container-multi';
10155 if (align ==='left' && this.fieldLabel.length) {
10157 cfg.cls += ' roo-form-group-label-left';
10162 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10163 tooltip : 'This field is required'
10168 cls : 'control-label',
10169 html : this.fieldLabel
10181 var labelCfg = cfg.cn[1];
10182 var contentCfg = cfg.cn[2];
10184 if(this.indicatorpos == 'right'){
10189 cls : 'control-label',
10193 html : this.fieldLabel
10197 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10198 tooltip : 'This field is required'
10211 labelCfg = cfg.cn[0];
10212 contentCfg = cfg.cn[1];
10215 if(this.labelWidth > 12){
10216 labelCfg.style = "width: " + this.labelWidth + 'px';
10219 if(this.labelWidth < 13 && this.labelmd == 0){
10220 this.labelmd = this.labelWidth;
10223 if(this.labellg > 0){
10224 labelCfg.cls += ' col-lg-' + this.labellg;
10225 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10228 if(this.labelmd > 0){
10229 labelCfg.cls += ' col-md-' + this.labelmd;
10230 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10233 if(this.labelsm > 0){
10234 labelCfg.cls += ' col-sm-' + this.labelsm;
10235 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10238 if(this.labelxs > 0){
10239 labelCfg.cls += ' col-xs-' + this.labelxs;
10240 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10243 } else if ( this.fieldLabel.length) {
10244 // Roo.log(" label");
10248 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10249 tooltip : 'This field is required'
10253 //cls : 'input-group-addon',
10254 html : this.fieldLabel
10262 if(this.indicatorpos == 'right'){
10270 html : this.fieldLabel
10274 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10275 tooltip : 'This field is required'
10288 // Roo.log(" no label && no align");
10295 ['xs','sm','md','lg'].map(function(size){
10296 if (settings[size]) {
10297 cfg.cls += ' col-' + size + '-' + settings[size];
10308 onResize : function(w, h){
10309 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10310 // if(typeof w == 'number'){
10311 // var x = w - this.trigger.getWidth();
10312 // this.inputEl().setWidth(this.adjustWidth('input', x));
10313 // this.trigger.setStyle('left', x+'px');
10318 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10321 getResizeEl : function(){
10322 return this.inputEl();
10326 getPositionEl : function(){
10327 return this.inputEl();
10331 alignErrorIcon : function(){
10332 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10336 initEvents : function(){
10340 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10341 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10342 if(!this.multiple && this.showToggleBtn){
10343 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10344 if(this.hideTrigger){
10345 this.trigger.setDisplayed(false);
10347 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10351 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10354 if(this.removable && !this.editable && !this.tickable){
10355 var close = this.closeTriggerEl();
10358 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10359 close.on('click', this.removeBtnClick, this, close);
10363 //this.trigger.addClassOnOver('x-form-trigger-over');
10364 //this.trigger.addClassOnClick('x-form-trigger-click');
10367 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10371 closeTriggerEl : function()
10373 var close = this.el.select('.roo-combo-removable-btn', true).first();
10374 return close ? close : false;
10377 removeBtnClick : function(e, h, el)
10379 e.preventDefault();
10381 if(this.fireEvent("remove", this) !== false){
10383 this.fireEvent("afterremove", this)
10387 createList : function()
10389 this.list = Roo.get(document.body).createChild({
10391 cls: 'typeahead typeahead-long dropdown-menu',
10392 style: 'display:none'
10395 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10400 initTrigger : function(){
10405 onDestroy : function(){
10407 this.trigger.removeAllListeners();
10408 // this.trigger.remove();
10411 // this.wrap.remove();
10413 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10417 onFocus : function(){
10418 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10420 if(!this.mimicing){
10421 this.wrap.addClass('x-trigger-wrap-focus');
10422 this.mimicing = true;
10423 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10424 if(this.monitorTab){
10425 this.el.on("keydown", this.checkTab, this);
10432 checkTab : function(e){
10433 if(e.getKey() == e.TAB){
10434 this.triggerBlur();
10439 onBlur : function(){
10444 mimicBlur : function(e, t){
10446 if(!this.wrap.contains(t) && this.validateBlur()){
10447 this.triggerBlur();
10453 triggerBlur : function(){
10454 this.mimicing = false;
10455 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10456 if(this.monitorTab){
10457 this.el.un("keydown", this.checkTab, this);
10459 //this.wrap.removeClass('x-trigger-wrap-focus');
10460 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10464 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10465 validateBlur : function(e, t){
10470 onDisable : function(){
10471 this.inputEl().dom.disabled = true;
10472 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10474 // this.wrap.addClass('x-item-disabled');
10479 onEnable : function(){
10480 this.inputEl().dom.disabled = false;
10481 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10483 // this.el.removeClass('x-item-disabled');
10488 onShow : function(){
10489 var ae = this.getActionEl();
10492 ae.dom.style.display = '';
10493 ae.dom.style.visibility = 'visible';
10499 onHide : function(){
10500 var ae = this.getActionEl();
10501 ae.dom.style.display = 'none';
10505 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10506 * by an implementing function.
10508 * @param {EventObject} e
10510 onTriggerClick : Roo.emptyFn
10514 * Ext JS Library 1.1.1
10515 * Copyright(c) 2006-2007, Ext JS, LLC.
10517 * Originally Released Under LGPL - original licence link has changed is not relivant.
10520 * <script type="text/javascript">
10525 * @class Roo.data.SortTypes
10527 * Defines the default sorting (casting?) comparison functions used when sorting data.
10529 Roo.data.SortTypes = {
10531 * Default sort that does nothing
10532 * @param {Mixed} s The value being converted
10533 * @return {Mixed} The comparison value
10535 none : function(s){
10540 * The regular expression used to strip tags
10544 stripTagsRE : /<\/?[^>]+>/gi,
10547 * Strips all HTML tags to sort on text only
10548 * @param {Mixed} s The value being converted
10549 * @return {String} The comparison value
10551 asText : function(s){
10552 return String(s).replace(this.stripTagsRE, "");
10556 * Strips all HTML tags to sort on text only - Case insensitive
10557 * @param {Mixed} s The value being converted
10558 * @return {String} The comparison value
10560 asUCText : function(s){
10561 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10565 * Case insensitive string
10566 * @param {Mixed} s The value being converted
10567 * @return {String} The comparison value
10569 asUCString : function(s) {
10570 return String(s).toUpperCase();
10575 * @param {Mixed} s The value being converted
10576 * @return {Number} The comparison value
10578 asDate : function(s) {
10582 if(s instanceof Date){
10583 return s.getTime();
10585 return Date.parse(String(s));
10590 * @param {Mixed} s The value being converted
10591 * @return {Float} The comparison value
10593 asFloat : function(s) {
10594 var val = parseFloat(String(s).replace(/,/g, ""));
10603 * @param {Mixed} s The value being converted
10604 * @return {Number} The comparison value
10606 asInt : function(s) {
10607 var val = parseInt(String(s).replace(/,/g, ""));
10615 * Ext JS Library 1.1.1
10616 * Copyright(c) 2006-2007, Ext JS, LLC.
10618 * Originally Released Under LGPL - original licence link has changed is not relivant.
10621 * <script type="text/javascript">
10625 * @class Roo.data.Record
10626 * Instances of this class encapsulate both record <em>definition</em> information, and record
10627 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10628 * to access Records cached in an {@link Roo.data.Store} object.<br>
10630 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10631 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10634 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10636 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10637 * {@link #create}. The parameters are the same.
10638 * @param {Array} data An associative Array of data values keyed by the field name.
10639 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10640 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10641 * not specified an integer id is generated.
10643 Roo.data.Record = function(data, id){
10644 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10649 * Generate a constructor for a specific record layout.
10650 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10651 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10652 * Each field definition object may contain the following properties: <ul>
10653 * <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,
10654 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10655 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10656 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10657 * is being used, then this is a string containing the javascript expression to reference the data relative to
10658 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10659 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10660 * this may be omitted.</p></li>
10661 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10662 * <ul><li>auto (Default, implies no conversion)</li>
10667 * <li>date</li></ul></p></li>
10668 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10669 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10670 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10671 * by the Reader into an object that will be stored in the Record. It is passed the
10672 * following parameters:<ul>
10673 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10675 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10677 * <br>usage:<br><pre><code>
10678 var TopicRecord = Roo.data.Record.create(
10679 {name: 'title', mapping: 'topic_title'},
10680 {name: 'author', mapping: 'username'},
10681 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10682 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10683 {name: 'lastPoster', mapping: 'user2'},
10684 {name: 'excerpt', mapping: 'post_text'}
10687 var myNewRecord = new TopicRecord({
10688 title: 'Do my job please',
10691 lastPost: new Date(),
10692 lastPoster: 'Animal',
10693 excerpt: 'No way dude!'
10695 myStore.add(myNewRecord);
10700 Roo.data.Record.create = function(o){
10701 var f = function(){
10702 f.superclass.constructor.apply(this, arguments);
10704 Roo.extend(f, Roo.data.Record);
10705 var p = f.prototype;
10706 p.fields = new Roo.util.MixedCollection(false, function(field){
10709 for(var i = 0, len = o.length; i < len; i++){
10710 p.fields.add(new Roo.data.Field(o[i]));
10712 f.getField = function(name){
10713 return p.fields.get(name);
10718 Roo.data.Record.AUTO_ID = 1000;
10719 Roo.data.Record.EDIT = 'edit';
10720 Roo.data.Record.REJECT = 'reject';
10721 Roo.data.Record.COMMIT = 'commit';
10723 Roo.data.Record.prototype = {
10725 * Readonly flag - true if this record has been modified.
10734 join : function(store){
10735 this.store = store;
10739 * Set the named field to the specified value.
10740 * @param {String} name The name of the field to set.
10741 * @param {Object} value The value to set the field to.
10743 set : function(name, value){
10744 if(this.data[name] == value){
10748 if(!this.modified){
10749 this.modified = {};
10751 if(typeof this.modified[name] == 'undefined'){
10752 this.modified[name] = this.data[name];
10754 this.data[name] = value;
10755 if(!this.editing && this.store){
10756 this.store.afterEdit(this);
10761 * Get the value of the named field.
10762 * @param {String} name The name of the field to get the value of.
10763 * @return {Object} The value of the field.
10765 get : function(name){
10766 return this.data[name];
10770 beginEdit : function(){
10771 this.editing = true;
10772 this.modified = {};
10776 cancelEdit : function(){
10777 this.editing = false;
10778 delete this.modified;
10782 endEdit : function(){
10783 this.editing = false;
10784 if(this.dirty && this.store){
10785 this.store.afterEdit(this);
10790 * Usually called by the {@link Roo.data.Store} which owns the Record.
10791 * Rejects all changes made to the Record since either creation, or the last commit operation.
10792 * Modified fields are reverted to their original values.
10794 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10795 * of reject operations.
10797 reject : function(){
10798 var m = this.modified;
10800 if(typeof m[n] != "function"){
10801 this.data[n] = m[n];
10804 this.dirty = false;
10805 delete this.modified;
10806 this.editing = false;
10808 this.store.afterReject(this);
10813 * Usually called by the {@link Roo.data.Store} which owns the Record.
10814 * Commits all changes made to the Record since either creation, or the last commit operation.
10816 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10817 * of commit operations.
10819 commit : function(){
10820 this.dirty = false;
10821 delete this.modified;
10822 this.editing = false;
10824 this.store.afterCommit(this);
10829 hasError : function(){
10830 return this.error != null;
10834 clearError : function(){
10839 * Creates a copy of this record.
10840 * @param {String} id (optional) A new record id if you don't want to use this record's id
10843 copy : function(newId) {
10844 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10848 * Ext JS Library 1.1.1
10849 * Copyright(c) 2006-2007, Ext JS, LLC.
10851 * Originally Released Under LGPL - original licence link has changed is not relivant.
10854 * <script type="text/javascript">
10860 * @class Roo.data.Store
10861 * @extends Roo.util.Observable
10862 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10863 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10865 * 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
10866 * has no knowledge of the format of the data returned by the Proxy.<br>
10868 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10869 * instances from the data object. These records are cached and made available through accessor functions.
10871 * Creates a new Store.
10872 * @param {Object} config A config object containing the objects needed for the Store to access data,
10873 * and read the data into Records.
10875 Roo.data.Store = function(config){
10876 this.data = new Roo.util.MixedCollection(false);
10877 this.data.getKey = function(o){
10880 this.baseParams = {};
10882 this.paramNames = {
10887 "multisort" : "_multisort"
10890 if(config && config.data){
10891 this.inlineData = config.data;
10892 delete config.data;
10895 Roo.apply(this, config);
10897 if(this.reader){ // reader passed
10898 this.reader = Roo.factory(this.reader, Roo.data);
10899 this.reader.xmodule = this.xmodule || false;
10900 if(!this.recordType){
10901 this.recordType = this.reader.recordType;
10903 if(this.reader.onMetaChange){
10904 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10908 if(this.recordType){
10909 this.fields = this.recordType.prototype.fields;
10911 this.modified = [];
10915 * @event datachanged
10916 * Fires when the data cache has changed, and a widget which is using this Store
10917 * as a Record cache should refresh its view.
10918 * @param {Store} this
10920 datachanged : true,
10922 * @event metachange
10923 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10924 * @param {Store} this
10925 * @param {Object} meta The JSON metadata
10930 * Fires when Records have been added to the Store
10931 * @param {Store} this
10932 * @param {Roo.data.Record[]} records The array of Records added
10933 * @param {Number} index The index at which the record(s) were added
10938 * Fires when a Record has been removed from the Store
10939 * @param {Store} this
10940 * @param {Roo.data.Record} record The Record that was removed
10941 * @param {Number} index The index at which the record was removed
10946 * Fires when a Record has been updated
10947 * @param {Store} this
10948 * @param {Roo.data.Record} record The Record that was updated
10949 * @param {String} operation The update operation being performed. Value may be one of:
10951 Roo.data.Record.EDIT
10952 Roo.data.Record.REJECT
10953 Roo.data.Record.COMMIT
10959 * Fires when the data cache has been cleared.
10960 * @param {Store} this
10964 * @event beforeload
10965 * Fires before a request is made for a new data object. If the beforeload handler returns false
10966 * the load action will be canceled.
10967 * @param {Store} this
10968 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10972 * @event beforeloadadd
10973 * Fires after a new set of Records has been loaded.
10974 * @param {Store} this
10975 * @param {Roo.data.Record[]} records The Records that were loaded
10976 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10978 beforeloadadd : true,
10981 * Fires after a new set of Records has been loaded, before they are added to the store.
10982 * @param {Store} this
10983 * @param {Roo.data.Record[]} records The Records that were loaded
10984 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10985 * @params {Object} return from reader
10989 * @event loadexception
10990 * Fires if an exception occurs in the Proxy during loading.
10991 * Called with the signature of the Proxy's "loadexception" event.
10992 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10995 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10996 * @param {Object} load options
10997 * @param {Object} jsonData from your request (normally this contains the Exception)
10999 loadexception : true
11003 this.proxy = Roo.factory(this.proxy, Roo.data);
11004 this.proxy.xmodule = this.xmodule || false;
11005 this.relayEvents(this.proxy, ["loadexception"]);
11007 this.sortToggle = {};
11008 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11010 Roo.data.Store.superclass.constructor.call(this);
11012 if(this.inlineData){
11013 this.loadData(this.inlineData);
11014 delete this.inlineData;
11018 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11020 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11021 * without a remote query - used by combo/forms at present.
11025 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11028 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11031 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11032 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11035 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11036 * on any HTTP request
11039 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11042 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11046 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11047 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11049 remoteSort : false,
11052 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11053 * loaded or when a record is removed. (defaults to false).
11055 pruneModifiedRecords : false,
11058 lastOptions : null,
11061 * Add Records to the Store and fires the add event.
11062 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11064 add : function(records){
11065 records = [].concat(records);
11066 for(var i = 0, len = records.length; i < len; i++){
11067 records[i].join(this);
11069 var index = this.data.length;
11070 this.data.addAll(records);
11071 this.fireEvent("add", this, records, index);
11075 * Remove a Record from the Store and fires the remove event.
11076 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11078 remove : function(record){
11079 var index = this.data.indexOf(record);
11080 this.data.removeAt(index);
11081 if(this.pruneModifiedRecords){
11082 this.modified.remove(record);
11084 this.fireEvent("remove", this, record, index);
11088 * Remove all Records from the Store and fires the clear event.
11090 removeAll : function(){
11092 if(this.pruneModifiedRecords){
11093 this.modified = [];
11095 this.fireEvent("clear", this);
11099 * Inserts Records to the Store at the given index and fires the add event.
11100 * @param {Number} index The start index at which to insert the passed Records.
11101 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11103 insert : function(index, records){
11104 records = [].concat(records);
11105 for(var i = 0, len = records.length; i < len; i++){
11106 this.data.insert(index, records[i]);
11107 records[i].join(this);
11109 this.fireEvent("add", this, records, index);
11113 * Get the index within the cache of the passed Record.
11114 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11115 * @return {Number} The index of the passed Record. Returns -1 if not found.
11117 indexOf : function(record){
11118 return this.data.indexOf(record);
11122 * Get the index within the cache of the Record with the passed id.
11123 * @param {String} id The id of the Record to find.
11124 * @return {Number} The index of the Record. Returns -1 if not found.
11126 indexOfId : function(id){
11127 return this.data.indexOfKey(id);
11131 * Get the Record with the specified id.
11132 * @param {String} id The id of the Record to find.
11133 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11135 getById : function(id){
11136 return this.data.key(id);
11140 * Get the Record at the specified index.
11141 * @param {Number} index The index of the Record to find.
11142 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11144 getAt : function(index){
11145 return this.data.itemAt(index);
11149 * Returns a range of Records between specified indices.
11150 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11151 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11152 * @return {Roo.data.Record[]} An array of Records
11154 getRange : function(start, end){
11155 return this.data.getRange(start, end);
11159 storeOptions : function(o){
11160 o = Roo.apply({}, o);
11163 this.lastOptions = o;
11167 * Loads the Record cache from the configured Proxy using the configured Reader.
11169 * If using remote paging, then the first load call must specify the <em>start</em>
11170 * and <em>limit</em> properties in the options.params property to establish the initial
11171 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11173 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11174 * and this call will return before the new data has been loaded. Perform any post-processing
11175 * in a callback function, or in a "load" event handler.</strong>
11177 * @param {Object} options An object containing properties which control loading options:<ul>
11178 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11179 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11180 * passed the following arguments:<ul>
11181 * <li>r : Roo.data.Record[]</li>
11182 * <li>options: Options object from the load call</li>
11183 * <li>success: Boolean success indicator</li></ul></li>
11184 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11185 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11188 load : function(options){
11189 options = options || {};
11190 if(this.fireEvent("beforeload", this, options) !== false){
11191 this.storeOptions(options);
11192 var p = Roo.apply(options.params || {}, this.baseParams);
11193 // if meta was not loaded from remote source.. try requesting it.
11194 if (!this.reader.metaFromRemote) {
11195 p._requestMeta = 1;
11197 if(this.sortInfo && this.remoteSort){
11198 var pn = this.paramNames;
11199 p[pn["sort"]] = this.sortInfo.field;
11200 p[pn["dir"]] = this.sortInfo.direction;
11202 if (this.multiSort) {
11203 var pn = this.paramNames;
11204 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11207 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11212 * Reloads the Record cache from the configured Proxy using the configured Reader and
11213 * the options from the last load operation performed.
11214 * @param {Object} options (optional) An object containing properties which may override the options
11215 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11216 * the most recently used options are reused).
11218 reload : function(options){
11219 this.load(Roo.applyIf(options||{}, this.lastOptions));
11223 // Called as a callback by the Reader during a load operation.
11224 loadRecords : function(o, options, success){
11225 if(!o || success === false){
11226 if(success !== false){
11227 this.fireEvent("load", this, [], options, o);
11229 if(options.callback){
11230 options.callback.call(options.scope || this, [], options, false);
11234 // if data returned failure - throw an exception.
11235 if (o.success === false) {
11236 // show a message if no listener is registered.
11237 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11238 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11240 // loadmask wil be hooked into this..
11241 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11244 var r = o.records, t = o.totalRecords || r.length;
11246 this.fireEvent("beforeloadadd", this, r, options, o);
11248 if(!options || options.add !== true){
11249 if(this.pruneModifiedRecords){
11250 this.modified = [];
11252 for(var i = 0, len = r.length; i < len; i++){
11256 this.data = this.snapshot;
11257 delete this.snapshot;
11260 this.data.addAll(r);
11261 this.totalLength = t;
11263 this.fireEvent("datachanged", this);
11265 this.totalLength = Math.max(t, this.data.length+r.length);
11269 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11271 var e = new Roo.data.Record({});
11273 e.set(this.parent.displayField, this.parent.emptyTitle);
11274 e.set(this.parent.valueField, '');
11279 this.fireEvent("load", this, r, options, o);
11280 if(options.callback){
11281 options.callback.call(options.scope || this, r, options, true);
11287 * Loads data from a passed data block. A Reader which understands the format of the data
11288 * must have been configured in the constructor.
11289 * @param {Object} data The data block from which to read the Records. The format of the data expected
11290 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11291 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11293 loadData : function(o, append){
11294 var r = this.reader.readRecords(o);
11295 this.loadRecords(r, {add: append}, true);
11299 * Gets the number of cached records.
11301 * <em>If using paging, this may not be the total size of the dataset. If the data object
11302 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11303 * the data set size</em>
11305 getCount : function(){
11306 return this.data.length || 0;
11310 * Gets the total number of records in the dataset as returned by the server.
11312 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11313 * the dataset size</em>
11315 getTotalCount : function(){
11316 return this.totalLength || 0;
11320 * Returns the sort state of the Store as an object with two properties:
11322 field {String} The name of the field by which the Records are sorted
11323 direction {String} The sort order, "ASC" or "DESC"
11326 getSortState : function(){
11327 return this.sortInfo;
11331 applySort : function(){
11332 if(this.sortInfo && !this.remoteSort){
11333 var s = this.sortInfo, f = s.field;
11334 var st = this.fields.get(f).sortType;
11335 var fn = function(r1, r2){
11336 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11337 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11339 this.data.sort(s.direction, fn);
11340 if(this.snapshot && this.snapshot != this.data){
11341 this.snapshot.sort(s.direction, fn);
11347 * Sets the default sort column and order to be used by the next load operation.
11348 * @param {String} fieldName The name of the field to sort by.
11349 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11351 setDefaultSort : function(field, dir){
11352 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11356 * Sort the Records.
11357 * If remote sorting is used, the sort is performed on the server, and the cache is
11358 * reloaded. If local sorting is used, the cache is sorted internally.
11359 * @param {String} fieldName The name of the field to sort by.
11360 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11362 sort : function(fieldName, dir){
11363 var f = this.fields.get(fieldName);
11365 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11367 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11368 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11373 this.sortToggle[f.name] = dir;
11374 this.sortInfo = {field: f.name, direction: dir};
11375 if(!this.remoteSort){
11377 this.fireEvent("datachanged", this);
11379 this.load(this.lastOptions);
11384 * Calls the specified function for each of the Records in the cache.
11385 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11386 * Returning <em>false</em> aborts and exits the iteration.
11387 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11389 each : function(fn, scope){
11390 this.data.each(fn, scope);
11394 * Gets all records modified since the last commit. Modified records are persisted across load operations
11395 * (e.g., during paging).
11396 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11398 getModifiedRecords : function(){
11399 return this.modified;
11403 createFilterFn : function(property, value, anyMatch){
11404 if(!value.exec){ // not a regex
11405 value = String(value);
11406 if(value.length == 0){
11409 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11411 return function(r){
11412 return value.test(r.data[property]);
11417 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11418 * @param {String} property A field on your records
11419 * @param {Number} start The record index to start at (defaults to 0)
11420 * @param {Number} end The last record index to include (defaults to length - 1)
11421 * @return {Number} The sum
11423 sum : function(property, start, end){
11424 var rs = this.data.items, v = 0;
11425 start = start || 0;
11426 end = (end || end === 0) ? end : rs.length-1;
11428 for(var i = start; i <= end; i++){
11429 v += (rs[i].data[property] || 0);
11435 * Filter the records by a specified property.
11436 * @param {String} field A field on your records
11437 * @param {String/RegExp} value Either a string that the field
11438 * should start with or a RegExp to test against the field
11439 * @param {Boolean} anyMatch True to match any part not just the beginning
11441 filter : function(property, value, anyMatch){
11442 var fn = this.createFilterFn(property, value, anyMatch);
11443 return fn ? this.filterBy(fn) : this.clearFilter();
11447 * Filter by a function. The specified function will be called with each
11448 * record in this data source. If the function returns true the record is included,
11449 * otherwise it is filtered.
11450 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11451 * @param {Object} scope (optional) The scope of the function (defaults to this)
11453 filterBy : function(fn, scope){
11454 this.snapshot = this.snapshot || this.data;
11455 this.data = this.queryBy(fn, scope||this);
11456 this.fireEvent("datachanged", this);
11460 * Query the records by a specified property.
11461 * @param {String} field A field on your records
11462 * @param {String/RegExp} value Either a string that the field
11463 * should start with or a RegExp to test against the field
11464 * @param {Boolean} anyMatch True to match any part not just the beginning
11465 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11467 query : function(property, value, anyMatch){
11468 var fn = this.createFilterFn(property, value, anyMatch);
11469 return fn ? this.queryBy(fn) : this.data.clone();
11473 * Query by a function. The specified function will be called with each
11474 * record in this data source. If the function returns true the record is included
11476 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11477 * @param {Object} scope (optional) The scope of the function (defaults to this)
11478 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11480 queryBy : function(fn, scope){
11481 var data = this.snapshot || this.data;
11482 return data.filterBy(fn, scope||this);
11486 * Collects unique values for a particular dataIndex from this store.
11487 * @param {String} dataIndex The property to collect
11488 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11489 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11490 * @return {Array} An array of the unique values
11492 collect : function(dataIndex, allowNull, bypassFilter){
11493 var d = (bypassFilter === true && this.snapshot) ?
11494 this.snapshot.items : this.data.items;
11495 var v, sv, r = [], l = {};
11496 for(var i = 0, len = d.length; i < len; i++){
11497 v = d[i].data[dataIndex];
11499 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11508 * Revert to a view of the Record cache with no filtering applied.
11509 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11511 clearFilter : function(suppressEvent){
11512 if(this.snapshot && this.snapshot != this.data){
11513 this.data = this.snapshot;
11514 delete this.snapshot;
11515 if(suppressEvent !== true){
11516 this.fireEvent("datachanged", this);
11522 afterEdit : function(record){
11523 if(this.modified.indexOf(record) == -1){
11524 this.modified.push(record);
11526 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11530 afterReject : function(record){
11531 this.modified.remove(record);
11532 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11536 afterCommit : function(record){
11537 this.modified.remove(record);
11538 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11542 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11543 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11545 commitChanges : function(){
11546 var m = this.modified.slice(0);
11547 this.modified = [];
11548 for(var i = 0, len = m.length; i < len; i++){
11554 * Cancel outstanding changes on all changed records.
11556 rejectChanges : function(){
11557 var m = this.modified.slice(0);
11558 this.modified = [];
11559 for(var i = 0, len = m.length; i < len; i++){
11564 onMetaChange : function(meta, rtype, o){
11565 this.recordType = rtype;
11566 this.fields = rtype.prototype.fields;
11567 delete this.snapshot;
11568 this.sortInfo = meta.sortInfo || this.sortInfo;
11569 this.modified = [];
11570 this.fireEvent('metachange', this, this.reader.meta);
11573 moveIndex : function(data, type)
11575 var index = this.indexOf(data);
11577 var newIndex = index + type;
11581 this.insert(newIndex, data);
11586 * Ext JS Library 1.1.1
11587 * Copyright(c) 2006-2007, Ext JS, LLC.
11589 * Originally Released Under LGPL - original licence link has changed is not relivant.
11592 * <script type="text/javascript">
11596 * @class Roo.data.SimpleStore
11597 * @extends Roo.data.Store
11598 * Small helper class to make creating Stores from Array data easier.
11599 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11600 * @cfg {Array} fields An array of field definition objects, or field name strings.
11601 * @cfg {Array} data The multi-dimensional array of data
11603 * @param {Object} config
11605 Roo.data.SimpleStore = function(config){
11606 Roo.data.SimpleStore.superclass.constructor.call(this, {
11608 reader: new Roo.data.ArrayReader({
11611 Roo.data.Record.create(config.fields)
11613 proxy : new Roo.data.MemoryProxy(config.data)
11617 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11619 * Ext JS Library 1.1.1
11620 * Copyright(c) 2006-2007, Ext JS, LLC.
11622 * Originally Released Under LGPL - original licence link has changed is not relivant.
11625 * <script type="text/javascript">
11630 * @extends Roo.data.Store
11631 * @class Roo.data.JsonStore
11632 * Small helper class to make creating Stores for JSON data easier. <br/>
11634 var store = new Roo.data.JsonStore({
11635 url: 'get-images.php',
11637 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11640 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11641 * JsonReader and HttpProxy (unless inline data is provided).</b>
11642 * @cfg {Array} fields An array of field definition objects, or field name strings.
11644 * @param {Object} config
11646 Roo.data.JsonStore = function(c){
11647 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11648 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11649 reader: new Roo.data.JsonReader(c, c.fields)
11652 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11654 * Ext JS Library 1.1.1
11655 * Copyright(c) 2006-2007, Ext JS, LLC.
11657 * Originally Released Under LGPL - original licence link has changed is not relivant.
11660 * <script type="text/javascript">
11664 Roo.data.Field = function(config){
11665 if(typeof config == "string"){
11666 config = {name: config};
11668 Roo.apply(this, config);
11671 this.type = "auto";
11674 var st = Roo.data.SortTypes;
11675 // named sortTypes are supported, here we look them up
11676 if(typeof this.sortType == "string"){
11677 this.sortType = st[this.sortType];
11680 // set default sortType for strings and dates
11681 if(!this.sortType){
11684 this.sortType = st.asUCString;
11687 this.sortType = st.asDate;
11690 this.sortType = st.none;
11695 var stripRe = /[\$,%]/g;
11697 // prebuilt conversion function for this field, instead of
11698 // switching every time we're reading a value
11700 var cv, dateFormat = this.dateFormat;
11705 cv = function(v){ return v; };
11708 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11712 return v !== undefined && v !== null && v !== '' ?
11713 parseInt(String(v).replace(stripRe, ""), 10) : '';
11718 return v !== undefined && v !== null && v !== '' ?
11719 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11724 cv = function(v){ return v === true || v === "true" || v == 1; };
11731 if(v instanceof Date){
11735 if(dateFormat == "timestamp"){
11736 return new Date(v*1000);
11738 return Date.parseDate(v, dateFormat);
11740 var parsed = Date.parse(v);
11741 return parsed ? new Date(parsed) : null;
11750 Roo.data.Field.prototype = {
11758 * Ext JS Library 1.1.1
11759 * Copyright(c) 2006-2007, Ext JS, LLC.
11761 * Originally Released Under LGPL - original licence link has changed is not relivant.
11764 * <script type="text/javascript">
11767 // Base class for reading structured data from a data source. This class is intended to be
11768 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11771 * @class Roo.data.DataReader
11772 * Base class for reading structured data from a data source. This class is intended to be
11773 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11776 Roo.data.DataReader = function(meta, recordType){
11780 this.recordType = recordType instanceof Array ?
11781 Roo.data.Record.create(recordType) : recordType;
11784 Roo.data.DataReader.prototype = {
11786 * Create an empty record
11787 * @param {Object} data (optional) - overlay some values
11788 * @return {Roo.data.Record} record created.
11790 newRow : function(d) {
11792 this.recordType.prototype.fields.each(function(c) {
11794 case 'int' : da[c.name] = 0; break;
11795 case 'date' : da[c.name] = new Date(); break;
11796 case 'float' : da[c.name] = 0.0; break;
11797 case 'boolean' : da[c.name] = false; break;
11798 default : da[c.name] = ""; break;
11802 return new this.recordType(Roo.apply(da, d));
11807 * Ext JS Library 1.1.1
11808 * Copyright(c) 2006-2007, Ext JS, LLC.
11810 * Originally Released Under LGPL - original licence link has changed is not relivant.
11813 * <script type="text/javascript">
11817 * @class Roo.data.DataProxy
11818 * @extends Roo.data.Observable
11819 * This class is an abstract base class for implementations which provide retrieval of
11820 * unformatted data objects.<br>
11822 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11823 * (of the appropriate type which knows how to parse the data object) to provide a block of
11824 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11826 * Custom implementations must implement the load method as described in
11827 * {@link Roo.data.HttpProxy#load}.
11829 Roo.data.DataProxy = function(){
11832 * @event beforeload
11833 * Fires before a network request is made to retrieve a data object.
11834 * @param {Object} This DataProxy object.
11835 * @param {Object} params The params parameter to the load function.
11840 * Fires before the load method's callback is called.
11841 * @param {Object} This DataProxy object.
11842 * @param {Object} o The data object.
11843 * @param {Object} arg The callback argument object passed to the load function.
11847 * @event loadexception
11848 * Fires if an Exception occurs during data retrieval.
11849 * @param {Object} This DataProxy object.
11850 * @param {Object} o The data object.
11851 * @param {Object} arg The callback argument object passed to the load function.
11852 * @param {Object} e The Exception.
11854 loadexception : true
11856 Roo.data.DataProxy.superclass.constructor.call(this);
11859 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11862 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11866 * Ext JS Library 1.1.1
11867 * Copyright(c) 2006-2007, Ext JS, LLC.
11869 * Originally Released Under LGPL - original licence link has changed is not relivant.
11872 * <script type="text/javascript">
11875 * @class Roo.data.MemoryProxy
11876 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11877 * to the Reader when its load method is called.
11879 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11881 Roo.data.MemoryProxy = function(data){
11885 Roo.data.MemoryProxy.superclass.constructor.call(this);
11889 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11892 * Load data from the requested source (in this case an in-memory
11893 * data object passed to the constructor), read the data object into
11894 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11895 * process that block using the passed callback.
11896 * @param {Object} params This parameter is not used by the MemoryProxy class.
11897 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11898 * object into a block of Roo.data.Records.
11899 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11900 * The function must be passed <ul>
11901 * <li>The Record block object</li>
11902 * <li>The "arg" argument from the load function</li>
11903 * <li>A boolean success indicator</li>
11905 * @param {Object} scope The scope in which to call the callback
11906 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11908 load : function(params, reader, callback, scope, arg){
11909 params = params || {};
11912 result = reader.readRecords(this.data);
11914 this.fireEvent("loadexception", this, arg, null, e);
11915 callback.call(scope, null, arg, false);
11918 callback.call(scope, result, arg, true);
11922 update : function(params, records){
11927 * Ext JS Library 1.1.1
11928 * Copyright(c) 2006-2007, Ext JS, LLC.
11930 * Originally Released Under LGPL - original licence link has changed is not relivant.
11933 * <script type="text/javascript">
11936 * @class Roo.data.HttpProxy
11937 * @extends Roo.data.DataProxy
11938 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11939 * configured to reference a certain URL.<br><br>
11941 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11942 * from which the running page was served.<br><br>
11944 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11946 * Be aware that to enable the browser to parse an XML document, the server must set
11947 * the Content-Type header in the HTTP response to "text/xml".
11949 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11950 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11951 * will be used to make the request.
11953 Roo.data.HttpProxy = function(conn){
11954 Roo.data.HttpProxy.superclass.constructor.call(this);
11955 // is conn a conn config or a real conn?
11957 this.useAjax = !conn || !conn.events;
11961 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11962 // thse are take from connection...
11965 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11968 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11969 * extra parameters to each request made by this object. (defaults to undefined)
11972 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11973 * to each request made by this object. (defaults to undefined)
11976 * @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)
11979 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11982 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11988 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11992 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11993 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11994 * a finer-grained basis than the DataProxy events.
11996 getConnection : function(){
11997 return this.useAjax ? Roo.Ajax : this.conn;
12001 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12002 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12003 * process that block using the passed callback.
12004 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12005 * for the request to the remote server.
12006 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12007 * object into a block of Roo.data.Records.
12008 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12009 * The function must be passed <ul>
12010 * <li>The Record block object</li>
12011 * <li>The "arg" argument from the load function</li>
12012 * <li>A boolean success indicator</li>
12014 * @param {Object} scope The scope in which to call the callback
12015 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12017 load : function(params, reader, callback, scope, arg){
12018 if(this.fireEvent("beforeload", this, params) !== false){
12020 params : params || {},
12022 callback : callback,
12027 callback : this.loadResponse,
12031 Roo.applyIf(o, this.conn);
12032 if(this.activeRequest){
12033 Roo.Ajax.abort(this.activeRequest);
12035 this.activeRequest = Roo.Ajax.request(o);
12037 this.conn.request(o);
12040 callback.call(scope||this, null, arg, false);
12045 loadResponse : function(o, success, response){
12046 delete this.activeRequest;
12048 this.fireEvent("loadexception", this, o, response);
12049 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12054 result = o.reader.read(response);
12056 this.fireEvent("loadexception", this, o, response, e);
12057 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12061 this.fireEvent("load", this, o, o.request.arg);
12062 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12066 update : function(dataSet){
12071 updateResponse : function(dataSet){
12076 * Ext JS Library 1.1.1
12077 * Copyright(c) 2006-2007, Ext JS, LLC.
12079 * Originally Released Under LGPL - original licence link has changed is not relivant.
12082 * <script type="text/javascript">
12086 * @class Roo.data.ScriptTagProxy
12087 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12088 * other than the originating domain of the running page.<br><br>
12090 * <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
12091 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12093 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12094 * source code that is used as the source inside a <script> tag.<br><br>
12096 * In order for the browser to process the returned data, the server must wrap the data object
12097 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12098 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12099 * depending on whether the callback name was passed:
12102 boolean scriptTag = false;
12103 String cb = request.getParameter("callback");
12106 response.setContentType("text/javascript");
12108 response.setContentType("application/x-json");
12110 Writer out = response.getWriter();
12112 out.write(cb + "(");
12114 out.print(dataBlock.toJsonString());
12121 * @param {Object} config A configuration object.
12123 Roo.data.ScriptTagProxy = function(config){
12124 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12125 Roo.apply(this, config);
12126 this.head = document.getElementsByTagName("head")[0];
12129 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12131 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12133 * @cfg {String} url The URL from which to request the data object.
12136 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12140 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12141 * the server the name of the callback function set up by the load call to process the returned data object.
12142 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12143 * javascript output which calls this named function passing the data object as its only parameter.
12145 callbackParam : "callback",
12147 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12148 * name to the request.
12153 * Load data from the configured URL, read the data object into
12154 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12155 * process that block using the passed callback.
12156 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12157 * for the request to the remote server.
12158 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12159 * object into a block of Roo.data.Records.
12160 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12161 * The function must be passed <ul>
12162 * <li>The Record block object</li>
12163 * <li>The "arg" argument from the load function</li>
12164 * <li>A boolean success indicator</li>
12166 * @param {Object} scope The scope in which to call the callback
12167 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12169 load : function(params, reader, callback, scope, arg){
12170 if(this.fireEvent("beforeload", this, params) !== false){
12172 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12174 var url = this.url;
12175 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12177 url += "&_dc=" + (new Date().getTime());
12179 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12182 cb : "stcCallback"+transId,
12183 scriptId : "stcScript"+transId,
12187 callback : callback,
12193 window[trans.cb] = function(o){
12194 conn.handleResponse(o, trans);
12197 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12199 if(this.autoAbort !== false){
12203 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12205 var script = document.createElement("script");
12206 script.setAttribute("src", url);
12207 script.setAttribute("type", "text/javascript");
12208 script.setAttribute("id", trans.scriptId);
12209 this.head.appendChild(script);
12211 this.trans = trans;
12213 callback.call(scope||this, null, arg, false);
12218 isLoading : function(){
12219 return this.trans ? true : false;
12223 * Abort the current server request.
12225 abort : function(){
12226 if(this.isLoading()){
12227 this.destroyTrans(this.trans);
12232 destroyTrans : function(trans, isLoaded){
12233 this.head.removeChild(document.getElementById(trans.scriptId));
12234 clearTimeout(trans.timeoutId);
12236 window[trans.cb] = undefined;
12238 delete window[trans.cb];
12241 // if hasn't been loaded, wait for load to remove it to prevent script error
12242 window[trans.cb] = function(){
12243 window[trans.cb] = undefined;
12245 delete window[trans.cb];
12252 handleResponse : function(o, trans){
12253 this.trans = false;
12254 this.destroyTrans(trans, true);
12257 result = trans.reader.readRecords(o);
12259 this.fireEvent("loadexception", this, o, trans.arg, e);
12260 trans.callback.call(trans.scope||window, null, trans.arg, false);
12263 this.fireEvent("load", this, o, trans.arg);
12264 trans.callback.call(trans.scope||window, result, trans.arg, true);
12268 handleFailure : function(trans){
12269 this.trans = false;
12270 this.destroyTrans(trans, false);
12271 this.fireEvent("loadexception", this, null, trans.arg);
12272 trans.callback.call(trans.scope||window, null, trans.arg, false);
12276 * Ext JS Library 1.1.1
12277 * Copyright(c) 2006-2007, Ext JS, LLC.
12279 * Originally Released Under LGPL - original licence link has changed is not relivant.
12282 * <script type="text/javascript">
12286 * @class Roo.data.JsonReader
12287 * @extends Roo.data.DataReader
12288 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12289 * based on mappings in a provided Roo.data.Record constructor.
12291 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12292 * in the reply previously.
12297 var RecordDef = Roo.data.Record.create([
12298 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12299 {name: 'occupation'} // This field will use "occupation" as the mapping.
12301 var myReader = new Roo.data.JsonReader({
12302 totalProperty: "results", // The property which contains the total dataset size (optional)
12303 root: "rows", // The property which contains an Array of row objects
12304 id: "id" // The property within each row object that provides an ID for the record (optional)
12308 * This would consume a JSON file like this:
12310 { 'results': 2, 'rows': [
12311 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12312 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12315 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12316 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12317 * paged from the remote server.
12318 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12319 * @cfg {String} root name of the property which contains the Array of row objects.
12320 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12321 * @cfg {Array} fields Array of field definition objects
12323 * Create a new JsonReader
12324 * @param {Object} meta Metadata configuration options
12325 * @param {Object} recordType Either an Array of field definition objects,
12326 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12328 Roo.data.JsonReader = function(meta, recordType){
12331 // set some defaults:
12332 Roo.applyIf(meta, {
12333 totalProperty: 'total',
12334 successProperty : 'success',
12339 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12341 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12344 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12345 * Used by Store query builder to append _requestMeta to params.
12348 metaFromRemote : false,
12350 * This method is only used by a DataProxy which has retrieved data from a remote server.
12351 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12352 * @return {Object} data A data block which is used by an Roo.data.Store object as
12353 * a cache of Roo.data.Records.
12355 read : function(response){
12356 var json = response.responseText;
12358 var o = /* eval:var:o */ eval("("+json+")");
12360 throw {message: "JsonReader.read: Json object not found"};
12366 this.metaFromRemote = true;
12367 this.meta = o.metaData;
12368 this.recordType = Roo.data.Record.create(o.metaData.fields);
12369 this.onMetaChange(this.meta, this.recordType, o);
12371 return this.readRecords(o);
12374 // private function a store will implement
12375 onMetaChange : function(meta, recordType, o){
12382 simpleAccess: function(obj, subsc) {
12389 getJsonAccessor: function(){
12391 return function(expr) {
12393 return(re.test(expr))
12394 ? new Function("obj", "return obj." + expr)
12399 return Roo.emptyFn;
12404 * Create a data block containing Roo.data.Records from an XML document.
12405 * @param {Object} o An object which contains an Array of row objects in the property specified
12406 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12407 * which contains the total size of the dataset.
12408 * @return {Object} data A data block which is used by an Roo.data.Store object as
12409 * a cache of Roo.data.Records.
12411 readRecords : function(o){
12413 * After any data loads, the raw JSON data is available for further custom processing.
12417 var s = this.meta, Record = this.recordType,
12418 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12420 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12422 if(s.totalProperty) {
12423 this.getTotal = this.getJsonAccessor(s.totalProperty);
12425 if(s.successProperty) {
12426 this.getSuccess = this.getJsonAccessor(s.successProperty);
12428 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12430 var g = this.getJsonAccessor(s.id);
12431 this.getId = function(rec) {
12433 return (r === undefined || r === "") ? null : r;
12436 this.getId = function(){return null;};
12439 for(var jj = 0; jj < fl; jj++){
12441 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12442 this.ef[jj] = this.getJsonAccessor(map);
12446 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12447 if(s.totalProperty){
12448 var vt = parseInt(this.getTotal(o), 10);
12453 if(s.successProperty){
12454 var vs = this.getSuccess(o);
12455 if(vs === false || vs === 'false'){
12460 for(var i = 0; i < c; i++){
12463 var id = this.getId(n);
12464 for(var j = 0; j < fl; j++){
12466 var v = this.ef[j](n);
12468 Roo.log('missing convert for ' + f.name);
12472 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12474 var record = new Record(values, id);
12476 records[i] = record;
12482 totalRecords : totalRecords
12487 * Ext JS Library 1.1.1
12488 * Copyright(c) 2006-2007, Ext JS, LLC.
12490 * Originally Released Under LGPL - original licence link has changed is not relivant.
12493 * <script type="text/javascript">
12497 * @class Roo.data.ArrayReader
12498 * @extends Roo.data.DataReader
12499 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12500 * Each element of that Array represents a row of data fields. The
12501 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12502 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12506 var RecordDef = Roo.data.Record.create([
12507 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12508 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12510 var myReader = new Roo.data.ArrayReader({
12511 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12515 * This would consume an Array like this:
12517 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12519 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12521 * Create a new JsonReader
12522 * @param {Object} meta Metadata configuration options.
12523 * @param {Object} recordType Either an Array of field definition objects
12524 * as specified to {@link Roo.data.Record#create},
12525 * or an {@link Roo.data.Record} object
12526 * created using {@link Roo.data.Record#create}.
12528 Roo.data.ArrayReader = function(meta, recordType){
12529 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12532 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12534 * Create a data block containing Roo.data.Records from an XML document.
12535 * @param {Object} o An Array of row objects which represents the dataset.
12536 * @return {Object} data A data block which is used by an Roo.data.Store object as
12537 * a cache of Roo.data.Records.
12539 readRecords : function(o){
12540 var sid = this.meta ? this.meta.id : null;
12541 var recordType = this.recordType, fields = recordType.prototype.fields;
12544 for(var i = 0; i < root.length; i++){
12547 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12548 for(var j = 0, jlen = fields.length; j < jlen; j++){
12549 var f = fields.items[j];
12550 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12551 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12553 values[f.name] = v;
12555 var record = new recordType(values, id);
12557 records[records.length] = record;
12561 totalRecords : records.length
12570 * @class Roo.bootstrap.ComboBox
12571 * @extends Roo.bootstrap.TriggerField
12572 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12573 * @cfg {Boolean} append (true|false) default false
12574 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12575 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12576 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12577 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12578 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12579 * @cfg {Boolean} animate default true
12580 * @cfg {Boolean} emptyResultText only for touch device
12581 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12582 * @cfg {String} emptyTitle default ''
12584 * Create a new ComboBox.
12585 * @param {Object} config Configuration options
12587 Roo.bootstrap.ComboBox = function(config){
12588 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12592 * Fires when the dropdown list is expanded
12593 * @param {Roo.bootstrap.ComboBox} combo This combo box
12598 * Fires when the dropdown list is collapsed
12599 * @param {Roo.bootstrap.ComboBox} combo This combo box
12603 * @event beforeselect
12604 * Fires before a list item is selected. Return false to cancel the selection.
12605 * @param {Roo.bootstrap.ComboBox} combo This combo box
12606 * @param {Roo.data.Record} record The data record returned from the underlying store
12607 * @param {Number} index The index of the selected item in the dropdown list
12609 'beforeselect' : true,
12612 * Fires when a list item is selected
12613 * @param {Roo.bootstrap.ComboBox} combo This combo box
12614 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12615 * @param {Number} index The index of the selected item in the dropdown list
12619 * @event beforequery
12620 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12621 * The event object passed has these properties:
12622 * @param {Roo.bootstrap.ComboBox} combo This combo box
12623 * @param {String} query The query
12624 * @param {Boolean} forceAll true to force "all" query
12625 * @param {Boolean} cancel true to cancel the query
12626 * @param {Object} e The query event object
12628 'beforequery': true,
12631 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12632 * @param {Roo.bootstrap.ComboBox} combo This combo box
12637 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12638 * @param {Roo.bootstrap.ComboBox} combo This combo box
12639 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12644 * Fires when the remove value from the combobox array
12645 * @param {Roo.bootstrap.ComboBox} combo This combo box
12649 * @event afterremove
12650 * Fires when the remove value from the combobox array
12651 * @param {Roo.bootstrap.ComboBox} combo This combo box
12653 'afterremove' : true,
12655 * @event specialfilter
12656 * Fires when specialfilter
12657 * @param {Roo.bootstrap.ComboBox} combo This combo box
12659 'specialfilter' : true,
12662 * Fires when tick the element
12663 * @param {Roo.bootstrap.ComboBox} combo This combo box
12667 * @event touchviewdisplay
12668 * Fires when touch view require special display (default is using displayField)
12669 * @param {Roo.bootstrap.ComboBox} combo This combo box
12670 * @param {Object} cfg set html .
12672 'touchviewdisplay' : true
12677 this.tickItems = [];
12679 this.selectedIndex = -1;
12680 if(this.mode == 'local'){
12681 if(config.queryDelay === undefined){
12682 this.queryDelay = 10;
12684 if(config.minChars === undefined){
12690 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12693 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12694 * rendering into an Roo.Editor, defaults to false)
12697 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12698 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12701 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12704 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12705 * the dropdown list (defaults to undefined, with no header element)
12709 * @cfg {String/Roo.Template} tpl The template to use to render the output
12713 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12715 listWidth: undefined,
12717 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12718 * mode = 'remote' or 'text' if mode = 'local')
12720 displayField: undefined,
12723 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12724 * mode = 'remote' or 'value' if mode = 'local').
12725 * Note: use of a valueField requires the user make a selection
12726 * in order for a value to be mapped.
12728 valueField: undefined,
12730 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12735 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12736 * field's data value (defaults to the underlying DOM element's name)
12738 hiddenName: undefined,
12740 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12744 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12746 selectedClass: 'active',
12749 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12753 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12754 * anchor positions (defaults to 'tl-bl')
12756 listAlign: 'tl-bl?',
12758 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12762 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12763 * query specified by the allQuery config option (defaults to 'query')
12765 triggerAction: 'query',
12767 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12768 * (defaults to 4, does not apply if editable = false)
12772 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12773 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12777 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12778 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12782 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12783 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12787 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12788 * when editable = true (defaults to false)
12790 selectOnFocus:false,
12792 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12794 queryParam: 'query',
12796 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12797 * when mode = 'remote' (defaults to 'Loading...')
12799 loadingText: 'Loading...',
12801 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12805 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12809 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12810 * traditional select (defaults to true)
12814 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12818 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12822 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12823 * listWidth has a higher value)
12827 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12828 * allow the user to set arbitrary text into the field (defaults to false)
12830 forceSelection:false,
12832 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12833 * if typeAhead = true (defaults to 250)
12835 typeAheadDelay : 250,
12837 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12838 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12840 valueNotFoundText : undefined,
12842 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12844 blockFocus : false,
12847 * @cfg {Boolean} disableClear Disable showing of clear button.
12849 disableClear : false,
12851 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12853 alwaysQuery : false,
12856 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12861 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12863 invalidClass : "has-warning",
12866 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12868 validClass : "has-success",
12871 * @cfg {Boolean} specialFilter (true|false) special filter default false
12873 specialFilter : false,
12876 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12878 mobileTouchView : true,
12881 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12883 useNativeIOS : false,
12885 ios_options : false,
12897 btnPosition : 'right',
12898 triggerList : true,
12899 showToggleBtn : true,
12901 emptyResultText: 'Empty',
12902 triggerText : 'Select',
12905 // element that contains real text value.. (when hidden is used..)
12907 getAutoCreate : function()
12912 * Render classic select for iso
12915 if(Roo.isIOS && this.useNativeIOS){
12916 cfg = this.getAutoCreateNativeIOS();
12924 if(Roo.isTouch && this.mobileTouchView){
12925 cfg = this.getAutoCreateTouchView();
12932 if(!this.tickable){
12933 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12938 * ComboBox with tickable selections
12941 var align = this.labelAlign || this.parentLabelAlign();
12944 cls : 'form-group roo-combobox-tickable' //input-group
12947 var btn_text_select = '';
12948 var btn_text_done = '';
12949 var btn_text_cancel = '';
12951 if (this.btn_text_show) {
12952 btn_text_select = 'Select';
12953 btn_text_done = 'Done';
12954 btn_text_cancel = 'Cancel';
12959 cls : 'tickable-buttons',
12964 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12965 //html : this.triggerText
12966 html: btn_text_select
12972 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12974 html: btn_text_done
12980 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12982 html: btn_text_cancel
12988 buttons.cn.unshift({
12990 cls: 'roo-select2-search-field-input'
12996 Roo.each(buttons.cn, function(c){
12998 c.cls += ' btn-' + _this.size;
13001 if (_this.disabled) {
13012 cls: 'form-hidden-field'
13016 cls: 'roo-select2-choices',
13020 cls: 'roo-select2-search-field',
13031 cls: 'roo-select2-container input-group roo-select2-container-multi',
13036 // cls: 'typeahead typeahead-long dropdown-menu',
13037 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13042 if(this.hasFeedback && !this.allowBlank){
13046 cls: 'glyphicon form-control-feedback'
13049 combobox.cn.push(feedback);
13053 if (align ==='left' && this.fieldLabel.length) {
13055 cfg.cls += ' roo-form-group-label-left';
13060 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13061 tooltip : 'This field is required'
13066 cls : 'control-label',
13067 html : this.fieldLabel
13079 var labelCfg = cfg.cn[1];
13080 var contentCfg = cfg.cn[2];
13083 if(this.indicatorpos == 'right'){
13089 cls : 'control-label',
13093 html : this.fieldLabel
13097 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13098 tooltip : 'This field is required'
13113 labelCfg = cfg.cn[0];
13114 contentCfg = cfg.cn[1];
13118 if(this.labelWidth > 12){
13119 labelCfg.style = "width: " + this.labelWidth + 'px';
13122 if(this.labelWidth < 13 && this.labelmd == 0){
13123 this.labelmd = this.labelWidth;
13126 if(this.labellg > 0){
13127 labelCfg.cls += ' col-lg-' + this.labellg;
13128 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13131 if(this.labelmd > 0){
13132 labelCfg.cls += ' col-md-' + this.labelmd;
13133 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13136 if(this.labelsm > 0){
13137 labelCfg.cls += ' col-sm-' + this.labelsm;
13138 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13141 if(this.labelxs > 0){
13142 labelCfg.cls += ' col-xs-' + this.labelxs;
13143 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13147 } else if ( this.fieldLabel.length) {
13148 // Roo.log(" label");
13152 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13153 tooltip : 'This field is required'
13157 //cls : 'input-group-addon',
13158 html : this.fieldLabel
13163 if(this.indicatorpos == 'right'){
13167 //cls : 'input-group-addon',
13168 html : this.fieldLabel
13172 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13173 tooltip : 'This field is required'
13182 // Roo.log(" no label && no align");
13189 ['xs','sm','md','lg'].map(function(size){
13190 if (settings[size]) {
13191 cfg.cls += ' col-' + size + '-' + settings[size];
13199 _initEventsCalled : false,
13202 initEvents: function()
13204 if (this._initEventsCalled) { // as we call render... prevent looping...
13207 this._initEventsCalled = true;
13210 throw "can not find store for combo";
13213 this.indicator = this.indicatorEl();
13215 this.store = Roo.factory(this.store, Roo.data);
13216 this.store.parent = this;
13218 // if we are building from html. then this element is so complex, that we can not really
13219 // use the rendered HTML.
13220 // so we have to trash and replace the previous code.
13221 if (Roo.XComponent.build_from_html) {
13222 // remove this element....
13223 var e = this.el.dom, k=0;
13224 while (e ) { e = e.previousSibling; ++k;}
13229 this.rendered = false;
13231 this.render(this.parent().getChildContainer(true), k);
13234 if(Roo.isIOS && this.useNativeIOS){
13235 this.initIOSView();
13243 if(Roo.isTouch && this.mobileTouchView){
13244 this.initTouchView();
13249 this.initTickableEvents();
13253 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13255 if(this.hiddenName){
13257 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13259 this.hiddenField.dom.value =
13260 this.hiddenValue !== undefined ? this.hiddenValue :
13261 this.value !== undefined ? this.value : '';
13263 // prevent input submission
13264 this.el.dom.removeAttribute('name');
13265 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13270 // this.el.dom.setAttribute('autocomplete', 'off');
13273 var cls = 'x-combo-list';
13275 //this.list = new Roo.Layer({
13276 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13282 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13283 _this.list.setWidth(lw);
13286 this.list.on('mouseover', this.onViewOver, this);
13287 this.list.on('mousemove', this.onViewMove, this);
13288 this.list.on('scroll', this.onViewScroll, this);
13291 this.list.swallowEvent('mousewheel');
13292 this.assetHeight = 0;
13295 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13296 this.assetHeight += this.header.getHeight();
13299 this.innerList = this.list.createChild({cls:cls+'-inner'});
13300 this.innerList.on('mouseover', this.onViewOver, this);
13301 this.innerList.on('mousemove', this.onViewMove, this);
13302 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13304 if(this.allowBlank && !this.pageSize && !this.disableClear){
13305 this.footer = this.list.createChild({cls:cls+'-ft'});
13306 this.pageTb = new Roo.Toolbar(this.footer);
13310 this.footer = this.list.createChild({cls:cls+'-ft'});
13311 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13312 {pageSize: this.pageSize});
13316 if (this.pageTb && this.allowBlank && !this.disableClear) {
13318 this.pageTb.add(new Roo.Toolbar.Fill(), {
13319 cls: 'x-btn-icon x-btn-clear',
13321 handler: function()
13324 _this.clearValue();
13325 _this.onSelect(false, -1);
13330 this.assetHeight += this.footer.getHeight();
13335 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13338 this.view = new Roo.View(this.list, this.tpl, {
13339 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13341 //this.view.wrapEl.setDisplayed(false);
13342 this.view.on('click', this.onViewClick, this);
13345 this.store.on('beforeload', this.onBeforeLoad, this);
13346 this.store.on('load', this.onLoad, this);
13347 this.store.on('loadexception', this.onLoadException, this);
13349 if(this.resizable){
13350 this.resizer = new Roo.Resizable(this.list, {
13351 pinned:true, handles:'se'
13353 this.resizer.on('resize', function(r, w, h){
13354 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13355 this.listWidth = w;
13356 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13357 this.restrictHeight();
13359 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13362 if(!this.editable){
13363 this.editable = true;
13364 this.setEditable(false);
13369 if (typeof(this.events.add.listeners) != 'undefined') {
13371 this.addicon = this.wrap.createChild(
13372 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13374 this.addicon.on('click', function(e) {
13375 this.fireEvent('add', this);
13378 if (typeof(this.events.edit.listeners) != 'undefined') {
13380 this.editicon = this.wrap.createChild(
13381 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13382 if (this.addicon) {
13383 this.editicon.setStyle('margin-left', '40px');
13385 this.editicon.on('click', function(e) {
13387 // we fire even if inothing is selected..
13388 this.fireEvent('edit', this, this.lastData );
13394 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13395 "up" : function(e){
13396 this.inKeyMode = true;
13400 "down" : function(e){
13401 if(!this.isExpanded()){
13402 this.onTriggerClick();
13404 this.inKeyMode = true;
13409 "enter" : function(e){
13410 // this.onViewClick();
13414 if(this.fireEvent("specialkey", this, e)){
13415 this.onViewClick(false);
13421 "esc" : function(e){
13425 "tab" : function(e){
13428 if(this.fireEvent("specialkey", this, e)){
13429 this.onViewClick(false);
13437 doRelay : function(foo, bar, hname){
13438 if(hname == 'down' || this.scope.isExpanded()){
13439 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13448 this.queryDelay = Math.max(this.queryDelay || 10,
13449 this.mode == 'local' ? 10 : 250);
13452 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13454 if(this.typeAhead){
13455 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13457 if(this.editable !== false){
13458 this.inputEl().on("keyup", this.onKeyUp, this);
13460 if(this.forceSelection){
13461 this.inputEl().on('blur', this.doForce, this);
13465 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13466 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13470 initTickableEvents: function()
13474 if(this.hiddenName){
13476 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13478 this.hiddenField.dom.value =
13479 this.hiddenValue !== undefined ? this.hiddenValue :
13480 this.value !== undefined ? this.value : '';
13482 // prevent input submission
13483 this.el.dom.removeAttribute('name');
13484 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13489 // this.list = this.el.select('ul.dropdown-menu',true).first();
13491 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13492 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13493 if(this.triggerList){
13494 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13497 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13498 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13500 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13501 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13503 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13504 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13506 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13507 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13508 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13511 this.cancelBtn.hide();
13516 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13517 _this.list.setWidth(lw);
13520 this.list.on('mouseover', this.onViewOver, this);
13521 this.list.on('mousemove', this.onViewMove, this);
13523 this.list.on('scroll', this.onViewScroll, this);
13526 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>';
13529 this.view = new Roo.View(this.list, this.tpl, {
13530 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13533 //this.view.wrapEl.setDisplayed(false);
13534 this.view.on('click', this.onViewClick, this);
13538 this.store.on('beforeload', this.onBeforeLoad, this);
13539 this.store.on('load', this.onLoad, this);
13540 this.store.on('loadexception', this.onLoadException, this);
13543 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13544 "up" : function(e){
13545 this.inKeyMode = true;
13549 "down" : function(e){
13550 this.inKeyMode = true;
13554 "enter" : function(e){
13555 if(this.fireEvent("specialkey", this, e)){
13556 this.onViewClick(false);
13562 "esc" : function(e){
13563 this.onTickableFooterButtonClick(e, false, false);
13566 "tab" : function(e){
13567 this.fireEvent("specialkey", this, e);
13569 this.onTickableFooterButtonClick(e, false, false);
13576 doRelay : function(e, fn, key){
13577 if(this.scope.isExpanded()){
13578 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13587 this.queryDelay = Math.max(this.queryDelay || 10,
13588 this.mode == 'local' ? 10 : 250);
13591 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13593 if(this.typeAhead){
13594 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13597 if(this.editable !== false){
13598 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13601 this.indicator = this.indicatorEl();
13603 if(this.indicator){
13604 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13605 this.indicator.hide();
13610 onDestroy : function(){
13612 this.view.setStore(null);
13613 this.view.el.removeAllListeners();
13614 this.view.el.remove();
13615 this.view.purgeListeners();
13618 this.list.dom.innerHTML = '';
13622 this.store.un('beforeload', this.onBeforeLoad, this);
13623 this.store.un('load', this.onLoad, this);
13624 this.store.un('loadexception', this.onLoadException, this);
13626 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13630 fireKey : function(e){
13631 if(e.isNavKeyPress() && !this.list.isVisible()){
13632 this.fireEvent("specialkey", this, e);
13637 onResize: function(w, h){
13638 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13640 // if(typeof w != 'number'){
13641 // // we do not handle it!?!?
13644 // var tw = this.trigger.getWidth();
13645 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13646 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13648 // this.inputEl().setWidth( this.adjustWidth('input', x));
13650 // //this.trigger.setStyle('left', x+'px');
13652 // if(this.list && this.listWidth === undefined){
13653 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13654 // this.list.setWidth(lw);
13655 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13663 * Allow or prevent the user from directly editing the field text. If false is passed,
13664 * the user will only be able to select from the items defined in the dropdown list. This method
13665 * is the runtime equivalent of setting the 'editable' config option at config time.
13666 * @param {Boolean} value True to allow the user to directly edit the field text
13668 setEditable : function(value){
13669 if(value == this.editable){
13672 this.editable = value;
13674 this.inputEl().dom.setAttribute('readOnly', true);
13675 this.inputEl().on('mousedown', this.onTriggerClick, this);
13676 this.inputEl().addClass('x-combo-noedit');
13678 this.inputEl().dom.setAttribute('readOnly', false);
13679 this.inputEl().un('mousedown', this.onTriggerClick, this);
13680 this.inputEl().removeClass('x-combo-noedit');
13686 onBeforeLoad : function(combo,opts){
13687 if(!this.hasFocus){
13691 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13693 this.restrictHeight();
13694 this.selectedIndex = -1;
13698 onLoad : function(){
13700 this.hasQuery = false;
13702 if(!this.hasFocus){
13706 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13707 this.loading.hide();
13710 if(this.store.getCount() > 0){
13713 this.restrictHeight();
13714 if(this.lastQuery == this.allQuery){
13715 if(this.editable && !this.tickable){
13716 this.inputEl().dom.select();
13720 !this.selectByValue(this.value, true) &&
13723 !this.store.lastOptions ||
13724 typeof(this.store.lastOptions.add) == 'undefined' ||
13725 this.store.lastOptions.add != true
13728 this.select(0, true);
13731 if(this.autoFocus){
13734 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13735 this.taTask.delay(this.typeAheadDelay);
13739 this.onEmptyResults();
13745 onLoadException : function()
13747 this.hasQuery = false;
13749 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13750 this.loading.hide();
13753 if(this.tickable && this.editable){
13758 // only causes errors at present
13759 //Roo.log(this.store.reader.jsonData);
13760 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13762 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13768 onTypeAhead : function(){
13769 if(this.store.getCount() > 0){
13770 var r = this.store.getAt(0);
13771 var newValue = r.data[this.displayField];
13772 var len = newValue.length;
13773 var selStart = this.getRawValue().length;
13775 if(selStart != len){
13776 this.setRawValue(newValue);
13777 this.selectText(selStart, newValue.length);
13783 onSelect : function(record, index){
13785 if(this.fireEvent('beforeselect', this, record, index) !== false){
13787 this.setFromData(index > -1 ? record.data : false);
13790 this.fireEvent('select', this, record, index);
13795 * Returns the currently selected field value or empty string if no value is set.
13796 * @return {String} value The selected value
13798 getValue : function()
13800 if(Roo.isIOS && this.useNativeIOS){
13801 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13805 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13808 if(this.valueField){
13809 return typeof this.value != 'undefined' ? this.value : '';
13811 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13815 getRawValue : function()
13817 if(Roo.isIOS && this.useNativeIOS){
13818 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13821 var v = this.inputEl().getValue();
13827 * Clears any text/value currently set in the field
13829 clearValue : function(){
13831 if(this.hiddenField){
13832 this.hiddenField.dom.value = '';
13835 this.setRawValue('');
13836 this.lastSelectionText = '';
13837 this.lastData = false;
13839 var close = this.closeTriggerEl();
13850 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13851 * will be displayed in the field. If the value does not match the data value of an existing item,
13852 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13853 * Otherwise the field will be blank (although the value will still be set).
13854 * @param {String} value The value to match
13856 setValue : function(v)
13858 if(Roo.isIOS && this.useNativeIOS){
13859 this.setIOSValue(v);
13869 if(this.valueField){
13870 var r = this.findRecord(this.valueField, v);
13872 text = r.data[this.displayField];
13873 }else if(this.valueNotFoundText !== undefined){
13874 text = this.valueNotFoundText;
13877 this.lastSelectionText = text;
13878 if(this.hiddenField){
13879 this.hiddenField.dom.value = v;
13881 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13884 var close = this.closeTriggerEl();
13887 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13893 * @property {Object} the last set data for the element
13898 * Sets the value of the field based on a object which is related to the record format for the store.
13899 * @param {Object} value the value to set as. or false on reset?
13901 setFromData : function(o){
13908 var dv = ''; // display value
13909 var vv = ''; // value value..
13911 if (this.displayField) {
13912 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13914 // this is an error condition!!!
13915 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13918 if(this.valueField){
13919 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13922 var close = this.closeTriggerEl();
13925 if(dv.length || vv * 1 > 0){
13927 this.blockFocus=true;
13933 if(this.hiddenField){
13934 this.hiddenField.dom.value = vv;
13936 this.lastSelectionText = dv;
13937 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13941 // no hidden field.. - we store the value in 'value', but still display
13942 // display field!!!!
13943 this.lastSelectionText = dv;
13944 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13951 reset : function(){
13952 // overridden so that last data is reset..
13959 this.setValue(this.originalValue);
13960 //this.clearInvalid();
13961 this.lastData = false;
13963 this.view.clearSelections();
13969 findRecord : function(prop, value){
13971 if(this.store.getCount() > 0){
13972 this.store.each(function(r){
13973 if(r.data[prop] == value){
13983 getName: function()
13985 // returns hidden if it's set..
13986 if (!this.rendered) {return ''};
13987 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13991 onViewMove : function(e, t){
13992 this.inKeyMode = false;
13996 onViewOver : function(e, t){
13997 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14000 var item = this.view.findItemFromChild(t);
14003 var index = this.view.indexOf(item);
14004 this.select(index, false);
14009 onViewClick : function(view, doFocus, el, e)
14011 var index = this.view.getSelectedIndexes()[0];
14013 var r = this.store.getAt(index);
14017 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14024 Roo.each(this.tickItems, function(v,k){
14026 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14028 _this.tickItems.splice(k, 1);
14030 if(typeof(e) == 'undefined' && view == false){
14031 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14043 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14044 this.tickItems.push(r.data);
14047 if(typeof(e) == 'undefined' && view == false){
14048 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14055 this.onSelect(r, index);
14057 if(doFocus !== false && !this.blockFocus){
14058 this.inputEl().focus();
14063 restrictHeight : function(){
14064 //this.innerList.dom.style.height = '';
14065 //var inner = this.innerList.dom;
14066 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14067 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14068 //this.list.beginUpdate();
14069 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14070 this.list.alignTo(this.inputEl(), this.listAlign);
14071 this.list.alignTo(this.inputEl(), this.listAlign);
14072 //this.list.endUpdate();
14076 onEmptyResults : function(){
14078 if(this.tickable && this.editable){
14079 this.hasFocus = false;
14080 this.restrictHeight();
14088 * Returns true if the dropdown list is expanded, else false.
14090 isExpanded : function(){
14091 return this.list.isVisible();
14095 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14096 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14097 * @param {String} value The data value of the item to select
14098 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14099 * selected item if it is not currently in view (defaults to true)
14100 * @return {Boolean} True if the value matched an item in the list, else false
14102 selectByValue : function(v, scrollIntoView){
14103 if(v !== undefined && v !== null){
14104 var r = this.findRecord(this.valueField || this.displayField, v);
14106 this.select(this.store.indexOf(r), scrollIntoView);
14114 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14115 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14116 * @param {Number} index The zero-based index of the list item to select
14117 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14118 * selected item if it is not currently in view (defaults to true)
14120 select : function(index, scrollIntoView){
14121 this.selectedIndex = index;
14122 this.view.select(index);
14123 if(scrollIntoView !== false){
14124 var el = this.view.getNode(index);
14126 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14129 this.list.scrollChildIntoView(el, false);
14135 selectNext : function(){
14136 var ct = this.store.getCount();
14138 if(this.selectedIndex == -1){
14140 }else if(this.selectedIndex < ct-1){
14141 this.select(this.selectedIndex+1);
14147 selectPrev : function(){
14148 var ct = this.store.getCount();
14150 if(this.selectedIndex == -1){
14152 }else if(this.selectedIndex != 0){
14153 this.select(this.selectedIndex-1);
14159 onKeyUp : function(e){
14160 if(this.editable !== false && !e.isSpecialKey()){
14161 this.lastKey = e.getKey();
14162 this.dqTask.delay(this.queryDelay);
14167 validateBlur : function(){
14168 return !this.list || !this.list.isVisible();
14172 initQuery : function(){
14174 var v = this.getRawValue();
14176 if(this.tickable && this.editable){
14177 v = this.tickableInputEl().getValue();
14184 doForce : function(){
14185 if(this.inputEl().dom.value.length > 0){
14186 this.inputEl().dom.value =
14187 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14193 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14194 * query allowing the query action to be canceled if needed.
14195 * @param {String} query The SQL query to execute
14196 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14197 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14198 * saved in the current store (defaults to false)
14200 doQuery : function(q, forceAll){
14202 if(q === undefined || q === null){
14207 forceAll: forceAll,
14211 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14216 forceAll = qe.forceAll;
14217 if(forceAll === true || (q.length >= this.minChars)){
14219 this.hasQuery = true;
14221 if(this.lastQuery != q || this.alwaysQuery){
14222 this.lastQuery = q;
14223 if(this.mode == 'local'){
14224 this.selectedIndex = -1;
14226 this.store.clearFilter();
14229 if(this.specialFilter){
14230 this.fireEvent('specialfilter', this);
14235 this.store.filter(this.displayField, q);
14238 this.store.fireEvent("datachanged", this.store);
14245 this.store.baseParams[this.queryParam] = q;
14247 var options = {params : this.getParams(q)};
14250 options.add = true;
14251 options.params.start = this.page * this.pageSize;
14254 this.store.load(options);
14257 * this code will make the page width larger, at the beginning, the list not align correctly,
14258 * we should expand the list on onLoad
14259 * so command out it
14264 this.selectedIndex = -1;
14269 this.loadNext = false;
14273 getParams : function(q){
14275 //p[this.queryParam] = q;
14279 p.limit = this.pageSize;
14285 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14287 collapse : function(){
14288 if(!this.isExpanded()){
14294 this.hasFocus = false;
14298 this.cancelBtn.hide();
14299 this.trigger.show();
14302 this.tickableInputEl().dom.value = '';
14303 this.tickableInputEl().blur();
14308 Roo.get(document).un('mousedown', this.collapseIf, this);
14309 Roo.get(document).un('mousewheel', this.collapseIf, this);
14310 if (!this.editable) {
14311 Roo.get(document).un('keydown', this.listKeyPress, this);
14313 this.fireEvent('collapse', this);
14319 collapseIf : function(e){
14320 var in_combo = e.within(this.el);
14321 var in_list = e.within(this.list);
14322 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14324 if (in_combo || in_list || is_list) {
14325 //e.stopPropagation();
14330 this.onTickableFooterButtonClick(e, false, false);
14338 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14340 expand : function(){
14342 if(this.isExpanded() || !this.hasFocus){
14346 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14347 this.list.setWidth(lw);
14353 this.restrictHeight();
14357 this.tickItems = Roo.apply([], this.item);
14360 this.cancelBtn.show();
14361 this.trigger.hide();
14364 this.tickableInputEl().focus();
14369 Roo.get(document).on('mousedown', this.collapseIf, this);
14370 Roo.get(document).on('mousewheel', this.collapseIf, this);
14371 if (!this.editable) {
14372 Roo.get(document).on('keydown', this.listKeyPress, this);
14375 this.fireEvent('expand', this);
14379 // Implements the default empty TriggerField.onTriggerClick function
14380 onTriggerClick : function(e)
14382 Roo.log('trigger click');
14384 if(this.disabled || !this.triggerList){
14389 this.loadNext = false;
14391 if(this.isExpanded()){
14393 if (!this.blockFocus) {
14394 this.inputEl().focus();
14398 this.hasFocus = true;
14399 if(this.triggerAction == 'all') {
14400 this.doQuery(this.allQuery, true);
14402 this.doQuery(this.getRawValue());
14404 if (!this.blockFocus) {
14405 this.inputEl().focus();
14410 onTickableTriggerClick : function(e)
14417 this.loadNext = false;
14418 this.hasFocus = true;
14420 if(this.triggerAction == 'all') {
14421 this.doQuery(this.allQuery, true);
14423 this.doQuery(this.getRawValue());
14427 onSearchFieldClick : function(e)
14429 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14430 this.onTickableFooterButtonClick(e, false, false);
14434 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14439 this.loadNext = false;
14440 this.hasFocus = true;
14442 if(this.triggerAction == 'all') {
14443 this.doQuery(this.allQuery, true);
14445 this.doQuery(this.getRawValue());
14449 listKeyPress : function(e)
14451 //Roo.log('listkeypress');
14452 // scroll to first matching element based on key pres..
14453 if (e.isSpecialKey()) {
14456 var k = String.fromCharCode(e.getKey()).toUpperCase();
14459 var csel = this.view.getSelectedNodes();
14460 var cselitem = false;
14462 var ix = this.view.indexOf(csel[0]);
14463 cselitem = this.store.getAt(ix);
14464 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14470 this.store.each(function(v) {
14472 // start at existing selection.
14473 if (cselitem.id == v.id) {
14479 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14480 match = this.store.indexOf(v);
14486 if (match === false) {
14487 return true; // no more action?
14490 this.view.select(match);
14491 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14492 sn.scrollIntoView(sn.dom.parentNode, false);
14495 onViewScroll : function(e, t){
14497 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){
14501 this.hasQuery = true;
14503 this.loading = this.list.select('.loading', true).first();
14505 if(this.loading === null){
14506 this.list.createChild({
14508 cls: 'loading roo-select2-more-results roo-select2-active',
14509 html: 'Loading more results...'
14512 this.loading = this.list.select('.loading', true).first();
14514 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14516 this.loading.hide();
14519 this.loading.show();
14524 this.loadNext = true;
14526 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14531 addItem : function(o)
14533 var dv = ''; // display value
14535 if (this.displayField) {
14536 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14538 // this is an error condition!!!
14539 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14546 var choice = this.choices.createChild({
14548 cls: 'roo-select2-search-choice',
14557 cls: 'roo-select2-search-choice-close fa fa-times',
14562 }, this.searchField);
14564 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14566 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14574 this.inputEl().dom.value = '';
14579 onRemoveItem : function(e, _self, o)
14581 e.preventDefault();
14583 this.lastItem = Roo.apply([], this.item);
14585 var index = this.item.indexOf(o.data) * 1;
14588 Roo.log('not this item?!');
14592 this.item.splice(index, 1);
14597 this.fireEvent('remove', this, e);
14603 syncValue : function()
14605 if(!this.item.length){
14612 Roo.each(this.item, function(i){
14613 if(_this.valueField){
14614 value.push(i[_this.valueField]);
14621 this.value = value.join(',');
14623 if(this.hiddenField){
14624 this.hiddenField.dom.value = this.value;
14627 this.store.fireEvent("datachanged", this.store);
14632 clearItem : function()
14634 if(!this.multiple){
14640 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14648 if(this.tickable && !Roo.isTouch){
14649 this.view.refresh();
14653 inputEl: function ()
14655 if(Roo.isIOS && this.useNativeIOS){
14656 return this.el.select('select.roo-ios-select', true).first();
14659 if(Roo.isTouch && this.mobileTouchView){
14660 return this.el.select('input.form-control',true).first();
14664 return this.searchField;
14667 return this.el.select('input.form-control',true).first();
14670 onTickableFooterButtonClick : function(e, btn, el)
14672 e.preventDefault();
14674 this.lastItem = Roo.apply([], this.item);
14676 if(btn && btn.name == 'cancel'){
14677 this.tickItems = Roo.apply([], this.item);
14686 Roo.each(this.tickItems, function(o){
14694 validate : function()
14696 if(this.getVisibilityEl().hasClass('hidden')){
14700 var v = this.getRawValue();
14703 v = this.getValue();
14706 if(this.disabled || this.allowBlank || v.length){
14711 this.markInvalid();
14715 tickableInputEl : function()
14717 if(!this.tickable || !this.editable){
14718 return this.inputEl();
14721 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14725 getAutoCreateTouchView : function()
14730 cls: 'form-group' //input-group
14736 type : this.inputType,
14737 cls : 'form-control x-combo-noedit',
14738 autocomplete: 'new-password',
14739 placeholder : this.placeholder || '',
14744 input.name = this.name;
14748 input.cls += ' input-' + this.size;
14751 if (this.disabled) {
14752 input.disabled = true;
14763 inputblock.cls += ' input-group';
14765 inputblock.cn.unshift({
14767 cls : 'input-group-addon',
14772 if(this.removable && !this.multiple){
14773 inputblock.cls += ' roo-removable';
14775 inputblock.cn.push({
14778 cls : 'roo-combo-removable-btn close'
14782 if(this.hasFeedback && !this.allowBlank){
14784 inputblock.cls += ' has-feedback';
14786 inputblock.cn.push({
14788 cls: 'glyphicon form-control-feedback'
14795 inputblock.cls += (this.before) ? '' : ' input-group';
14797 inputblock.cn.push({
14799 cls : 'input-group-addon',
14810 cls: 'form-hidden-field'
14824 cls: 'form-hidden-field'
14828 cls: 'roo-select2-choices',
14832 cls: 'roo-select2-search-field',
14845 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14851 if(!this.multiple && this.showToggleBtn){
14858 if (this.caret != false) {
14861 cls: 'fa fa-' + this.caret
14868 cls : 'input-group-addon btn dropdown-toggle',
14873 cls: 'combobox-clear',
14887 combobox.cls += ' roo-select2-container-multi';
14890 var align = this.labelAlign || this.parentLabelAlign();
14892 if (align ==='left' && this.fieldLabel.length) {
14897 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14898 tooltip : 'This field is required'
14902 cls : 'control-label',
14903 html : this.fieldLabel
14914 var labelCfg = cfg.cn[1];
14915 var contentCfg = cfg.cn[2];
14918 if(this.indicatorpos == 'right'){
14923 cls : 'control-label',
14927 html : this.fieldLabel
14931 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14932 tooltip : 'This field is required'
14945 labelCfg = cfg.cn[0];
14946 contentCfg = cfg.cn[1];
14951 if(this.labelWidth > 12){
14952 labelCfg.style = "width: " + this.labelWidth + 'px';
14955 if(this.labelWidth < 13 && this.labelmd == 0){
14956 this.labelmd = this.labelWidth;
14959 if(this.labellg > 0){
14960 labelCfg.cls += ' col-lg-' + this.labellg;
14961 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14964 if(this.labelmd > 0){
14965 labelCfg.cls += ' col-md-' + this.labelmd;
14966 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14969 if(this.labelsm > 0){
14970 labelCfg.cls += ' col-sm-' + this.labelsm;
14971 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14974 if(this.labelxs > 0){
14975 labelCfg.cls += ' col-xs-' + this.labelxs;
14976 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14980 } else if ( this.fieldLabel.length) {
14984 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14985 tooltip : 'This field is required'
14989 cls : 'control-label',
14990 html : this.fieldLabel
15001 if(this.indicatorpos == 'right'){
15005 cls : 'control-label',
15006 html : this.fieldLabel,
15010 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15011 tooltip : 'This field is required'
15028 var settings = this;
15030 ['xs','sm','md','lg'].map(function(size){
15031 if (settings[size]) {
15032 cfg.cls += ' col-' + size + '-' + settings[size];
15039 initTouchView : function()
15041 this.renderTouchView();
15043 this.touchViewEl.on('scroll', function(){
15044 this.el.dom.scrollTop = 0;
15047 this.originalValue = this.getValue();
15049 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15051 this.inputEl().on("click", this.showTouchView, this);
15052 if (this.triggerEl) {
15053 this.triggerEl.on("click", this.showTouchView, this);
15057 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15058 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15060 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15062 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15063 this.store.on('load', this.onTouchViewLoad, this);
15064 this.store.on('loadexception', this.onTouchViewLoadException, this);
15066 if(this.hiddenName){
15068 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15070 this.hiddenField.dom.value =
15071 this.hiddenValue !== undefined ? this.hiddenValue :
15072 this.value !== undefined ? this.value : '';
15074 this.el.dom.removeAttribute('name');
15075 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15079 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15080 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15083 if(this.removable && !this.multiple){
15084 var close = this.closeTriggerEl();
15086 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15087 close.on('click', this.removeBtnClick, this, close);
15091 * fix the bug in Safari iOS8
15093 this.inputEl().on("focus", function(e){
15094 document.activeElement.blur();
15102 renderTouchView : function()
15104 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15105 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15107 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15108 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15110 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15111 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15112 this.touchViewBodyEl.setStyle('overflow', 'auto');
15114 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15115 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15117 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15118 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15122 showTouchView : function()
15128 this.touchViewHeaderEl.hide();
15130 if(this.modalTitle.length){
15131 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15132 this.touchViewHeaderEl.show();
15135 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15136 this.touchViewEl.show();
15138 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15140 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15141 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15143 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15145 if(this.modalTitle.length){
15146 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15149 this.touchViewBodyEl.setHeight(bodyHeight);
15153 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15155 this.touchViewEl.addClass('in');
15158 this.doTouchViewQuery();
15162 hideTouchView : function()
15164 this.touchViewEl.removeClass('in');
15168 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15170 this.touchViewEl.setStyle('display', 'none');
15175 setTouchViewValue : function()
15182 Roo.each(this.tickItems, function(o){
15187 this.hideTouchView();
15190 doTouchViewQuery : function()
15199 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15203 if(!this.alwaysQuery || this.mode == 'local'){
15204 this.onTouchViewLoad();
15211 onTouchViewBeforeLoad : function(combo,opts)
15217 onTouchViewLoad : function()
15219 if(this.store.getCount() < 1){
15220 this.onTouchViewEmptyResults();
15224 this.clearTouchView();
15226 var rawValue = this.getRawValue();
15228 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15230 this.tickItems = [];
15232 this.store.data.each(function(d, rowIndex){
15233 var row = this.touchViewListGroup.createChild(template);
15235 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15236 row.addClass(d.data.cls);
15239 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15242 html : d.data[this.displayField]
15245 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15246 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15249 row.removeClass('selected');
15250 if(!this.multiple && this.valueField &&
15251 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15254 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15255 row.addClass('selected');
15258 if(this.multiple && this.valueField &&
15259 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15263 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15264 this.tickItems.push(d.data);
15267 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15271 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15273 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15275 if(this.modalTitle.length){
15276 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15279 var listHeight = this.touchViewListGroup.getHeight();
15283 if(firstChecked && listHeight > bodyHeight){
15284 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15289 onTouchViewLoadException : function()
15291 this.hideTouchView();
15294 onTouchViewEmptyResults : function()
15296 this.clearTouchView();
15298 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15300 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15304 clearTouchView : function()
15306 this.touchViewListGroup.dom.innerHTML = '';
15309 onTouchViewClick : function(e, el, o)
15311 e.preventDefault();
15314 var rowIndex = o.rowIndex;
15316 var r = this.store.getAt(rowIndex);
15318 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15320 if(!this.multiple){
15321 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15322 c.dom.removeAttribute('checked');
15325 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15327 this.setFromData(r.data);
15329 var close = this.closeTriggerEl();
15335 this.hideTouchView();
15337 this.fireEvent('select', this, r, rowIndex);
15342 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15343 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15344 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15348 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15349 this.addItem(r.data);
15350 this.tickItems.push(r.data);
15354 getAutoCreateNativeIOS : function()
15357 cls: 'form-group' //input-group,
15362 cls : 'roo-ios-select'
15366 combobox.name = this.name;
15369 if (this.disabled) {
15370 combobox.disabled = true;
15373 var settings = this;
15375 ['xs','sm','md','lg'].map(function(size){
15376 if (settings[size]) {
15377 cfg.cls += ' col-' + size + '-' + settings[size];
15387 initIOSView : function()
15389 this.store.on('load', this.onIOSViewLoad, this);
15394 onIOSViewLoad : function()
15396 if(this.store.getCount() < 1){
15400 this.clearIOSView();
15402 if(this.allowBlank) {
15404 var default_text = '-- SELECT --';
15406 if(this.placeholder.length){
15407 default_text = this.placeholder;
15410 if(this.emptyTitle.length){
15411 default_text += ' - ' + this.emptyTitle + ' -';
15414 var opt = this.inputEl().createChild({
15417 html : default_text
15421 o[this.valueField] = 0;
15422 o[this.displayField] = default_text;
15424 this.ios_options.push({
15431 this.store.data.each(function(d, rowIndex){
15435 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15436 html = d.data[this.displayField];
15441 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15442 value = d.data[this.valueField];
15451 if(this.value == d.data[this.valueField]){
15452 option['selected'] = true;
15455 var opt = this.inputEl().createChild(option);
15457 this.ios_options.push({
15464 this.inputEl().on('change', function(){
15465 this.fireEvent('select', this);
15470 clearIOSView: function()
15472 this.inputEl().dom.innerHTML = '';
15474 this.ios_options = [];
15477 setIOSValue: function(v)
15481 if(!this.ios_options){
15485 Roo.each(this.ios_options, function(opts){
15487 opts.el.dom.removeAttribute('selected');
15489 if(opts.data[this.valueField] != v){
15493 opts.el.dom.setAttribute('selected', true);
15499 * @cfg {Boolean} grow
15503 * @cfg {Number} growMin
15507 * @cfg {Number} growMax
15516 Roo.apply(Roo.bootstrap.ComboBox, {
15520 cls: 'modal-header',
15542 cls: 'list-group-item',
15546 cls: 'roo-combobox-list-group-item-value'
15550 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15564 listItemCheckbox : {
15566 cls: 'list-group-item',
15570 cls: 'roo-combobox-list-group-item-value'
15574 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15590 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15595 cls: 'modal-footer',
15603 cls: 'col-xs-6 text-left',
15606 cls: 'btn btn-danger roo-touch-view-cancel',
15612 cls: 'col-xs-6 text-right',
15615 cls: 'btn btn-success roo-touch-view-ok',
15626 Roo.apply(Roo.bootstrap.ComboBox, {
15628 touchViewTemplate : {
15630 cls: 'modal fade roo-combobox-touch-view',
15634 cls: 'modal-dialog',
15635 style : 'position:fixed', // we have to fix position....
15639 cls: 'modal-content',
15641 Roo.bootstrap.ComboBox.header,
15642 Roo.bootstrap.ComboBox.body,
15643 Roo.bootstrap.ComboBox.footer
15652 * Ext JS Library 1.1.1
15653 * Copyright(c) 2006-2007, Ext JS, LLC.
15655 * Originally Released Under LGPL - original licence link has changed is not relivant.
15658 * <script type="text/javascript">
15663 * @extends Roo.util.Observable
15664 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15665 * This class also supports single and multi selection modes. <br>
15666 * Create a data model bound view:
15668 var store = new Roo.data.Store(...);
15670 var view = new Roo.View({
15672 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15674 singleSelect: true,
15675 selectedClass: "ydataview-selected",
15679 // listen for node click?
15680 view.on("click", function(vw, index, node, e){
15681 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15685 dataModel.load("foobar.xml");
15687 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15689 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15690 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15692 * Note: old style constructor is still suported (container, template, config)
15695 * Create a new View
15696 * @param {Object} config The config object
15699 Roo.View = function(config, depreciated_tpl, depreciated_config){
15701 this.parent = false;
15703 if (typeof(depreciated_tpl) == 'undefined') {
15704 // new way.. - universal constructor.
15705 Roo.apply(this, config);
15706 this.el = Roo.get(this.el);
15709 this.el = Roo.get(config);
15710 this.tpl = depreciated_tpl;
15711 Roo.apply(this, depreciated_config);
15713 this.wrapEl = this.el.wrap().wrap();
15714 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15717 if(typeof(this.tpl) == "string"){
15718 this.tpl = new Roo.Template(this.tpl);
15720 // support xtype ctors..
15721 this.tpl = new Roo.factory(this.tpl, Roo);
15725 this.tpl.compile();
15730 * @event beforeclick
15731 * Fires before a click is processed. Returns false to cancel the default action.
15732 * @param {Roo.View} this
15733 * @param {Number} index The index of the target node
15734 * @param {HTMLElement} node The target node
15735 * @param {Roo.EventObject} e The raw event object
15737 "beforeclick" : true,
15740 * Fires when a template node is clicked.
15741 * @param {Roo.View} this
15742 * @param {Number} index The index of the target node
15743 * @param {HTMLElement} node The target node
15744 * @param {Roo.EventObject} e The raw event object
15749 * Fires when a template node is double clicked.
15750 * @param {Roo.View} this
15751 * @param {Number} index The index of the target node
15752 * @param {HTMLElement} node The target node
15753 * @param {Roo.EventObject} e The raw event object
15757 * @event contextmenu
15758 * Fires when a template node is right clicked.
15759 * @param {Roo.View} this
15760 * @param {Number} index The index of the target node
15761 * @param {HTMLElement} node The target node
15762 * @param {Roo.EventObject} e The raw event object
15764 "contextmenu" : true,
15766 * @event selectionchange
15767 * Fires when the selected nodes change.
15768 * @param {Roo.View} this
15769 * @param {Array} selections Array of the selected nodes
15771 "selectionchange" : true,
15774 * @event beforeselect
15775 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15776 * @param {Roo.View} this
15777 * @param {HTMLElement} node The node to be selected
15778 * @param {Array} selections Array of currently selected nodes
15780 "beforeselect" : true,
15782 * @event preparedata
15783 * Fires on every row to render, to allow you to change the data.
15784 * @param {Roo.View} this
15785 * @param {Object} data to be rendered (change this)
15787 "preparedata" : true
15795 "click": this.onClick,
15796 "dblclick": this.onDblClick,
15797 "contextmenu": this.onContextMenu,
15801 this.selections = [];
15803 this.cmp = new Roo.CompositeElementLite([]);
15805 this.store = Roo.factory(this.store, Roo.data);
15806 this.setStore(this.store, true);
15809 if ( this.footer && this.footer.xtype) {
15811 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15813 this.footer.dataSource = this.store;
15814 this.footer.container = fctr;
15815 this.footer = Roo.factory(this.footer, Roo);
15816 fctr.insertFirst(this.el);
15818 // this is a bit insane - as the paging toolbar seems to detach the el..
15819 // dom.parentNode.parentNode.parentNode
15820 // they get detached?
15824 Roo.View.superclass.constructor.call(this);
15829 Roo.extend(Roo.View, Roo.util.Observable, {
15832 * @cfg {Roo.data.Store} store Data store to load data from.
15837 * @cfg {String|Roo.Element} el The container element.
15842 * @cfg {String|Roo.Template} tpl The template used by this View
15846 * @cfg {String} dataName the named area of the template to use as the data area
15847 * Works with domtemplates roo-name="name"
15851 * @cfg {String} selectedClass The css class to add to selected nodes
15853 selectedClass : "x-view-selected",
15855 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15860 * @cfg {String} text to display on mask (default Loading)
15864 * @cfg {Boolean} multiSelect Allow multiple selection
15866 multiSelect : false,
15868 * @cfg {Boolean} singleSelect Allow single selection
15870 singleSelect: false,
15873 * @cfg {Boolean} toggleSelect - selecting
15875 toggleSelect : false,
15878 * @cfg {Boolean} tickable - selecting
15883 * Returns the element this view is bound to.
15884 * @return {Roo.Element}
15886 getEl : function(){
15887 return this.wrapEl;
15893 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15895 refresh : function(){
15896 //Roo.log('refresh');
15899 // if we are using something like 'domtemplate', then
15900 // the what gets used is:
15901 // t.applySubtemplate(NAME, data, wrapping data..)
15902 // the outer template then get' applied with
15903 // the store 'extra data'
15904 // and the body get's added to the
15905 // roo-name="data" node?
15906 // <span class='roo-tpl-{name}'></span> ?????
15910 this.clearSelections();
15911 this.el.update("");
15913 var records = this.store.getRange();
15914 if(records.length < 1) {
15916 // is this valid?? = should it render a template??
15918 this.el.update(this.emptyText);
15922 if (this.dataName) {
15923 this.el.update(t.apply(this.store.meta)); //????
15924 el = this.el.child('.roo-tpl-' + this.dataName);
15927 for(var i = 0, len = records.length; i < len; i++){
15928 var data = this.prepareData(records[i].data, i, records[i]);
15929 this.fireEvent("preparedata", this, data, i, records[i]);
15931 var d = Roo.apply({}, data);
15934 Roo.apply(d, {'roo-id' : Roo.id()});
15938 Roo.each(this.parent.item, function(item){
15939 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15942 Roo.apply(d, {'roo-data-checked' : 'checked'});
15946 html[html.length] = Roo.util.Format.trim(
15948 t.applySubtemplate(this.dataName, d, this.store.meta) :
15955 el.update(html.join(""));
15956 this.nodes = el.dom.childNodes;
15957 this.updateIndexes(0);
15962 * Function to override to reformat the data that is sent to
15963 * the template for each node.
15964 * DEPRICATED - use the preparedata event handler.
15965 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15966 * a JSON object for an UpdateManager bound view).
15968 prepareData : function(data, index, record)
15970 this.fireEvent("preparedata", this, data, index, record);
15974 onUpdate : function(ds, record){
15975 // Roo.log('on update');
15976 this.clearSelections();
15977 var index = this.store.indexOf(record);
15978 var n = this.nodes[index];
15979 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15980 n.parentNode.removeChild(n);
15981 this.updateIndexes(index, index);
15987 onAdd : function(ds, records, index)
15989 //Roo.log(['on Add', ds, records, index] );
15990 this.clearSelections();
15991 if(this.nodes.length == 0){
15995 var n = this.nodes[index];
15996 for(var i = 0, len = records.length; i < len; i++){
15997 var d = this.prepareData(records[i].data, i, records[i]);
15999 this.tpl.insertBefore(n, d);
16002 this.tpl.append(this.el, d);
16005 this.updateIndexes(index);
16008 onRemove : function(ds, record, index){
16009 // Roo.log('onRemove');
16010 this.clearSelections();
16011 var el = this.dataName ?
16012 this.el.child('.roo-tpl-' + this.dataName) :
16015 el.dom.removeChild(this.nodes[index]);
16016 this.updateIndexes(index);
16020 * Refresh an individual node.
16021 * @param {Number} index
16023 refreshNode : function(index){
16024 this.onUpdate(this.store, this.store.getAt(index));
16027 updateIndexes : function(startIndex, endIndex){
16028 var ns = this.nodes;
16029 startIndex = startIndex || 0;
16030 endIndex = endIndex || ns.length - 1;
16031 for(var i = startIndex; i <= endIndex; i++){
16032 ns[i].nodeIndex = i;
16037 * Changes the data store this view uses and refresh the view.
16038 * @param {Store} store
16040 setStore : function(store, initial){
16041 if(!initial && this.store){
16042 this.store.un("datachanged", this.refresh);
16043 this.store.un("add", this.onAdd);
16044 this.store.un("remove", this.onRemove);
16045 this.store.un("update", this.onUpdate);
16046 this.store.un("clear", this.refresh);
16047 this.store.un("beforeload", this.onBeforeLoad);
16048 this.store.un("load", this.onLoad);
16049 this.store.un("loadexception", this.onLoad);
16053 store.on("datachanged", this.refresh, this);
16054 store.on("add", this.onAdd, this);
16055 store.on("remove", this.onRemove, this);
16056 store.on("update", this.onUpdate, this);
16057 store.on("clear", this.refresh, this);
16058 store.on("beforeload", this.onBeforeLoad, this);
16059 store.on("load", this.onLoad, this);
16060 store.on("loadexception", this.onLoad, this);
16068 * onbeforeLoad - masks the loading area.
16071 onBeforeLoad : function(store,opts)
16073 //Roo.log('onBeforeLoad');
16075 this.el.update("");
16077 this.el.mask(this.mask ? this.mask : "Loading" );
16079 onLoad : function ()
16086 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16087 * @param {HTMLElement} node
16088 * @return {HTMLElement} The template node
16090 findItemFromChild : function(node){
16091 var el = this.dataName ?
16092 this.el.child('.roo-tpl-' + this.dataName,true) :
16095 if(!node || node.parentNode == el){
16098 var p = node.parentNode;
16099 while(p && p != el){
16100 if(p.parentNode == el){
16109 onClick : function(e){
16110 var item = this.findItemFromChild(e.getTarget());
16112 var index = this.indexOf(item);
16113 if(this.onItemClick(item, index, e) !== false){
16114 this.fireEvent("click", this, index, item, e);
16117 this.clearSelections();
16122 onContextMenu : function(e){
16123 var item = this.findItemFromChild(e.getTarget());
16125 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16130 onDblClick : function(e){
16131 var item = this.findItemFromChild(e.getTarget());
16133 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16137 onItemClick : function(item, index, e)
16139 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16142 if (this.toggleSelect) {
16143 var m = this.isSelected(item) ? 'unselect' : 'select';
16146 _t[m](item, true, false);
16149 if(this.multiSelect || this.singleSelect){
16150 if(this.multiSelect && e.shiftKey && this.lastSelection){
16151 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16153 this.select(item, this.multiSelect && e.ctrlKey);
16154 this.lastSelection = item;
16157 if(!this.tickable){
16158 e.preventDefault();
16166 * Get the number of selected nodes.
16169 getSelectionCount : function(){
16170 return this.selections.length;
16174 * Get the currently selected nodes.
16175 * @return {Array} An array of HTMLElements
16177 getSelectedNodes : function(){
16178 return this.selections;
16182 * Get the indexes of the selected nodes.
16185 getSelectedIndexes : function(){
16186 var indexes = [], s = this.selections;
16187 for(var i = 0, len = s.length; i < len; i++){
16188 indexes.push(s[i].nodeIndex);
16194 * Clear all selections
16195 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16197 clearSelections : function(suppressEvent){
16198 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16199 this.cmp.elements = this.selections;
16200 this.cmp.removeClass(this.selectedClass);
16201 this.selections = [];
16202 if(!suppressEvent){
16203 this.fireEvent("selectionchange", this, this.selections);
16209 * Returns true if the passed node is selected
16210 * @param {HTMLElement/Number} node The node or node index
16211 * @return {Boolean}
16213 isSelected : function(node){
16214 var s = this.selections;
16218 node = this.getNode(node);
16219 return s.indexOf(node) !== -1;
16224 * @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
16225 * @param {Boolean} keepExisting (optional) true to keep existing selections
16226 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16228 select : function(nodeInfo, keepExisting, suppressEvent){
16229 if(nodeInfo instanceof Array){
16231 this.clearSelections(true);
16233 for(var i = 0, len = nodeInfo.length; i < len; i++){
16234 this.select(nodeInfo[i], true, true);
16238 var node = this.getNode(nodeInfo);
16239 if(!node || this.isSelected(node)){
16240 return; // already selected.
16243 this.clearSelections(true);
16246 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16247 Roo.fly(node).addClass(this.selectedClass);
16248 this.selections.push(node);
16249 if(!suppressEvent){
16250 this.fireEvent("selectionchange", this, this.selections);
16258 * @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
16259 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16260 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16262 unselect : function(nodeInfo, keepExisting, suppressEvent)
16264 if(nodeInfo instanceof Array){
16265 Roo.each(this.selections, function(s) {
16266 this.unselect(s, nodeInfo);
16270 var node = this.getNode(nodeInfo);
16271 if(!node || !this.isSelected(node)){
16272 //Roo.log("not selected");
16273 return; // not selected.
16277 Roo.each(this.selections, function(s) {
16279 Roo.fly(node).removeClass(this.selectedClass);
16286 this.selections= ns;
16287 this.fireEvent("selectionchange", this, this.selections);
16291 * Gets a template node.
16292 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16293 * @return {HTMLElement} The node or null if it wasn't found
16295 getNode : function(nodeInfo){
16296 if(typeof nodeInfo == "string"){
16297 return document.getElementById(nodeInfo);
16298 }else if(typeof nodeInfo == "number"){
16299 return this.nodes[nodeInfo];
16305 * Gets a range template nodes.
16306 * @param {Number} startIndex
16307 * @param {Number} endIndex
16308 * @return {Array} An array of nodes
16310 getNodes : function(start, end){
16311 var ns = this.nodes;
16312 start = start || 0;
16313 end = typeof end == "undefined" ? ns.length - 1 : end;
16316 for(var i = start; i <= end; i++){
16320 for(var i = start; i >= end; i--){
16328 * Finds the index of the passed node
16329 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16330 * @return {Number} The index of the node or -1
16332 indexOf : function(node){
16333 node = this.getNode(node);
16334 if(typeof node.nodeIndex == "number"){
16335 return node.nodeIndex;
16337 var ns = this.nodes;
16338 for(var i = 0, len = ns.length; i < len; i++){
16349 * based on jquery fullcalendar
16353 Roo.bootstrap = Roo.bootstrap || {};
16355 * @class Roo.bootstrap.Calendar
16356 * @extends Roo.bootstrap.Component
16357 * Bootstrap Calendar class
16358 * @cfg {Boolean} loadMask (true|false) default false
16359 * @cfg {Object} header generate the user specific header of the calendar, default false
16362 * Create a new Container
16363 * @param {Object} config The config object
16368 Roo.bootstrap.Calendar = function(config){
16369 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16373 * Fires when a date is selected
16374 * @param {DatePicker} this
16375 * @param {Date} date The selected date
16379 * @event monthchange
16380 * Fires when the displayed month changes
16381 * @param {DatePicker} this
16382 * @param {Date} date The selected month
16384 'monthchange': true,
16386 * @event evententer
16387 * Fires when mouse over an event
16388 * @param {Calendar} this
16389 * @param {event} Event
16391 'evententer': true,
16393 * @event eventleave
16394 * Fires when the mouse leaves an
16395 * @param {Calendar} this
16398 'eventleave': true,
16400 * @event eventclick
16401 * Fires when the mouse click an
16402 * @param {Calendar} this
16411 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16414 * @cfg {Number} startDay
16415 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16423 getAutoCreate : function(){
16426 var fc_button = function(name, corner, style, content ) {
16427 return Roo.apply({},{
16429 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16431 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16434 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16445 style : 'width:100%',
16452 cls : 'fc-header-left',
16454 fc_button('prev', 'left', 'arrow', '‹' ),
16455 fc_button('next', 'right', 'arrow', '›' ),
16456 { tag: 'span', cls: 'fc-header-space' },
16457 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16465 cls : 'fc-header-center',
16469 cls: 'fc-header-title',
16472 html : 'month / year'
16480 cls : 'fc-header-right',
16482 /* fc_button('month', 'left', '', 'month' ),
16483 fc_button('week', '', '', 'week' ),
16484 fc_button('day', 'right', '', 'day' )
16496 header = this.header;
16499 var cal_heads = function() {
16501 // fixme - handle this.
16503 for (var i =0; i < Date.dayNames.length; i++) {
16504 var d = Date.dayNames[i];
16507 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16508 html : d.substring(0,3)
16512 ret[0].cls += ' fc-first';
16513 ret[6].cls += ' fc-last';
16516 var cal_cell = function(n) {
16519 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16524 cls: 'fc-day-number',
16528 cls: 'fc-day-content',
16532 style: 'position: relative;' // height: 17px;
16544 var cal_rows = function() {
16547 for (var r = 0; r < 6; r++) {
16554 for (var i =0; i < Date.dayNames.length; i++) {
16555 var d = Date.dayNames[i];
16556 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16559 row.cn[0].cls+=' fc-first';
16560 row.cn[0].cn[0].style = 'min-height:90px';
16561 row.cn[6].cls+=' fc-last';
16565 ret[0].cls += ' fc-first';
16566 ret[4].cls += ' fc-prev-last';
16567 ret[5].cls += ' fc-last';
16574 cls: 'fc-border-separate',
16575 style : 'width:100%',
16583 cls : 'fc-first fc-last',
16601 cls : 'fc-content',
16602 style : "position: relative;",
16605 cls : 'fc-view fc-view-month fc-grid',
16606 style : 'position: relative',
16607 unselectable : 'on',
16610 cls : 'fc-event-container',
16611 style : 'position:absolute;z-index:8;top:0;left:0;'
16629 initEvents : function()
16632 throw "can not find store for calendar";
16638 style: "text-align:center",
16642 style: "background-color:white;width:50%;margin:250 auto",
16646 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16657 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16659 var size = this.el.select('.fc-content', true).first().getSize();
16660 this.maskEl.setSize(size.width, size.height);
16661 this.maskEl.enableDisplayMode("block");
16662 if(!this.loadMask){
16663 this.maskEl.hide();
16666 this.store = Roo.factory(this.store, Roo.data);
16667 this.store.on('load', this.onLoad, this);
16668 this.store.on('beforeload', this.onBeforeLoad, this);
16672 this.cells = this.el.select('.fc-day',true);
16673 //Roo.log(this.cells);
16674 this.textNodes = this.el.query('.fc-day-number');
16675 this.cells.addClassOnOver('fc-state-hover');
16677 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16678 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16679 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16680 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16682 this.on('monthchange', this.onMonthChange, this);
16684 this.update(new Date().clearTime());
16687 resize : function() {
16688 var sz = this.el.getSize();
16690 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16691 this.el.select('.fc-day-content div',true).setHeight(34);
16696 showPrevMonth : function(e){
16697 this.update(this.activeDate.add("mo", -1));
16699 showToday : function(e){
16700 this.update(new Date().clearTime());
16703 showNextMonth : function(e){
16704 this.update(this.activeDate.add("mo", 1));
16708 showPrevYear : function(){
16709 this.update(this.activeDate.add("y", -1));
16713 showNextYear : function(){
16714 this.update(this.activeDate.add("y", 1));
16719 update : function(date)
16721 var vd = this.activeDate;
16722 this.activeDate = date;
16723 // if(vd && this.el){
16724 // var t = date.getTime();
16725 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16726 // Roo.log('using add remove');
16728 // this.fireEvent('monthchange', this, date);
16730 // this.cells.removeClass("fc-state-highlight");
16731 // this.cells.each(function(c){
16732 // if(c.dateValue == t){
16733 // c.addClass("fc-state-highlight");
16734 // setTimeout(function(){
16735 // try{c.dom.firstChild.focus();}catch(e){}
16745 var days = date.getDaysInMonth();
16747 var firstOfMonth = date.getFirstDateOfMonth();
16748 var startingPos = firstOfMonth.getDay()-this.startDay;
16750 if(startingPos < this.startDay){
16754 var pm = date.add(Date.MONTH, -1);
16755 var prevStart = pm.getDaysInMonth()-startingPos;
16757 this.cells = this.el.select('.fc-day',true);
16758 this.textNodes = this.el.query('.fc-day-number');
16759 this.cells.addClassOnOver('fc-state-hover');
16761 var cells = this.cells.elements;
16762 var textEls = this.textNodes;
16764 Roo.each(cells, function(cell){
16765 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16768 days += startingPos;
16770 // convert everything to numbers so it's fast
16771 var day = 86400000;
16772 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16775 //Roo.log(prevStart);
16777 var today = new Date().clearTime().getTime();
16778 var sel = date.clearTime().getTime();
16779 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16780 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16781 var ddMatch = this.disabledDatesRE;
16782 var ddText = this.disabledDatesText;
16783 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16784 var ddaysText = this.disabledDaysText;
16785 var format = this.format;
16787 var setCellClass = function(cal, cell){
16791 //Roo.log('set Cell Class');
16793 var t = d.getTime();
16797 cell.dateValue = t;
16799 cell.className += " fc-today";
16800 cell.className += " fc-state-highlight";
16801 cell.title = cal.todayText;
16804 // disable highlight in other month..
16805 //cell.className += " fc-state-highlight";
16810 cell.className = " fc-state-disabled";
16811 cell.title = cal.minText;
16815 cell.className = " fc-state-disabled";
16816 cell.title = cal.maxText;
16820 if(ddays.indexOf(d.getDay()) != -1){
16821 cell.title = ddaysText;
16822 cell.className = " fc-state-disabled";
16825 if(ddMatch && format){
16826 var fvalue = d.dateFormat(format);
16827 if(ddMatch.test(fvalue)){
16828 cell.title = ddText.replace("%0", fvalue);
16829 cell.className = " fc-state-disabled";
16833 if (!cell.initialClassName) {
16834 cell.initialClassName = cell.dom.className;
16837 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16842 for(; i < startingPos; i++) {
16843 textEls[i].innerHTML = (++prevStart);
16844 d.setDate(d.getDate()+1);
16846 cells[i].className = "fc-past fc-other-month";
16847 setCellClass(this, cells[i]);
16852 for(; i < days; i++){
16853 intDay = i - startingPos + 1;
16854 textEls[i].innerHTML = (intDay);
16855 d.setDate(d.getDate()+1);
16857 cells[i].className = ''; // "x-date-active";
16858 setCellClass(this, cells[i]);
16862 for(; i < 42; i++) {
16863 textEls[i].innerHTML = (++extraDays);
16864 d.setDate(d.getDate()+1);
16866 cells[i].className = "fc-future fc-other-month";
16867 setCellClass(this, cells[i]);
16870 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16872 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16874 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16875 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16877 if(totalRows != 6){
16878 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16879 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16882 this.fireEvent('monthchange', this, date);
16886 if(!this.internalRender){
16887 var main = this.el.dom.firstChild;
16888 var w = main.offsetWidth;
16889 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16890 Roo.fly(main).setWidth(w);
16891 this.internalRender = true;
16892 // opera does not respect the auto grow header center column
16893 // then, after it gets a width opera refuses to recalculate
16894 // without a second pass
16895 if(Roo.isOpera && !this.secondPass){
16896 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16897 this.secondPass = true;
16898 this.update.defer(10, this, [date]);
16905 findCell : function(dt) {
16906 dt = dt.clearTime().getTime();
16908 this.cells.each(function(c){
16909 //Roo.log("check " +c.dateValue + '?=' + dt);
16910 if(c.dateValue == dt){
16920 findCells : function(ev) {
16921 var s = ev.start.clone().clearTime().getTime();
16923 var e= ev.end.clone().clearTime().getTime();
16926 this.cells.each(function(c){
16927 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16929 if(c.dateValue > e){
16932 if(c.dateValue < s){
16941 // findBestRow: function(cells)
16945 // for (var i =0 ; i < cells.length;i++) {
16946 // ret = Math.max(cells[i].rows || 0,ret);
16953 addItem : function(ev)
16955 // look for vertical location slot in
16956 var cells = this.findCells(ev);
16958 // ev.row = this.findBestRow(cells);
16960 // work out the location.
16964 for(var i =0; i < cells.length; i++) {
16966 cells[i].row = cells[0].row;
16969 cells[i].row = cells[i].row + 1;
16979 if (crow.start.getY() == cells[i].getY()) {
16981 crow.end = cells[i];
16998 cells[0].events.push(ev);
17000 this.calevents.push(ev);
17003 clearEvents: function() {
17005 if(!this.calevents){
17009 Roo.each(this.cells.elements, function(c){
17015 Roo.each(this.calevents, function(e) {
17016 Roo.each(e.els, function(el) {
17017 el.un('mouseenter' ,this.onEventEnter, this);
17018 el.un('mouseleave' ,this.onEventLeave, this);
17023 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17029 renderEvents: function()
17033 this.cells.each(function(c) {
17042 if(c.row != c.events.length){
17043 r = 4 - (4 - (c.row - c.events.length));
17046 c.events = ev.slice(0, r);
17047 c.more = ev.slice(r);
17049 if(c.more.length && c.more.length == 1){
17050 c.events.push(c.more.pop());
17053 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17057 this.cells.each(function(c) {
17059 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17062 for (var e = 0; e < c.events.length; e++){
17063 var ev = c.events[e];
17064 var rows = ev.rows;
17066 for(var i = 0; i < rows.length; i++) {
17068 // how many rows should it span..
17071 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17072 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17074 unselectable : "on",
17077 cls: 'fc-event-inner',
17081 // cls: 'fc-event-time',
17082 // html : cells.length > 1 ? '' : ev.time
17086 cls: 'fc-event-title',
17087 html : String.format('{0}', ev.title)
17094 cls: 'ui-resizable-handle ui-resizable-e',
17095 html : '  '
17102 cfg.cls += ' fc-event-start';
17104 if ((i+1) == rows.length) {
17105 cfg.cls += ' fc-event-end';
17108 var ctr = _this.el.select('.fc-event-container',true).first();
17109 var cg = ctr.createChild(cfg);
17111 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17112 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17114 var r = (c.more.length) ? 1 : 0;
17115 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17116 cg.setWidth(ebox.right - sbox.x -2);
17118 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17119 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17120 cg.on('click', _this.onEventClick, _this, ev);
17131 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17132 style : 'position: absolute',
17133 unselectable : "on",
17136 cls: 'fc-event-inner',
17140 cls: 'fc-event-title',
17148 cls: 'ui-resizable-handle ui-resizable-e',
17149 html : '  '
17155 var ctr = _this.el.select('.fc-event-container',true).first();
17156 var cg = ctr.createChild(cfg);
17158 var sbox = c.select('.fc-day-content',true).first().getBox();
17159 var ebox = c.select('.fc-day-content',true).first().getBox();
17161 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17162 cg.setWidth(ebox.right - sbox.x -2);
17164 cg.on('click', _this.onMoreEventClick, _this, c.more);
17174 onEventEnter: function (e, el,event,d) {
17175 this.fireEvent('evententer', this, el, event);
17178 onEventLeave: function (e, el,event,d) {
17179 this.fireEvent('eventleave', this, el, event);
17182 onEventClick: function (e, el,event,d) {
17183 this.fireEvent('eventclick', this, el, event);
17186 onMonthChange: function () {
17190 onMoreEventClick: function(e, el, more)
17194 this.calpopover.placement = 'right';
17195 this.calpopover.setTitle('More');
17197 this.calpopover.setContent('');
17199 var ctr = this.calpopover.el.select('.popover-content', true).first();
17201 Roo.each(more, function(m){
17203 cls : 'fc-event-hori fc-event-draggable',
17206 var cg = ctr.createChild(cfg);
17208 cg.on('click', _this.onEventClick, _this, m);
17211 this.calpopover.show(el);
17216 onLoad: function ()
17218 this.calevents = [];
17221 if(this.store.getCount() > 0){
17222 this.store.data.each(function(d){
17225 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17226 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17227 time : d.data.start_time,
17228 title : d.data.title,
17229 description : d.data.description,
17230 venue : d.data.venue
17235 this.renderEvents();
17237 if(this.calevents.length && this.loadMask){
17238 this.maskEl.hide();
17242 onBeforeLoad: function()
17244 this.clearEvents();
17246 this.maskEl.show();
17260 * @class Roo.bootstrap.Popover
17261 * @extends Roo.bootstrap.Component
17262 * Bootstrap Popover class
17263 * @cfg {String} html contents of the popover (or false to use children..)
17264 * @cfg {String} title of popover (or false to hide)
17265 * @cfg {String} placement how it is placed
17266 * @cfg {String} trigger click || hover (or false to trigger manually)
17267 * @cfg {String} over what (parent or false to trigger manually.)
17268 * @cfg {Number} delay - delay before showing
17271 * Create a new Popover
17272 * @param {Object} config The config object
17275 Roo.bootstrap.Popover = function(config){
17276 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17282 * After the popover show
17284 * @param {Roo.bootstrap.Popover} this
17289 * After the popover hide
17291 * @param {Roo.bootstrap.Popover} this
17297 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17299 title: 'Fill in a title',
17302 placement : 'right',
17303 trigger : 'hover', // hover
17309 can_build_overlaid : false,
17311 getChildContainer : function()
17313 return this.el.select('.popover-content',true).first();
17316 getAutoCreate : function(){
17319 cls : 'popover roo-dynamic',
17320 style: 'display:block',
17326 cls : 'popover-inner',
17330 cls: 'popover-title',
17334 cls : 'popover-content',
17345 setTitle: function(str)
17348 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17350 setContent: function(str)
17353 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17355 // as it get's added to the bottom of the page.
17356 onRender : function(ct, position)
17358 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17360 var cfg = Roo.apply({}, this.getAutoCreate());
17364 cfg.cls += ' ' + this.cls;
17367 cfg.style = this.style;
17369 //Roo.log("adding to ");
17370 this.el = Roo.get(document.body).createChild(cfg, position);
17371 // Roo.log(this.el);
17376 initEvents : function()
17378 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17379 this.el.enableDisplayMode('block');
17381 if (this.over === false) {
17384 if (this.triggers === false) {
17387 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17388 var triggers = this.trigger ? this.trigger.split(' ') : [];
17389 Roo.each(triggers, function(trigger) {
17391 if (trigger == 'click') {
17392 on_el.on('click', this.toggle, this);
17393 } else if (trigger != 'manual') {
17394 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17395 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17397 on_el.on(eventIn ,this.enter, this);
17398 on_el.on(eventOut, this.leave, this);
17409 toggle : function () {
17410 this.hoverState == 'in' ? this.leave() : this.enter();
17413 enter : function () {
17415 clearTimeout(this.timeout);
17417 this.hoverState = 'in';
17419 if (!this.delay || !this.delay.show) {
17424 this.timeout = setTimeout(function () {
17425 if (_t.hoverState == 'in') {
17428 }, this.delay.show)
17431 leave : function() {
17432 clearTimeout(this.timeout);
17434 this.hoverState = 'out';
17436 if (!this.delay || !this.delay.hide) {
17441 this.timeout = setTimeout(function () {
17442 if (_t.hoverState == 'out') {
17445 }, this.delay.hide)
17448 show : function (on_el)
17451 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17455 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17456 if (this.html !== false) {
17457 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17459 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17460 if (!this.title.length) {
17461 this.el.select('.popover-title',true).hide();
17464 var placement = typeof this.placement == 'function' ?
17465 this.placement.call(this, this.el, on_el) :
17468 var autoToken = /\s?auto?\s?/i;
17469 var autoPlace = autoToken.test(placement);
17471 placement = placement.replace(autoToken, '') || 'top';
17475 //this.el.setXY([0,0]);
17477 this.el.dom.style.display='block';
17478 this.el.addClass(placement);
17480 //this.el.appendTo(on_el);
17482 var p = this.getPosition();
17483 var box = this.el.getBox();
17488 var align = Roo.bootstrap.Popover.alignment[placement];
17491 this.el.alignTo(on_el, align[0],align[1]);
17492 //var arrow = this.el.select('.arrow',true).first();
17493 //arrow.set(align[2],
17495 this.el.addClass('in');
17498 if (this.el.hasClass('fade')) {
17502 this.hoverState = 'in';
17504 this.fireEvent('show', this);
17509 this.el.setXY([0,0]);
17510 this.el.removeClass('in');
17512 this.hoverState = null;
17514 this.fireEvent('hide', this);
17519 Roo.bootstrap.Popover.alignment = {
17520 'left' : ['r-l', [-10,0], 'right'],
17521 'right' : ['l-r', [10,0], 'left'],
17522 'bottom' : ['t-b', [0,10], 'top'],
17523 'top' : [ 'b-t', [0,-10], 'bottom']
17534 * @class Roo.bootstrap.Progress
17535 * @extends Roo.bootstrap.Component
17536 * Bootstrap Progress class
17537 * @cfg {Boolean} striped striped of the progress bar
17538 * @cfg {Boolean} active animated of the progress bar
17542 * Create a new Progress
17543 * @param {Object} config The config object
17546 Roo.bootstrap.Progress = function(config){
17547 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17550 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17555 getAutoCreate : function(){
17563 cfg.cls += ' progress-striped';
17567 cfg.cls += ' active';
17586 * @class Roo.bootstrap.ProgressBar
17587 * @extends Roo.bootstrap.Component
17588 * Bootstrap ProgressBar class
17589 * @cfg {Number} aria_valuenow aria-value now
17590 * @cfg {Number} aria_valuemin aria-value min
17591 * @cfg {Number} aria_valuemax aria-value max
17592 * @cfg {String} label label for the progress bar
17593 * @cfg {String} panel (success | info | warning | danger )
17594 * @cfg {String} role role of the progress bar
17595 * @cfg {String} sr_only text
17599 * Create a new ProgressBar
17600 * @param {Object} config The config object
17603 Roo.bootstrap.ProgressBar = function(config){
17604 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17607 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17611 aria_valuemax : 100,
17617 getAutoCreate : function()
17622 cls: 'progress-bar',
17623 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17635 cfg.role = this.role;
17638 if(this.aria_valuenow){
17639 cfg['aria-valuenow'] = this.aria_valuenow;
17642 if(this.aria_valuemin){
17643 cfg['aria-valuemin'] = this.aria_valuemin;
17646 if(this.aria_valuemax){
17647 cfg['aria-valuemax'] = this.aria_valuemax;
17650 if(this.label && !this.sr_only){
17651 cfg.html = this.label;
17655 cfg.cls += ' progress-bar-' + this.panel;
17661 update : function(aria_valuenow)
17663 this.aria_valuenow = aria_valuenow;
17665 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17680 * @class Roo.bootstrap.TabGroup
17681 * @extends Roo.bootstrap.Column
17682 * Bootstrap Column class
17683 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17684 * @cfg {Boolean} carousel true to make the group behave like a carousel
17685 * @cfg {Boolean} bullets show bullets for the panels
17686 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17687 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17688 * @cfg {Boolean} showarrow (true|false) show arrow default true
17691 * Create a new TabGroup
17692 * @param {Object} config The config object
17695 Roo.bootstrap.TabGroup = function(config){
17696 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17698 this.navId = Roo.id();
17701 Roo.bootstrap.TabGroup.register(this);
17705 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17708 transition : false,
17713 slideOnTouch : false,
17716 getAutoCreate : function()
17718 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17720 cfg.cls += ' tab-content';
17722 if (this.carousel) {
17723 cfg.cls += ' carousel slide';
17726 cls : 'carousel-inner',
17730 if(this.bullets && !Roo.isTouch){
17733 cls : 'carousel-bullets',
17737 if(this.bullets_cls){
17738 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17745 cfg.cn[0].cn.push(bullets);
17748 if(this.showarrow){
17749 cfg.cn[0].cn.push({
17751 class : 'carousel-arrow',
17755 class : 'carousel-prev',
17759 class : 'fa fa-chevron-left'
17765 class : 'carousel-next',
17769 class : 'fa fa-chevron-right'
17782 initEvents: function()
17784 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17785 // this.el.on("touchstart", this.onTouchStart, this);
17788 if(this.autoslide){
17791 this.slideFn = window.setInterval(function() {
17792 _this.showPanelNext();
17796 if(this.showarrow){
17797 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17798 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17804 // onTouchStart : function(e, el, o)
17806 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17810 // this.showPanelNext();
17814 getChildContainer : function()
17816 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17820 * register a Navigation item
17821 * @param {Roo.bootstrap.NavItem} the navitem to add
17823 register : function(item)
17825 this.tabs.push( item);
17826 item.navId = this.navId; // not really needed..
17831 getActivePanel : function()
17834 Roo.each(this.tabs, function(t) {
17844 getPanelByName : function(n)
17847 Roo.each(this.tabs, function(t) {
17848 if (t.tabId == n) {
17856 indexOfPanel : function(p)
17859 Roo.each(this.tabs, function(t,i) {
17860 if (t.tabId == p.tabId) {
17869 * show a specific panel
17870 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17871 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17873 showPanel : function (pan)
17875 if(this.transition || typeof(pan) == 'undefined'){
17876 Roo.log("waiting for the transitionend");
17880 if (typeof(pan) == 'number') {
17881 pan = this.tabs[pan];
17884 if (typeof(pan) == 'string') {
17885 pan = this.getPanelByName(pan);
17888 var cur = this.getActivePanel();
17891 Roo.log('pan or acitve pan is undefined');
17895 if (pan.tabId == this.getActivePanel().tabId) {
17899 if (false === cur.fireEvent('beforedeactivate')) {
17903 if(this.bullets > 0 && !Roo.isTouch){
17904 this.setActiveBullet(this.indexOfPanel(pan));
17907 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17909 this.transition = true;
17910 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17911 var lr = dir == 'next' ? 'left' : 'right';
17912 pan.el.addClass(dir); // or prev
17913 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17914 cur.el.addClass(lr); // or right
17915 pan.el.addClass(lr);
17918 cur.el.on('transitionend', function() {
17919 Roo.log("trans end?");
17921 pan.el.removeClass([lr,dir]);
17922 pan.setActive(true);
17924 cur.el.removeClass([lr]);
17925 cur.setActive(false);
17927 _this.transition = false;
17929 }, this, { single: true } );
17934 cur.setActive(false);
17935 pan.setActive(true);
17940 showPanelNext : function()
17942 var i = this.indexOfPanel(this.getActivePanel());
17944 if (i >= this.tabs.length - 1 && !this.autoslide) {
17948 if (i >= this.tabs.length - 1 && this.autoslide) {
17952 this.showPanel(this.tabs[i+1]);
17955 showPanelPrev : function()
17957 var i = this.indexOfPanel(this.getActivePanel());
17959 if (i < 1 && !this.autoslide) {
17963 if (i < 1 && this.autoslide) {
17964 i = this.tabs.length;
17967 this.showPanel(this.tabs[i-1]);
17971 addBullet: function()
17973 if(!this.bullets || Roo.isTouch){
17976 var ctr = this.el.select('.carousel-bullets',true).first();
17977 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17978 var bullet = ctr.createChild({
17979 cls : 'bullet bullet-' + i
17980 },ctr.dom.lastChild);
17985 bullet.on('click', (function(e, el, o, ii, t){
17987 e.preventDefault();
17989 this.showPanel(ii);
17991 if(this.autoslide && this.slideFn){
17992 clearInterval(this.slideFn);
17993 this.slideFn = window.setInterval(function() {
17994 _this.showPanelNext();
17998 }).createDelegate(this, [i, bullet], true));
18003 setActiveBullet : function(i)
18009 Roo.each(this.el.select('.bullet', true).elements, function(el){
18010 el.removeClass('selected');
18013 var bullet = this.el.select('.bullet-' + i, true).first();
18019 bullet.addClass('selected');
18030 Roo.apply(Roo.bootstrap.TabGroup, {
18034 * register a Navigation Group
18035 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18037 register : function(navgrp)
18039 this.groups[navgrp.navId] = navgrp;
18043 * fetch a Navigation Group based on the navigation ID
18044 * if one does not exist , it will get created.
18045 * @param {string} the navgroup to add
18046 * @returns {Roo.bootstrap.NavGroup} the navgroup
18048 get: function(navId) {
18049 if (typeof(this.groups[navId]) == 'undefined') {
18050 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18052 return this.groups[navId] ;
18067 * @class Roo.bootstrap.TabPanel
18068 * @extends Roo.bootstrap.Component
18069 * Bootstrap TabPanel class
18070 * @cfg {Boolean} active panel active
18071 * @cfg {String} html panel content
18072 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18073 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18074 * @cfg {String} href click to link..
18078 * Create a new TabPanel
18079 * @param {Object} config The config object
18082 Roo.bootstrap.TabPanel = function(config){
18083 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18087 * Fires when the active status changes
18088 * @param {Roo.bootstrap.TabPanel} this
18089 * @param {Boolean} state the new state
18094 * @event beforedeactivate
18095 * Fires before a tab is de-activated - can be used to do validation on a form.
18096 * @param {Roo.bootstrap.TabPanel} this
18097 * @return {Boolean} false if there is an error
18100 'beforedeactivate': true
18103 this.tabId = this.tabId || Roo.id();
18107 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18115 getAutoCreate : function(){
18118 // item is needed for carousel - not sure if it has any effect otherwise
18119 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18120 html: this.html || ''
18124 cfg.cls += ' active';
18128 cfg.tabId = this.tabId;
18135 initEvents: function()
18137 var p = this.parent();
18139 this.navId = this.navId || p.navId;
18141 if (typeof(this.navId) != 'undefined') {
18142 // not really needed.. but just in case.. parent should be a NavGroup.
18143 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18147 var i = tg.tabs.length - 1;
18149 if(this.active && tg.bullets > 0 && i < tg.bullets){
18150 tg.setActiveBullet(i);
18154 this.el.on('click', this.onClick, this);
18157 this.el.on("touchstart", this.onTouchStart, this);
18158 this.el.on("touchmove", this.onTouchMove, this);
18159 this.el.on("touchend", this.onTouchEnd, this);
18164 onRender : function(ct, position)
18166 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18169 setActive : function(state)
18171 Roo.log("panel - set active " + this.tabId + "=" + state);
18173 this.active = state;
18175 this.el.removeClass('active');
18177 } else if (!this.el.hasClass('active')) {
18178 this.el.addClass('active');
18181 this.fireEvent('changed', this, state);
18184 onClick : function(e)
18186 e.preventDefault();
18188 if(!this.href.length){
18192 window.location.href = this.href;
18201 onTouchStart : function(e)
18203 this.swiping = false;
18205 this.startX = e.browserEvent.touches[0].clientX;
18206 this.startY = e.browserEvent.touches[0].clientY;
18209 onTouchMove : function(e)
18211 this.swiping = true;
18213 this.endX = e.browserEvent.touches[0].clientX;
18214 this.endY = e.browserEvent.touches[0].clientY;
18217 onTouchEnd : function(e)
18224 var tabGroup = this.parent();
18226 if(this.endX > this.startX){ // swiping right
18227 tabGroup.showPanelPrev();
18231 if(this.startX > this.endX){ // swiping left
18232 tabGroup.showPanelNext();
18251 * @class Roo.bootstrap.DateField
18252 * @extends Roo.bootstrap.Input
18253 * Bootstrap DateField class
18254 * @cfg {Number} weekStart default 0
18255 * @cfg {String} viewMode default empty, (months|years)
18256 * @cfg {String} minViewMode default empty, (months|years)
18257 * @cfg {Number} startDate default -Infinity
18258 * @cfg {Number} endDate default Infinity
18259 * @cfg {Boolean} todayHighlight default false
18260 * @cfg {Boolean} todayBtn default false
18261 * @cfg {Boolean} calendarWeeks default false
18262 * @cfg {Object} daysOfWeekDisabled default empty
18263 * @cfg {Boolean} singleMode default false (true | false)
18265 * @cfg {Boolean} keyboardNavigation default true
18266 * @cfg {String} language default en
18269 * Create a new DateField
18270 * @param {Object} config The config object
18273 Roo.bootstrap.DateField = function(config){
18274 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18278 * Fires when this field show.
18279 * @param {Roo.bootstrap.DateField} this
18280 * @param {Mixed} date The date value
18285 * Fires when this field hide.
18286 * @param {Roo.bootstrap.DateField} this
18287 * @param {Mixed} date The date value
18292 * Fires when select a date.
18293 * @param {Roo.bootstrap.DateField} this
18294 * @param {Mixed} date The date value
18298 * @event beforeselect
18299 * Fires when before select a date.
18300 * @param {Roo.bootstrap.DateField} this
18301 * @param {Mixed} date The date value
18303 beforeselect : true
18307 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18310 * @cfg {String} format
18311 * The default date format string which can be overriden for localization support. The format must be
18312 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18316 * @cfg {String} altFormats
18317 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18318 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18320 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18328 todayHighlight : false,
18334 keyboardNavigation: true,
18336 calendarWeeks: false,
18338 startDate: -Infinity,
18342 daysOfWeekDisabled: [],
18346 singleMode : false,
18348 UTCDate: function()
18350 return new Date(Date.UTC.apply(Date, arguments));
18353 UTCToday: function()
18355 var today = new Date();
18356 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18359 getDate: function() {
18360 var d = this.getUTCDate();
18361 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18364 getUTCDate: function() {
18368 setDate: function(d) {
18369 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18372 setUTCDate: function(d) {
18374 this.setValue(this.formatDate(this.date));
18377 onRender: function(ct, position)
18380 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18382 this.language = this.language || 'en';
18383 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18384 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18386 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18387 this.format = this.format || 'm/d/y';
18388 this.isInline = false;
18389 this.isInput = true;
18390 this.component = this.el.select('.add-on', true).first() || false;
18391 this.component = (this.component && this.component.length === 0) ? false : this.component;
18392 this.hasInput = this.component && this.inputEl().length;
18394 if (typeof(this.minViewMode === 'string')) {
18395 switch (this.minViewMode) {
18397 this.minViewMode = 1;
18400 this.minViewMode = 2;
18403 this.minViewMode = 0;
18408 if (typeof(this.viewMode === 'string')) {
18409 switch (this.viewMode) {
18422 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18424 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18426 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18428 this.picker().on('mousedown', this.onMousedown, this);
18429 this.picker().on('click', this.onClick, this);
18431 this.picker().addClass('datepicker-dropdown');
18433 this.startViewMode = this.viewMode;
18435 if(this.singleMode){
18436 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18437 v.setVisibilityMode(Roo.Element.DISPLAY);
18441 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18442 v.setStyle('width', '189px');
18446 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18447 if(!this.calendarWeeks){
18452 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18453 v.attr('colspan', function(i, val){
18454 return parseInt(val) + 1;
18459 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18461 this.setStartDate(this.startDate);
18462 this.setEndDate(this.endDate);
18464 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18471 if(this.isInline) {
18476 picker : function()
18478 return this.pickerEl;
18479 // return this.el.select('.datepicker', true).first();
18482 fillDow: function()
18484 var dowCnt = this.weekStart;
18493 if(this.calendarWeeks){
18501 while (dowCnt < this.weekStart + 7) {
18505 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18509 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18512 fillMonths: function()
18515 var months = this.picker().select('>.datepicker-months td', true).first();
18517 months.dom.innerHTML = '';
18523 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18526 months.createChild(month);
18533 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;
18535 if (this.date < this.startDate) {
18536 this.viewDate = new Date(this.startDate);
18537 } else if (this.date > this.endDate) {
18538 this.viewDate = new Date(this.endDate);
18540 this.viewDate = new Date(this.date);
18548 var d = new Date(this.viewDate),
18549 year = d.getUTCFullYear(),
18550 month = d.getUTCMonth(),
18551 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18552 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18553 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18554 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18555 currentDate = this.date && this.date.valueOf(),
18556 today = this.UTCToday();
18558 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18560 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18562 // this.picker.select('>tfoot th.today').
18563 // .text(dates[this.language].today)
18564 // .toggle(this.todayBtn !== false);
18566 this.updateNavArrows();
18569 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18571 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18573 prevMonth.setUTCDate(day);
18575 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18577 var nextMonth = new Date(prevMonth);
18579 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18581 nextMonth = nextMonth.valueOf();
18583 var fillMonths = false;
18585 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18587 while(prevMonth.valueOf() < nextMonth) {
18590 if (prevMonth.getUTCDay() === this.weekStart) {
18592 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18600 if(this.calendarWeeks){
18601 // ISO 8601: First week contains first thursday.
18602 // ISO also states week starts on Monday, but we can be more abstract here.
18604 // Start of current week: based on weekstart/current date
18605 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18606 // Thursday of this week
18607 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18608 // First Thursday of year, year from thursday
18609 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18610 // Calendar week: ms between thursdays, div ms per day, div 7 days
18611 calWeek = (th - yth) / 864e5 / 7 + 1;
18613 fillMonths.cn.push({
18621 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18623 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18626 if (this.todayHighlight &&
18627 prevMonth.getUTCFullYear() == today.getFullYear() &&
18628 prevMonth.getUTCMonth() == today.getMonth() &&
18629 prevMonth.getUTCDate() == today.getDate()) {
18630 clsName += ' today';
18633 if (currentDate && prevMonth.valueOf() === currentDate) {
18634 clsName += ' active';
18637 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18638 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18639 clsName += ' disabled';
18642 fillMonths.cn.push({
18644 cls: 'day ' + clsName,
18645 html: prevMonth.getDate()
18648 prevMonth.setDate(prevMonth.getDate()+1);
18651 var currentYear = this.date && this.date.getUTCFullYear();
18652 var currentMonth = this.date && this.date.getUTCMonth();
18654 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18656 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18657 v.removeClass('active');
18659 if(currentYear === year && k === currentMonth){
18660 v.addClass('active');
18663 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18664 v.addClass('disabled');
18670 year = parseInt(year/10, 10) * 10;
18672 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18674 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18677 for (var i = -1; i < 11; i++) {
18678 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18680 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18688 showMode: function(dir)
18691 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18694 Roo.each(this.picker().select('>div',true).elements, function(v){
18695 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18698 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18703 if(this.isInline) {
18707 this.picker().removeClass(['bottom', 'top']);
18709 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18711 * place to the top of element!
18715 this.picker().addClass('top');
18716 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18721 this.picker().addClass('bottom');
18723 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18726 parseDate : function(value)
18728 if(!value || value instanceof Date){
18731 var v = Date.parseDate(value, this.format);
18732 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18733 v = Date.parseDate(value, 'Y-m-d');
18735 if(!v && this.altFormats){
18736 if(!this.altFormatsArray){
18737 this.altFormatsArray = this.altFormats.split("|");
18739 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18740 v = Date.parseDate(value, this.altFormatsArray[i]);
18746 formatDate : function(date, fmt)
18748 return (!date || !(date instanceof Date)) ?
18749 date : date.dateFormat(fmt || this.format);
18752 onFocus : function()
18754 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18758 onBlur : function()
18760 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18762 var d = this.inputEl().getValue();
18771 this.picker().show();
18775 this.fireEvent('show', this, this.date);
18780 if(this.isInline) {
18783 this.picker().hide();
18784 this.viewMode = this.startViewMode;
18787 this.fireEvent('hide', this, this.date);
18791 onMousedown: function(e)
18793 e.stopPropagation();
18794 e.preventDefault();
18799 Roo.bootstrap.DateField.superclass.keyup.call(this);
18803 setValue: function(v)
18805 if(this.fireEvent('beforeselect', this, v) !== false){
18806 var d = new Date(this.parseDate(v) ).clearTime();
18808 if(isNaN(d.getTime())){
18809 this.date = this.viewDate = '';
18810 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18814 v = this.formatDate(d);
18816 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18818 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18822 this.fireEvent('select', this, this.date);
18826 getValue: function()
18828 return this.formatDate(this.date);
18831 fireKey: function(e)
18833 if (!this.picker().isVisible()){
18834 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18840 var dateChanged = false,
18842 newDate, newViewDate;
18847 e.preventDefault();
18851 if (!this.keyboardNavigation) {
18854 dir = e.keyCode == 37 ? -1 : 1;
18857 newDate = this.moveYear(this.date, dir);
18858 newViewDate = this.moveYear(this.viewDate, dir);
18859 } else if (e.shiftKey){
18860 newDate = this.moveMonth(this.date, dir);
18861 newViewDate = this.moveMonth(this.viewDate, dir);
18863 newDate = new Date(this.date);
18864 newDate.setUTCDate(this.date.getUTCDate() + dir);
18865 newViewDate = new Date(this.viewDate);
18866 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18868 if (this.dateWithinRange(newDate)){
18869 this.date = newDate;
18870 this.viewDate = newViewDate;
18871 this.setValue(this.formatDate(this.date));
18873 e.preventDefault();
18874 dateChanged = true;
18879 if (!this.keyboardNavigation) {
18882 dir = e.keyCode == 38 ? -1 : 1;
18884 newDate = this.moveYear(this.date, dir);
18885 newViewDate = this.moveYear(this.viewDate, dir);
18886 } else if (e.shiftKey){
18887 newDate = this.moveMonth(this.date, dir);
18888 newViewDate = this.moveMonth(this.viewDate, dir);
18890 newDate = new Date(this.date);
18891 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18892 newViewDate = new Date(this.viewDate);
18893 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18895 if (this.dateWithinRange(newDate)){
18896 this.date = newDate;
18897 this.viewDate = newViewDate;
18898 this.setValue(this.formatDate(this.date));
18900 e.preventDefault();
18901 dateChanged = true;
18905 this.setValue(this.formatDate(this.date));
18907 e.preventDefault();
18910 this.setValue(this.formatDate(this.date));
18924 onClick: function(e)
18926 e.stopPropagation();
18927 e.preventDefault();
18929 var target = e.getTarget();
18931 if(target.nodeName.toLowerCase() === 'i'){
18932 target = Roo.get(target).dom.parentNode;
18935 var nodeName = target.nodeName;
18936 var className = target.className;
18937 var html = target.innerHTML;
18938 //Roo.log(nodeName);
18940 switch(nodeName.toLowerCase()) {
18942 switch(className) {
18948 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18949 switch(this.viewMode){
18951 this.viewDate = this.moveMonth(this.viewDate, dir);
18955 this.viewDate = this.moveYear(this.viewDate, dir);
18961 var date = new Date();
18962 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18964 this.setValue(this.formatDate(this.date));
18971 if (className.indexOf('disabled') < 0) {
18972 this.viewDate.setUTCDate(1);
18973 if (className.indexOf('month') > -1) {
18974 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18976 var year = parseInt(html, 10) || 0;
18977 this.viewDate.setUTCFullYear(year);
18981 if(this.singleMode){
18982 this.setValue(this.formatDate(this.viewDate));
18993 //Roo.log(className);
18994 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18995 var day = parseInt(html, 10) || 1;
18996 var year = this.viewDate.getUTCFullYear(),
18997 month = this.viewDate.getUTCMonth();
18999 if (className.indexOf('old') > -1) {
19006 } else if (className.indexOf('new') > -1) {
19014 //Roo.log([year,month,day]);
19015 this.date = this.UTCDate(year, month, day,0,0,0,0);
19016 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19018 //Roo.log(this.formatDate(this.date));
19019 this.setValue(this.formatDate(this.date));
19026 setStartDate: function(startDate)
19028 this.startDate = startDate || -Infinity;
19029 if (this.startDate !== -Infinity) {
19030 this.startDate = this.parseDate(this.startDate);
19033 this.updateNavArrows();
19036 setEndDate: function(endDate)
19038 this.endDate = endDate || Infinity;
19039 if (this.endDate !== Infinity) {
19040 this.endDate = this.parseDate(this.endDate);
19043 this.updateNavArrows();
19046 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19048 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19049 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19050 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19052 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19053 return parseInt(d, 10);
19056 this.updateNavArrows();
19059 updateNavArrows: function()
19061 if(this.singleMode){
19065 var d = new Date(this.viewDate),
19066 year = d.getUTCFullYear(),
19067 month = d.getUTCMonth();
19069 Roo.each(this.picker().select('.prev', true).elements, function(v){
19071 switch (this.viewMode) {
19074 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19080 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19087 Roo.each(this.picker().select('.next', true).elements, function(v){
19089 switch (this.viewMode) {
19092 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19098 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19106 moveMonth: function(date, dir)
19111 var new_date = new Date(date.valueOf()),
19112 day = new_date.getUTCDate(),
19113 month = new_date.getUTCMonth(),
19114 mag = Math.abs(dir),
19116 dir = dir > 0 ? 1 : -1;
19119 // If going back one month, make sure month is not current month
19120 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19122 return new_date.getUTCMonth() == month;
19124 // If going forward one month, make sure month is as expected
19125 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19127 return new_date.getUTCMonth() != new_month;
19129 new_month = month + dir;
19130 new_date.setUTCMonth(new_month);
19131 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19132 if (new_month < 0 || new_month > 11) {
19133 new_month = (new_month + 12) % 12;
19136 // For magnitudes >1, move one month at a time...
19137 for (var i=0; i<mag; i++) {
19138 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19139 new_date = this.moveMonth(new_date, dir);
19141 // ...then reset the day, keeping it in the new month
19142 new_month = new_date.getUTCMonth();
19143 new_date.setUTCDate(day);
19145 return new_month != new_date.getUTCMonth();
19148 // Common date-resetting loop -- if date is beyond end of month, make it
19151 new_date.setUTCDate(--day);
19152 new_date.setUTCMonth(new_month);
19157 moveYear: function(date, dir)
19159 return this.moveMonth(date, dir*12);
19162 dateWithinRange: function(date)
19164 return date >= this.startDate && date <= this.endDate;
19170 this.picker().remove();
19173 validateValue : function(value)
19175 if(this.getVisibilityEl().hasClass('hidden')){
19179 if(value.length < 1) {
19180 if(this.allowBlank){
19186 if(value.length < this.minLength){
19189 if(value.length > this.maxLength){
19193 var vt = Roo.form.VTypes;
19194 if(!vt[this.vtype](value, this)){
19198 if(typeof this.validator == "function"){
19199 var msg = this.validator(value);
19205 if(this.regex && !this.regex.test(value)){
19209 if(typeof(this.parseDate(value)) == 'undefined'){
19213 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19217 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19225 setVisible : function(visible)
19231 this.getEl().removeClass('hidden');
19237 this.getEl().addClass('hidden');
19242 Roo.apply(Roo.bootstrap.DateField, {
19253 html: '<i class="fa fa-arrow-left"/>'
19263 html: '<i class="fa fa-arrow-right"/>'
19305 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19306 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19307 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19308 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19309 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19322 navFnc: 'FullYear',
19327 navFnc: 'FullYear',
19332 Roo.apply(Roo.bootstrap.DateField, {
19336 cls: 'datepicker dropdown-menu roo-dynamic',
19340 cls: 'datepicker-days',
19344 cls: 'table-condensed',
19346 Roo.bootstrap.DateField.head,
19350 Roo.bootstrap.DateField.footer
19357 cls: 'datepicker-months',
19361 cls: 'table-condensed',
19363 Roo.bootstrap.DateField.head,
19364 Roo.bootstrap.DateField.content,
19365 Roo.bootstrap.DateField.footer
19372 cls: 'datepicker-years',
19376 cls: 'table-condensed',
19378 Roo.bootstrap.DateField.head,
19379 Roo.bootstrap.DateField.content,
19380 Roo.bootstrap.DateField.footer
19399 * @class Roo.bootstrap.TimeField
19400 * @extends Roo.bootstrap.Input
19401 * Bootstrap DateField class
19405 * Create a new TimeField
19406 * @param {Object} config The config object
19409 Roo.bootstrap.TimeField = function(config){
19410 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19414 * Fires when this field show.
19415 * @param {Roo.bootstrap.DateField} thisthis
19416 * @param {Mixed} date The date value
19421 * Fires when this field hide.
19422 * @param {Roo.bootstrap.DateField} this
19423 * @param {Mixed} date The date value
19428 * Fires when select a date.
19429 * @param {Roo.bootstrap.DateField} this
19430 * @param {Mixed} date The date value
19436 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19439 * @cfg {String} format
19440 * The default time format string which can be overriden for localization support. The format must be
19441 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19445 onRender: function(ct, position)
19448 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19450 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19452 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19454 this.pop = this.picker().select('>.datepicker-time',true).first();
19455 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19457 this.picker().on('mousedown', this.onMousedown, this);
19458 this.picker().on('click', this.onClick, this);
19460 this.picker().addClass('datepicker-dropdown');
19465 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19466 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19467 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19468 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19469 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19470 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19474 fireKey: function(e){
19475 if (!this.picker().isVisible()){
19476 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19482 e.preventDefault();
19490 this.onTogglePeriod();
19493 this.onIncrementMinutes();
19496 this.onDecrementMinutes();
19505 onClick: function(e) {
19506 e.stopPropagation();
19507 e.preventDefault();
19510 picker : function()
19512 return this.el.select('.datepicker', true).first();
19515 fillTime: function()
19517 var time = this.pop.select('tbody', true).first();
19519 time.dom.innerHTML = '';
19534 cls: 'hours-up glyphicon glyphicon-chevron-up'
19554 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19575 cls: 'timepicker-hour',
19590 cls: 'timepicker-minute',
19605 cls: 'btn btn-primary period',
19627 cls: 'hours-down glyphicon glyphicon-chevron-down'
19647 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19665 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19672 var hours = this.time.getHours();
19673 var minutes = this.time.getMinutes();
19686 hours = hours - 12;
19690 hours = '0' + hours;
19694 minutes = '0' + minutes;
19697 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19698 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19699 this.pop.select('button', true).first().dom.innerHTML = period;
19705 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19707 var cls = ['bottom'];
19709 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19716 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19721 this.picker().addClass(cls.join('-'));
19725 Roo.each(cls, function(c){
19727 _this.picker().setTop(_this.inputEl().getHeight());
19731 _this.picker().setTop(0 - _this.picker().getHeight());
19736 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19740 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19747 onFocus : function()
19749 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19753 onBlur : function()
19755 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19761 this.picker().show();
19766 this.fireEvent('show', this, this.date);
19771 this.picker().hide();
19774 this.fireEvent('hide', this, this.date);
19777 setTime : function()
19780 this.setValue(this.time.format(this.format));
19782 this.fireEvent('select', this, this.date);
19787 onMousedown: function(e){
19788 e.stopPropagation();
19789 e.preventDefault();
19792 onIncrementHours: function()
19794 Roo.log('onIncrementHours');
19795 this.time = this.time.add(Date.HOUR, 1);
19800 onDecrementHours: function()
19802 Roo.log('onDecrementHours');
19803 this.time = this.time.add(Date.HOUR, -1);
19807 onIncrementMinutes: function()
19809 Roo.log('onIncrementMinutes');
19810 this.time = this.time.add(Date.MINUTE, 1);
19814 onDecrementMinutes: function()
19816 Roo.log('onDecrementMinutes');
19817 this.time = this.time.add(Date.MINUTE, -1);
19821 onTogglePeriod: function()
19823 Roo.log('onTogglePeriod');
19824 this.time = this.time.add(Date.HOUR, 12);
19831 Roo.apply(Roo.bootstrap.TimeField, {
19861 cls: 'btn btn-info ok',
19873 Roo.apply(Roo.bootstrap.TimeField, {
19877 cls: 'datepicker dropdown-menu',
19881 cls: 'datepicker-time',
19885 cls: 'table-condensed',
19887 Roo.bootstrap.TimeField.content,
19888 Roo.bootstrap.TimeField.footer
19907 * @class Roo.bootstrap.MonthField
19908 * @extends Roo.bootstrap.Input
19909 * Bootstrap MonthField class
19911 * @cfg {String} language default en
19914 * Create a new MonthField
19915 * @param {Object} config The config object
19918 Roo.bootstrap.MonthField = function(config){
19919 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19924 * Fires when this field show.
19925 * @param {Roo.bootstrap.MonthField} this
19926 * @param {Mixed} date The date value
19931 * Fires when this field hide.
19932 * @param {Roo.bootstrap.MonthField} this
19933 * @param {Mixed} date The date value
19938 * Fires when select a date.
19939 * @param {Roo.bootstrap.MonthField} this
19940 * @param {String} oldvalue The old value
19941 * @param {String} newvalue The new value
19947 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19949 onRender: function(ct, position)
19952 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19954 this.language = this.language || 'en';
19955 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19956 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19958 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19959 this.isInline = false;
19960 this.isInput = true;
19961 this.component = this.el.select('.add-on', true).first() || false;
19962 this.component = (this.component && this.component.length === 0) ? false : this.component;
19963 this.hasInput = this.component && this.inputEL().length;
19965 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19967 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19969 this.picker().on('mousedown', this.onMousedown, this);
19970 this.picker().on('click', this.onClick, this);
19972 this.picker().addClass('datepicker-dropdown');
19974 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19975 v.setStyle('width', '189px');
19982 if(this.isInline) {
19988 setValue: function(v, suppressEvent)
19990 var o = this.getValue();
19992 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19996 if(suppressEvent !== true){
19997 this.fireEvent('select', this, o, v);
20002 getValue: function()
20007 onClick: function(e)
20009 e.stopPropagation();
20010 e.preventDefault();
20012 var target = e.getTarget();
20014 if(target.nodeName.toLowerCase() === 'i'){
20015 target = Roo.get(target).dom.parentNode;
20018 var nodeName = target.nodeName;
20019 var className = target.className;
20020 var html = target.innerHTML;
20022 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20026 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20028 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20034 picker : function()
20036 return this.pickerEl;
20039 fillMonths: function()
20042 var months = this.picker().select('>.datepicker-months td', true).first();
20044 months.dom.innerHTML = '';
20050 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20053 months.createChild(month);
20062 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20063 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20066 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20067 e.removeClass('active');
20069 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20070 e.addClass('active');
20077 if(this.isInline) {
20081 this.picker().removeClass(['bottom', 'top']);
20083 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20085 * place to the top of element!
20089 this.picker().addClass('top');
20090 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20095 this.picker().addClass('bottom');
20097 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20100 onFocus : function()
20102 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20106 onBlur : function()
20108 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20110 var d = this.inputEl().getValue();
20119 this.picker().show();
20120 this.picker().select('>.datepicker-months', true).first().show();
20124 this.fireEvent('show', this, this.date);
20129 if(this.isInline) {
20132 this.picker().hide();
20133 this.fireEvent('hide', this, this.date);
20137 onMousedown: function(e)
20139 e.stopPropagation();
20140 e.preventDefault();
20145 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20149 fireKey: function(e)
20151 if (!this.picker().isVisible()){
20152 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20163 e.preventDefault();
20167 dir = e.keyCode == 37 ? -1 : 1;
20169 this.vIndex = this.vIndex + dir;
20171 if(this.vIndex < 0){
20175 if(this.vIndex > 11){
20179 if(isNaN(this.vIndex)){
20183 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20189 dir = e.keyCode == 38 ? -1 : 1;
20191 this.vIndex = this.vIndex + dir * 4;
20193 if(this.vIndex < 0){
20197 if(this.vIndex > 11){
20201 if(isNaN(this.vIndex)){
20205 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20210 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20211 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20215 e.preventDefault();
20218 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20219 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20235 this.picker().remove();
20240 Roo.apply(Roo.bootstrap.MonthField, {
20259 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20260 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20265 Roo.apply(Roo.bootstrap.MonthField, {
20269 cls: 'datepicker dropdown-menu roo-dynamic',
20273 cls: 'datepicker-months',
20277 cls: 'table-condensed',
20279 Roo.bootstrap.DateField.content
20299 * @class Roo.bootstrap.CheckBox
20300 * @extends Roo.bootstrap.Input
20301 * Bootstrap CheckBox class
20303 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20304 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20305 * @cfg {String} boxLabel The text that appears beside the checkbox
20306 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20307 * @cfg {Boolean} checked initnal the element
20308 * @cfg {Boolean} inline inline the element (default false)
20309 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20310 * @cfg {String} tooltip label tooltip
20313 * Create a new CheckBox
20314 * @param {Object} config The config object
20317 Roo.bootstrap.CheckBox = function(config){
20318 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20323 * Fires when the element is checked or unchecked.
20324 * @param {Roo.bootstrap.CheckBox} this This input
20325 * @param {Boolean} checked The new checked value
20330 * Fires when the element is click.
20331 * @param {Roo.bootstrap.CheckBox} this This input
20338 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20340 inputType: 'checkbox',
20349 getAutoCreate : function()
20351 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20357 cfg.cls = 'form-group ' + this.inputType; //input-group
20360 cfg.cls += ' ' + this.inputType + '-inline';
20366 type : this.inputType,
20367 value : this.inputValue,
20368 cls : 'roo-' + this.inputType, //'form-box',
20369 placeholder : this.placeholder || ''
20373 if(this.inputType != 'radio'){
20377 cls : 'roo-hidden-value',
20378 value : this.checked ? this.inputValue : this.valueOff
20383 if (this.weight) { // Validity check?
20384 cfg.cls += " " + this.inputType + "-" + this.weight;
20387 if (this.disabled) {
20388 input.disabled=true;
20392 input.checked = this.checked;
20397 input.name = this.name;
20399 if(this.inputType != 'radio'){
20400 hidden.name = this.name;
20401 input.name = '_hidden_' + this.name;
20406 input.cls += ' input-' + this.size;
20411 ['xs','sm','md','lg'].map(function(size){
20412 if (settings[size]) {
20413 cfg.cls += ' col-' + size + '-' + settings[size];
20417 var inputblock = input;
20419 if (this.before || this.after) {
20422 cls : 'input-group',
20427 inputblock.cn.push({
20429 cls : 'input-group-addon',
20434 inputblock.cn.push(input);
20436 if(this.inputType != 'radio'){
20437 inputblock.cn.push(hidden);
20441 inputblock.cn.push({
20443 cls : 'input-group-addon',
20450 if (align ==='left' && this.fieldLabel.length) {
20451 // Roo.log("left and has label");
20456 cls : 'control-label',
20457 html : this.fieldLabel
20467 if(this.labelWidth > 12){
20468 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20471 if(this.labelWidth < 13 && this.labelmd == 0){
20472 this.labelmd = this.labelWidth;
20475 if(this.labellg > 0){
20476 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20477 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20480 if(this.labelmd > 0){
20481 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20482 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20485 if(this.labelsm > 0){
20486 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20487 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20490 if(this.labelxs > 0){
20491 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20492 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20495 } else if ( this.fieldLabel.length) {
20496 // Roo.log(" label");
20500 tag: this.boxLabel ? 'span' : 'label',
20502 cls: 'control-label box-input-label',
20503 //cls : 'input-group-addon',
20504 html : this.fieldLabel
20513 // Roo.log(" no label && no align");
20514 cfg.cn = [ inputblock ] ;
20520 var boxLabelCfg = {
20522 //'for': id, // box label is handled by onclick - so no for...
20524 html: this.boxLabel
20528 boxLabelCfg.tooltip = this.tooltip;
20531 cfg.cn.push(boxLabelCfg);
20534 if(this.inputType != 'radio'){
20535 cfg.cn.push(hidden);
20543 * return the real input element.
20545 inputEl: function ()
20547 return this.el.select('input.roo-' + this.inputType,true).first();
20549 hiddenEl: function ()
20551 return this.el.select('input.roo-hidden-value',true).first();
20554 labelEl: function()
20556 return this.el.select('label.control-label',true).first();
20558 /* depricated... */
20562 return this.labelEl();
20565 boxLabelEl: function()
20567 return this.el.select('label.box-label',true).first();
20570 initEvents : function()
20572 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20574 this.inputEl().on('click', this.onClick, this);
20576 if (this.boxLabel) {
20577 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20580 this.startValue = this.getValue();
20583 Roo.bootstrap.CheckBox.register(this);
20587 onClick : function(e)
20589 if(this.fireEvent('click', this, e) !== false){
20590 this.setChecked(!this.checked);
20595 setChecked : function(state,suppressEvent)
20597 this.startValue = this.getValue();
20599 if(this.inputType == 'radio'){
20601 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20602 e.dom.checked = false;
20605 this.inputEl().dom.checked = true;
20607 this.inputEl().dom.value = this.inputValue;
20609 if(suppressEvent !== true){
20610 this.fireEvent('check', this, true);
20618 this.checked = state;
20620 this.inputEl().dom.checked = state;
20623 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20625 if(suppressEvent !== true){
20626 this.fireEvent('check', this, state);
20632 getValue : function()
20634 if(this.inputType == 'radio'){
20635 return this.getGroupValue();
20638 return this.hiddenEl().dom.value;
20642 getGroupValue : function()
20644 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20648 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20651 setValue : function(v,suppressEvent)
20653 if(this.inputType == 'radio'){
20654 this.setGroupValue(v, suppressEvent);
20658 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20663 setGroupValue : function(v, suppressEvent)
20665 this.startValue = this.getValue();
20667 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20668 e.dom.checked = false;
20670 if(e.dom.value == v){
20671 e.dom.checked = true;
20675 if(suppressEvent !== true){
20676 this.fireEvent('check', this, true);
20684 validate : function()
20686 if(this.getVisibilityEl().hasClass('hidden')){
20692 (this.inputType == 'radio' && this.validateRadio()) ||
20693 (this.inputType == 'checkbox' && this.validateCheckbox())
20699 this.markInvalid();
20703 validateRadio : function()
20705 if(this.getVisibilityEl().hasClass('hidden')){
20709 if(this.allowBlank){
20715 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20716 if(!e.dom.checked){
20728 validateCheckbox : function()
20731 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20732 //return (this.getValue() == this.inputValue) ? true : false;
20735 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20743 for(var i in group){
20744 if(group[i].el.isVisible(true)){
20752 for(var i in group){
20757 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20764 * Mark this field as valid
20766 markValid : function()
20770 this.fireEvent('valid', this);
20772 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20775 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20782 if(this.inputType == 'radio'){
20783 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20784 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20785 e.findParent('.form-group', false, true).addClass(_this.validClass);
20792 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20793 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20797 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20803 for(var i in group){
20804 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20805 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20810 * Mark this field as invalid
20811 * @param {String} msg The validation message
20813 markInvalid : function(msg)
20815 if(this.allowBlank){
20821 this.fireEvent('invalid', this, msg);
20823 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20826 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20830 label.markInvalid();
20833 if(this.inputType == 'radio'){
20834 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20835 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20836 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20843 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20844 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20848 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20854 for(var i in group){
20855 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20856 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20861 clearInvalid : function()
20863 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20865 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20867 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20869 if (label && label.iconEl) {
20870 label.iconEl.removeClass(label.validClass);
20871 label.iconEl.removeClass(label.invalidClass);
20875 disable : function()
20877 if(this.inputType != 'radio'){
20878 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20885 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20886 _this.getActionEl().addClass(this.disabledClass);
20887 e.dom.disabled = true;
20891 this.disabled = true;
20892 this.fireEvent("disable", this);
20896 enable : function()
20898 if(this.inputType != 'radio'){
20899 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20906 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20907 _this.getActionEl().removeClass(this.disabledClass);
20908 e.dom.disabled = false;
20912 this.disabled = false;
20913 this.fireEvent("enable", this);
20917 setBoxLabel : function(v)
20922 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20928 Roo.apply(Roo.bootstrap.CheckBox, {
20933 * register a CheckBox Group
20934 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20936 register : function(checkbox)
20938 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20939 this.groups[checkbox.groupId] = {};
20942 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20946 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20950 * fetch a CheckBox Group based on the group ID
20951 * @param {string} the group ID
20952 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20954 get: function(groupId) {
20955 if (typeof(this.groups[groupId]) == 'undefined') {
20959 return this.groups[groupId] ;
20972 * @class Roo.bootstrap.Radio
20973 * @extends Roo.bootstrap.Component
20974 * Bootstrap Radio class
20975 * @cfg {String} boxLabel - the label associated
20976 * @cfg {String} value - the value of radio
20979 * Create a new Radio
20980 * @param {Object} config The config object
20982 Roo.bootstrap.Radio = function(config){
20983 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20987 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20993 getAutoCreate : function()
20997 cls : 'form-group radio',
21002 html : this.boxLabel
21010 initEvents : function()
21012 this.parent().register(this);
21014 this.el.on('click', this.onClick, this);
21018 onClick : function(e)
21020 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21021 this.setChecked(true);
21025 setChecked : function(state, suppressEvent)
21027 this.parent().setValue(this.value, suppressEvent);
21031 setBoxLabel : function(v)
21036 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21051 * @class Roo.bootstrap.SecurePass
21052 * @extends Roo.bootstrap.Input
21053 * Bootstrap SecurePass class
21057 * Create a new SecurePass
21058 * @param {Object} config The config object
21061 Roo.bootstrap.SecurePass = function (config) {
21062 // these go here, so the translation tool can replace them..
21064 PwdEmpty: "Please type a password, and then retype it to confirm.",
21065 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21066 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21067 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21068 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21069 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21070 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21071 TooWeak: "Your password is Too Weak."
21073 this.meterLabel = "Password strength:";
21074 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21075 this.meterClass = [
21076 "roo-password-meter-tooweak",
21077 "roo-password-meter-weak",
21078 "roo-password-meter-medium",
21079 "roo-password-meter-strong",
21080 "roo-password-meter-grey"
21085 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21088 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21090 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21092 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21093 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21094 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21095 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21096 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21097 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21098 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21108 * @cfg {String/Object} Label for the strength meter (defaults to
21109 * 'Password strength:')
21114 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21115 * ['Weak', 'Medium', 'Strong'])
21118 pwdStrengths: false,
21131 initEvents: function ()
21133 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21135 if (this.el.is('input[type=password]') && Roo.isSafari) {
21136 this.el.on('keydown', this.SafariOnKeyDown, this);
21139 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21142 onRender: function (ct, position)
21144 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21145 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21146 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21148 this.trigger.createChild({
21153 cls: 'roo-password-meter-grey col-xs-12',
21156 //width: this.meterWidth + 'px'
21160 cls: 'roo-password-meter-text'
21166 if (this.hideTrigger) {
21167 this.trigger.setDisplayed(false);
21169 this.setSize(this.width || '', this.height || '');
21172 onDestroy: function ()
21174 if (this.trigger) {
21175 this.trigger.removeAllListeners();
21176 this.trigger.remove();
21179 this.wrap.remove();
21181 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21184 checkStrength: function ()
21186 var pwd = this.inputEl().getValue();
21187 if (pwd == this._lastPwd) {
21192 if (this.ClientSideStrongPassword(pwd)) {
21194 } else if (this.ClientSideMediumPassword(pwd)) {
21196 } else if (this.ClientSideWeakPassword(pwd)) {
21202 Roo.log('strength1: ' + strength);
21204 //var pm = this.trigger.child('div/div/div').dom;
21205 var pm = this.trigger.child('div/div');
21206 pm.removeClass(this.meterClass);
21207 pm.addClass(this.meterClass[strength]);
21210 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21212 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21214 this._lastPwd = pwd;
21218 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21220 this._lastPwd = '';
21222 var pm = this.trigger.child('div/div');
21223 pm.removeClass(this.meterClass);
21224 pm.addClass('roo-password-meter-grey');
21227 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21230 this.inputEl().dom.type='password';
21233 validateValue: function (value)
21236 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21239 if (value.length == 0) {
21240 if (this.allowBlank) {
21241 this.clearInvalid();
21245 this.markInvalid(this.errors.PwdEmpty);
21246 this.errorMsg = this.errors.PwdEmpty;
21254 if ('[\x21-\x7e]*'.match(value)) {
21255 this.markInvalid(this.errors.PwdBadChar);
21256 this.errorMsg = this.errors.PwdBadChar;
21259 if (value.length < 6) {
21260 this.markInvalid(this.errors.PwdShort);
21261 this.errorMsg = this.errors.PwdShort;
21264 if (value.length > 16) {
21265 this.markInvalid(this.errors.PwdLong);
21266 this.errorMsg = this.errors.PwdLong;
21270 if (this.ClientSideStrongPassword(value)) {
21272 } else if (this.ClientSideMediumPassword(value)) {
21274 } else if (this.ClientSideWeakPassword(value)) {
21281 if (strength < 2) {
21282 //this.markInvalid(this.errors.TooWeak);
21283 this.errorMsg = this.errors.TooWeak;
21288 console.log('strength2: ' + strength);
21290 //var pm = this.trigger.child('div/div/div').dom;
21292 var pm = this.trigger.child('div/div');
21293 pm.removeClass(this.meterClass);
21294 pm.addClass(this.meterClass[strength]);
21296 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21298 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21300 this.errorMsg = '';
21304 CharacterSetChecks: function (type)
21307 this.fResult = false;
21310 isctype: function (character, type)
21313 case this.kCapitalLetter:
21314 if (character >= 'A' && character <= 'Z') {
21319 case this.kSmallLetter:
21320 if (character >= 'a' && character <= 'z') {
21326 if (character >= '0' && character <= '9') {
21331 case this.kPunctuation:
21332 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21343 IsLongEnough: function (pwd, size)
21345 return !(pwd == null || isNaN(size) || pwd.length < size);
21348 SpansEnoughCharacterSets: function (word, nb)
21350 if (!this.IsLongEnough(word, nb))
21355 var characterSetChecks = new Array(
21356 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21357 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21360 for (var index = 0; index < word.length; ++index) {
21361 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21362 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21363 characterSetChecks[nCharSet].fResult = true;
21370 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21371 if (characterSetChecks[nCharSet].fResult) {
21376 if (nCharSets < nb) {
21382 ClientSideStrongPassword: function (pwd)
21384 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21387 ClientSideMediumPassword: function (pwd)
21389 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21392 ClientSideWeakPassword: function (pwd)
21394 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21397 })//<script type="text/javascript">
21400 * Based Ext JS Library 1.1.1
21401 * Copyright(c) 2006-2007, Ext JS, LLC.
21407 * @class Roo.HtmlEditorCore
21408 * @extends Roo.Component
21409 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21411 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21414 Roo.HtmlEditorCore = function(config){
21417 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21422 * @event initialize
21423 * Fires when the editor is fully initialized (including the iframe)
21424 * @param {Roo.HtmlEditorCore} this
21429 * Fires when the editor is first receives the focus. Any insertion must wait
21430 * until after this event.
21431 * @param {Roo.HtmlEditorCore} this
21435 * @event beforesync
21436 * Fires before the textarea is updated with content from the editor iframe. Return false
21437 * to cancel the sync.
21438 * @param {Roo.HtmlEditorCore} this
21439 * @param {String} html
21443 * @event beforepush
21444 * Fires before the iframe editor is updated with content from the textarea. Return false
21445 * to cancel the push.
21446 * @param {Roo.HtmlEditorCore} this
21447 * @param {String} html
21452 * Fires when the textarea is updated with content from the editor iframe.
21453 * @param {Roo.HtmlEditorCore} this
21454 * @param {String} html
21459 * Fires when the iframe editor is updated with content from the textarea.
21460 * @param {Roo.HtmlEditorCore} this
21461 * @param {String} html
21466 * @event editorevent
21467 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21468 * @param {Roo.HtmlEditorCore} this
21474 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21476 // defaults : white / black...
21477 this.applyBlacklists();
21484 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21488 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21494 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21499 * @cfg {Number} height (in pixels)
21503 * @cfg {Number} width (in pixels)
21508 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21511 stylesheets: false,
21516 // private properties
21517 validationEvent : false,
21519 initialized : false,
21521 sourceEditMode : false,
21522 onFocus : Roo.emptyFn,
21524 hideMode:'offsets',
21528 // blacklist + whitelisted elements..
21535 * Protected method that will not generally be called directly. It
21536 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21537 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21539 getDocMarkup : function(){
21543 // inherit styels from page...??
21544 if (this.stylesheets === false) {
21546 Roo.get(document.head).select('style').each(function(node) {
21547 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21550 Roo.get(document.head).select('link').each(function(node) {
21551 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21554 } else if (!this.stylesheets.length) {
21556 st = '<style type="text/css">' +
21557 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21560 st = '<style type="text/css">' +
21565 st += '<style type="text/css">' +
21566 'IMG { cursor: pointer } ' +
21569 var cls = 'roo-htmleditor-body';
21571 if(this.bodyCls.length){
21572 cls += ' ' + this.bodyCls;
21575 return '<html><head>' + st +
21576 //<style type="text/css">' +
21577 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21579 ' </head><body class="' + cls + '"></body></html>';
21583 onRender : function(ct, position)
21586 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21587 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21590 this.el.dom.style.border = '0 none';
21591 this.el.dom.setAttribute('tabIndex', -1);
21592 this.el.addClass('x-hidden hide');
21596 if(Roo.isIE){ // fix IE 1px bogus margin
21597 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21601 this.frameId = Roo.id();
21605 var iframe = this.owner.wrap.createChild({
21607 cls: 'form-control', // bootstrap..
21609 name: this.frameId,
21610 frameBorder : 'no',
21611 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21616 this.iframe = iframe.dom;
21618 this.assignDocWin();
21620 this.doc.designMode = 'on';
21623 this.doc.write(this.getDocMarkup());
21627 var task = { // must defer to wait for browser to be ready
21629 //console.log("run task?" + this.doc.readyState);
21630 this.assignDocWin();
21631 if(this.doc.body || this.doc.readyState == 'complete'){
21633 this.doc.designMode="on";
21637 Roo.TaskMgr.stop(task);
21638 this.initEditor.defer(10, this);
21645 Roo.TaskMgr.start(task);
21650 onResize : function(w, h)
21652 Roo.log('resize: ' +w + ',' + h );
21653 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21657 if(typeof w == 'number'){
21659 this.iframe.style.width = w + 'px';
21661 if(typeof h == 'number'){
21663 this.iframe.style.height = h + 'px';
21665 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21672 * Toggles the editor between standard and source edit mode.
21673 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21675 toggleSourceEdit : function(sourceEditMode){
21677 this.sourceEditMode = sourceEditMode === true;
21679 if(this.sourceEditMode){
21681 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21684 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21685 //this.iframe.className = '';
21688 //this.setSize(this.owner.wrap.getSize());
21689 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21696 * Protected method that will not generally be called directly. If you need/want
21697 * custom HTML cleanup, this is the method you should override.
21698 * @param {String} html The HTML to be cleaned
21699 * return {String} The cleaned HTML
21701 cleanHtml : function(html){
21702 html = String(html);
21703 if(html.length > 5){
21704 if(Roo.isSafari){ // strip safari nonsense
21705 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21708 if(html == ' '){
21715 * HTML Editor -> Textarea
21716 * Protected method that will not generally be called directly. Syncs the contents
21717 * of the editor iframe with the textarea.
21719 syncValue : function(){
21720 if(this.initialized){
21721 var bd = (this.doc.body || this.doc.documentElement);
21722 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21723 var html = bd.innerHTML;
21725 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21726 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21728 html = '<div style="'+m[0]+'">' + html + '</div>';
21731 html = this.cleanHtml(html);
21732 // fix up the special chars.. normaly like back quotes in word...
21733 // however we do not want to do this with chinese..
21734 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21735 var cc = b.charCodeAt();
21737 (cc >= 0x4E00 && cc < 0xA000 ) ||
21738 (cc >= 0x3400 && cc < 0x4E00 ) ||
21739 (cc >= 0xf900 && cc < 0xfb00 )
21745 if(this.owner.fireEvent('beforesync', this, html) !== false){
21746 this.el.dom.value = html;
21747 this.owner.fireEvent('sync', this, html);
21753 * Protected method that will not generally be called directly. Pushes the value of the textarea
21754 * into the iframe editor.
21756 pushValue : function(){
21757 if(this.initialized){
21758 var v = this.el.dom.value.trim();
21760 // if(v.length < 1){
21764 if(this.owner.fireEvent('beforepush', this, v) !== false){
21765 var d = (this.doc.body || this.doc.documentElement);
21767 this.cleanUpPaste();
21768 this.el.dom.value = d.innerHTML;
21769 this.owner.fireEvent('push', this, v);
21775 deferFocus : function(){
21776 this.focus.defer(10, this);
21780 focus : function(){
21781 if(this.win && !this.sourceEditMode){
21788 assignDocWin: function()
21790 var iframe = this.iframe;
21793 this.doc = iframe.contentWindow.document;
21794 this.win = iframe.contentWindow;
21796 // if (!Roo.get(this.frameId)) {
21799 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21800 // this.win = Roo.get(this.frameId).dom.contentWindow;
21802 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21806 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21807 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21812 initEditor : function(){
21813 //console.log("INIT EDITOR");
21814 this.assignDocWin();
21818 this.doc.designMode="on";
21820 this.doc.write(this.getDocMarkup());
21823 var dbody = (this.doc.body || this.doc.documentElement);
21824 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21825 // this copies styles from the containing element into thsi one..
21826 // not sure why we need all of this..
21827 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21829 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21830 //ss['background-attachment'] = 'fixed'; // w3c
21831 dbody.bgProperties = 'fixed'; // ie
21832 //Roo.DomHelper.applyStyles(dbody, ss);
21833 Roo.EventManager.on(this.doc, {
21834 //'mousedown': this.onEditorEvent,
21835 'mouseup': this.onEditorEvent,
21836 'dblclick': this.onEditorEvent,
21837 'click': this.onEditorEvent,
21838 'keyup': this.onEditorEvent,
21843 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21845 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21846 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21848 this.initialized = true;
21850 this.owner.fireEvent('initialize', this);
21855 onDestroy : function(){
21861 //for (var i =0; i < this.toolbars.length;i++) {
21862 // // fixme - ask toolbars for heights?
21863 // this.toolbars[i].onDestroy();
21866 //this.wrap.dom.innerHTML = '';
21867 //this.wrap.remove();
21872 onFirstFocus : function(){
21874 this.assignDocWin();
21877 this.activated = true;
21880 if(Roo.isGecko){ // prevent silly gecko errors
21882 var s = this.win.getSelection();
21883 if(!s.focusNode || s.focusNode.nodeType != 3){
21884 var r = s.getRangeAt(0);
21885 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21890 this.execCmd('useCSS', true);
21891 this.execCmd('styleWithCSS', false);
21894 this.owner.fireEvent('activate', this);
21898 adjustFont: function(btn){
21899 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21900 //if(Roo.isSafari){ // safari
21903 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21904 if(Roo.isSafari){ // safari
21905 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21906 v = (v < 10) ? 10 : v;
21907 v = (v > 48) ? 48 : v;
21908 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21913 v = Math.max(1, v+adjust);
21915 this.execCmd('FontSize', v );
21918 onEditorEvent : function(e)
21920 this.owner.fireEvent('editorevent', this, e);
21921 // this.updateToolbar();
21922 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21925 insertTag : function(tg)
21927 // could be a bit smarter... -> wrap the current selected tRoo..
21928 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21930 range = this.createRange(this.getSelection());
21931 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21932 wrappingNode.appendChild(range.extractContents());
21933 range.insertNode(wrappingNode);
21940 this.execCmd("formatblock", tg);
21944 insertText : function(txt)
21948 var range = this.createRange();
21949 range.deleteContents();
21950 //alert(Sender.getAttribute('label'));
21952 range.insertNode(this.doc.createTextNode(txt));
21958 * Executes a Midas editor command on the editor document and performs necessary focus and
21959 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21960 * @param {String} cmd The Midas command
21961 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21963 relayCmd : function(cmd, value){
21965 this.execCmd(cmd, value);
21966 this.owner.fireEvent('editorevent', this);
21967 //this.updateToolbar();
21968 this.owner.deferFocus();
21972 * Executes a Midas editor command directly on the editor document.
21973 * For visual commands, you should use {@link #relayCmd} instead.
21974 * <b>This should only be called after the editor is initialized.</b>
21975 * @param {String} cmd The Midas command
21976 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21978 execCmd : function(cmd, value){
21979 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21986 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21988 * @param {String} text | dom node..
21990 insertAtCursor : function(text)
21993 if(!this.activated){
21999 var r = this.doc.selection.createRange();
22010 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22014 // from jquery ui (MIT licenced)
22016 var win = this.win;
22018 if (win.getSelection && win.getSelection().getRangeAt) {
22019 range = win.getSelection().getRangeAt(0);
22020 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22021 range.insertNode(node);
22022 } else if (win.document.selection && win.document.selection.createRange) {
22023 // no firefox support
22024 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22025 win.document.selection.createRange().pasteHTML(txt);
22027 // no firefox support
22028 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22029 this.execCmd('InsertHTML', txt);
22038 mozKeyPress : function(e){
22040 var c = e.getCharCode(), cmd;
22043 c = String.fromCharCode(c).toLowerCase();
22057 this.cleanUpPaste.defer(100, this);
22065 e.preventDefault();
22073 fixKeys : function(){ // load time branching for fastest keydown performance
22075 return function(e){
22076 var k = e.getKey(), r;
22079 r = this.doc.selection.createRange();
22082 r.pasteHTML('    ');
22089 r = this.doc.selection.createRange();
22091 var target = r.parentElement();
22092 if(!target || target.tagName.toLowerCase() != 'li'){
22094 r.pasteHTML('<br />');
22100 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22101 this.cleanUpPaste.defer(100, this);
22107 }else if(Roo.isOpera){
22108 return function(e){
22109 var k = e.getKey();
22113 this.execCmd('InsertHTML','    ');
22116 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22117 this.cleanUpPaste.defer(100, this);
22122 }else if(Roo.isSafari){
22123 return function(e){
22124 var k = e.getKey();
22128 this.execCmd('InsertText','\t');
22132 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22133 this.cleanUpPaste.defer(100, this);
22141 getAllAncestors: function()
22143 var p = this.getSelectedNode();
22146 a.push(p); // push blank onto stack..
22147 p = this.getParentElement();
22151 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22155 a.push(this.doc.body);
22159 lastSelNode : false,
22162 getSelection : function()
22164 this.assignDocWin();
22165 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22168 getSelectedNode: function()
22170 // this may only work on Gecko!!!
22172 // should we cache this!!!!
22177 var range = this.createRange(this.getSelection()).cloneRange();
22180 var parent = range.parentElement();
22182 var testRange = range.duplicate();
22183 testRange.moveToElementText(parent);
22184 if (testRange.inRange(range)) {
22187 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22190 parent = parent.parentElement;
22195 // is ancestor a text element.
22196 var ac = range.commonAncestorContainer;
22197 if (ac.nodeType == 3) {
22198 ac = ac.parentNode;
22201 var ar = ac.childNodes;
22204 var other_nodes = [];
22205 var has_other_nodes = false;
22206 for (var i=0;i<ar.length;i++) {
22207 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22210 // fullly contained node.
22212 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22217 // probably selected..
22218 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22219 other_nodes.push(ar[i]);
22223 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22228 has_other_nodes = true;
22230 if (!nodes.length && other_nodes.length) {
22231 nodes= other_nodes;
22233 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22239 createRange: function(sel)
22241 // this has strange effects when using with
22242 // top toolbar - not sure if it's a great idea.
22243 //this.editor.contentWindow.focus();
22244 if (typeof sel != "undefined") {
22246 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22248 return this.doc.createRange();
22251 return this.doc.createRange();
22254 getParentElement: function()
22257 this.assignDocWin();
22258 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22260 var range = this.createRange(sel);
22263 var p = range.commonAncestorContainer;
22264 while (p.nodeType == 3) { // text node
22275 * Range intersection.. the hard stuff...
22279 * [ -- selected range --- ]
22283 * if end is before start or hits it. fail.
22284 * if start is after end or hits it fail.
22286 * if either hits (but other is outside. - then it's not
22292 // @see http://www.thismuchiknow.co.uk/?p=64.
22293 rangeIntersectsNode : function(range, node)
22295 var nodeRange = node.ownerDocument.createRange();
22297 nodeRange.selectNode(node);
22299 nodeRange.selectNodeContents(node);
22302 var rangeStartRange = range.cloneRange();
22303 rangeStartRange.collapse(true);
22305 var rangeEndRange = range.cloneRange();
22306 rangeEndRange.collapse(false);
22308 var nodeStartRange = nodeRange.cloneRange();
22309 nodeStartRange.collapse(true);
22311 var nodeEndRange = nodeRange.cloneRange();
22312 nodeEndRange.collapse(false);
22314 return rangeStartRange.compareBoundaryPoints(
22315 Range.START_TO_START, nodeEndRange) == -1 &&
22316 rangeEndRange.compareBoundaryPoints(
22317 Range.START_TO_START, nodeStartRange) == 1;
22321 rangeCompareNode : function(range, node)
22323 var nodeRange = node.ownerDocument.createRange();
22325 nodeRange.selectNode(node);
22327 nodeRange.selectNodeContents(node);
22331 range.collapse(true);
22333 nodeRange.collapse(true);
22335 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22336 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22338 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22340 var nodeIsBefore = ss == 1;
22341 var nodeIsAfter = ee == -1;
22343 if (nodeIsBefore && nodeIsAfter) {
22346 if (!nodeIsBefore && nodeIsAfter) {
22347 return 1; //right trailed.
22350 if (nodeIsBefore && !nodeIsAfter) {
22351 return 2; // left trailed.
22357 // private? - in a new class?
22358 cleanUpPaste : function()
22360 // cleans up the whole document..
22361 Roo.log('cleanuppaste');
22363 this.cleanUpChildren(this.doc.body);
22364 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22365 if (clean != this.doc.body.innerHTML) {
22366 this.doc.body.innerHTML = clean;
22371 cleanWordChars : function(input) {// change the chars to hex code
22372 var he = Roo.HtmlEditorCore;
22374 var output = input;
22375 Roo.each(he.swapCodes, function(sw) {
22376 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22378 output = output.replace(swapper, sw[1]);
22385 cleanUpChildren : function (n)
22387 if (!n.childNodes.length) {
22390 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22391 this.cleanUpChild(n.childNodes[i]);
22398 cleanUpChild : function (node)
22401 //console.log(node);
22402 if (node.nodeName == "#text") {
22403 // clean up silly Windows -- stuff?
22406 if (node.nodeName == "#comment") {
22407 node.parentNode.removeChild(node);
22408 // clean up silly Windows -- stuff?
22411 var lcname = node.tagName.toLowerCase();
22412 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22413 // whitelist of tags..
22415 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22417 node.parentNode.removeChild(node);
22422 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22424 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22425 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22427 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22428 // remove_keep_children = true;
22431 if (remove_keep_children) {
22432 this.cleanUpChildren(node);
22433 // inserts everything just before this node...
22434 while (node.childNodes.length) {
22435 var cn = node.childNodes[0];
22436 node.removeChild(cn);
22437 node.parentNode.insertBefore(cn, node);
22439 node.parentNode.removeChild(node);
22443 if (!node.attributes || !node.attributes.length) {
22444 this.cleanUpChildren(node);
22448 function cleanAttr(n,v)
22451 if (v.match(/^\./) || v.match(/^\//)) {
22454 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22457 if (v.match(/^#/)) {
22460 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22461 node.removeAttribute(n);
22465 var cwhite = this.cwhite;
22466 var cblack = this.cblack;
22468 function cleanStyle(n,v)
22470 if (v.match(/expression/)) { //XSS?? should we even bother..
22471 node.removeAttribute(n);
22475 var parts = v.split(/;/);
22478 Roo.each(parts, function(p) {
22479 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22483 var l = p.split(':').shift().replace(/\s+/g,'');
22484 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22486 if ( cwhite.length && cblack.indexOf(l) > -1) {
22487 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22488 //node.removeAttribute(n);
22492 // only allow 'c whitelisted system attributes'
22493 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22494 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22495 //node.removeAttribute(n);
22505 if (clean.length) {
22506 node.setAttribute(n, clean.join(';'));
22508 node.removeAttribute(n);
22514 for (var i = node.attributes.length-1; i > -1 ; i--) {
22515 var a = node.attributes[i];
22518 if (a.name.toLowerCase().substr(0,2)=='on') {
22519 node.removeAttribute(a.name);
22522 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22523 node.removeAttribute(a.name);
22526 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22527 cleanAttr(a.name,a.value); // fixme..
22530 if (a.name == 'style') {
22531 cleanStyle(a.name,a.value);
22534 /// clean up MS crap..
22535 // tecnically this should be a list of valid class'es..
22538 if (a.name == 'class') {
22539 if (a.value.match(/^Mso/)) {
22540 node.className = '';
22543 if (a.value.match(/^body$/)) {
22544 node.className = '';
22555 this.cleanUpChildren(node);
22561 * Clean up MS wordisms...
22563 cleanWord : function(node)
22568 this.cleanWord(this.doc.body);
22571 if (node.nodeName == "#text") {
22572 // clean up silly Windows -- stuff?
22575 if (node.nodeName == "#comment") {
22576 node.parentNode.removeChild(node);
22577 // clean up silly Windows -- stuff?
22581 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22582 node.parentNode.removeChild(node);
22586 // remove - but keep children..
22587 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22588 while (node.childNodes.length) {
22589 var cn = node.childNodes[0];
22590 node.removeChild(cn);
22591 node.parentNode.insertBefore(cn, node);
22593 node.parentNode.removeChild(node);
22594 this.iterateChildren(node, this.cleanWord);
22598 if (node.className.length) {
22600 var cn = node.className.split(/\W+/);
22602 Roo.each(cn, function(cls) {
22603 if (cls.match(/Mso[a-zA-Z]+/)) {
22608 node.className = cna.length ? cna.join(' ') : '';
22610 node.removeAttribute("class");
22614 if (node.hasAttribute("lang")) {
22615 node.removeAttribute("lang");
22618 if (node.hasAttribute("style")) {
22620 var styles = node.getAttribute("style").split(";");
22622 Roo.each(styles, function(s) {
22623 if (!s.match(/:/)) {
22626 var kv = s.split(":");
22627 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22630 // what ever is left... we allow.
22633 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22634 if (!nstyle.length) {
22635 node.removeAttribute('style');
22638 this.iterateChildren(node, this.cleanWord);
22644 * iterateChildren of a Node, calling fn each time, using this as the scole..
22645 * @param {DomNode} node node to iterate children of.
22646 * @param {Function} fn method of this class to call on each item.
22648 iterateChildren : function(node, fn)
22650 if (!node.childNodes.length) {
22653 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22654 fn.call(this, node.childNodes[i])
22660 * cleanTableWidths.
22662 * Quite often pasting from word etc.. results in tables with column and widths.
22663 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22666 cleanTableWidths : function(node)
22671 this.cleanTableWidths(this.doc.body);
22676 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22679 Roo.log(node.tagName);
22680 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22681 this.iterateChildren(node, this.cleanTableWidths);
22684 if (node.hasAttribute('width')) {
22685 node.removeAttribute('width');
22689 if (node.hasAttribute("style")) {
22692 var styles = node.getAttribute("style").split(";");
22694 Roo.each(styles, function(s) {
22695 if (!s.match(/:/)) {
22698 var kv = s.split(":");
22699 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22702 // what ever is left... we allow.
22705 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22706 if (!nstyle.length) {
22707 node.removeAttribute('style');
22711 this.iterateChildren(node, this.cleanTableWidths);
22719 domToHTML : function(currentElement, depth, nopadtext) {
22721 depth = depth || 0;
22722 nopadtext = nopadtext || false;
22724 if (!currentElement) {
22725 return this.domToHTML(this.doc.body);
22728 //Roo.log(currentElement);
22730 var allText = false;
22731 var nodeName = currentElement.nodeName;
22732 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22734 if (nodeName == '#text') {
22736 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22741 if (nodeName != 'BODY') {
22744 // Prints the node tagName, such as <A>, <IMG>, etc
22747 for(i = 0; i < currentElement.attributes.length;i++) {
22749 var aname = currentElement.attributes.item(i).name;
22750 if (!currentElement.attributes.item(i).value.length) {
22753 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22756 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22765 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22768 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22773 // Traverse the tree
22775 var currentElementChild = currentElement.childNodes.item(i);
22776 var allText = true;
22777 var innerHTML = '';
22779 while (currentElementChild) {
22780 // Formatting code (indent the tree so it looks nice on the screen)
22781 var nopad = nopadtext;
22782 if (lastnode == 'SPAN') {
22786 if (currentElementChild.nodeName == '#text') {
22787 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22788 toadd = nopadtext ? toadd : toadd.trim();
22789 if (!nopad && toadd.length > 80) {
22790 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22792 innerHTML += toadd;
22795 currentElementChild = currentElement.childNodes.item(i);
22801 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22803 // Recursively traverse the tree structure of the child node
22804 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22805 lastnode = currentElementChild.nodeName;
22807 currentElementChild=currentElement.childNodes.item(i);
22813 // The remaining code is mostly for formatting the tree
22814 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22819 ret+= "</"+tagName+">";
22825 applyBlacklists : function()
22827 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22828 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22832 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22833 if (b.indexOf(tag) > -1) {
22836 this.white.push(tag);
22840 Roo.each(w, function(tag) {
22841 if (b.indexOf(tag) > -1) {
22844 if (this.white.indexOf(tag) > -1) {
22847 this.white.push(tag);
22852 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22853 if (w.indexOf(tag) > -1) {
22856 this.black.push(tag);
22860 Roo.each(b, function(tag) {
22861 if (w.indexOf(tag) > -1) {
22864 if (this.black.indexOf(tag) > -1) {
22867 this.black.push(tag);
22872 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22873 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22877 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22878 if (b.indexOf(tag) > -1) {
22881 this.cwhite.push(tag);
22885 Roo.each(w, function(tag) {
22886 if (b.indexOf(tag) > -1) {
22889 if (this.cwhite.indexOf(tag) > -1) {
22892 this.cwhite.push(tag);
22897 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22898 if (w.indexOf(tag) > -1) {
22901 this.cblack.push(tag);
22905 Roo.each(b, function(tag) {
22906 if (w.indexOf(tag) > -1) {
22909 if (this.cblack.indexOf(tag) > -1) {
22912 this.cblack.push(tag);
22917 setStylesheets : function(stylesheets)
22919 if(typeof(stylesheets) == 'string'){
22920 Roo.get(this.iframe.contentDocument.head).createChild({
22922 rel : 'stylesheet',
22931 Roo.each(stylesheets, function(s) {
22936 Roo.get(_this.iframe.contentDocument.head).createChild({
22938 rel : 'stylesheet',
22947 removeStylesheets : function()
22951 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22956 setStyle : function(style)
22958 Roo.get(this.iframe.contentDocument.head).createChild({
22967 // hide stuff that is not compatible
22981 * @event specialkey
22985 * @cfg {String} fieldClass @hide
22988 * @cfg {String} focusClass @hide
22991 * @cfg {String} autoCreate @hide
22994 * @cfg {String} inputType @hide
22997 * @cfg {String} invalidClass @hide
23000 * @cfg {String} invalidText @hide
23003 * @cfg {String} msgFx @hide
23006 * @cfg {String} validateOnBlur @hide
23010 Roo.HtmlEditorCore.white = [
23011 'area', 'br', 'img', 'input', 'hr', 'wbr',
23013 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23014 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23015 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23016 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23017 'table', 'ul', 'xmp',
23019 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23022 'dir', 'menu', 'ol', 'ul', 'dl',
23028 Roo.HtmlEditorCore.black = [
23029 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23031 'base', 'basefont', 'bgsound', 'blink', 'body',
23032 'frame', 'frameset', 'head', 'html', 'ilayer',
23033 'iframe', 'layer', 'link', 'meta', 'object',
23034 'script', 'style' ,'title', 'xml' // clean later..
23036 Roo.HtmlEditorCore.clean = [
23037 'script', 'style', 'title', 'xml'
23039 Roo.HtmlEditorCore.remove = [
23044 Roo.HtmlEditorCore.ablack = [
23048 Roo.HtmlEditorCore.aclean = [
23049 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23053 Roo.HtmlEditorCore.pwhite= [
23054 'http', 'https', 'mailto'
23057 // white listed style attributes.
23058 Roo.HtmlEditorCore.cwhite= [
23059 // 'text-align', /// default is to allow most things..
23065 // black listed style attributes.
23066 Roo.HtmlEditorCore.cblack= [
23067 // 'font-size' -- this can be set by the project
23071 Roo.HtmlEditorCore.swapCodes =[
23090 * @class Roo.bootstrap.HtmlEditor
23091 * @extends Roo.bootstrap.TextArea
23092 * Bootstrap HtmlEditor class
23095 * Create a new HtmlEditor
23096 * @param {Object} config The config object
23099 Roo.bootstrap.HtmlEditor = function(config){
23100 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23101 if (!this.toolbars) {
23102 this.toolbars = [];
23105 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23108 * @event initialize
23109 * Fires when the editor is fully initialized (including the iframe)
23110 * @param {HtmlEditor} this
23115 * Fires when the editor is first receives the focus. Any insertion must wait
23116 * until after this event.
23117 * @param {HtmlEditor} this
23121 * @event beforesync
23122 * Fires before the textarea is updated with content from the editor iframe. Return false
23123 * to cancel the sync.
23124 * @param {HtmlEditor} this
23125 * @param {String} html
23129 * @event beforepush
23130 * Fires before the iframe editor is updated with content from the textarea. Return false
23131 * to cancel the push.
23132 * @param {HtmlEditor} this
23133 * @param {String} html
23138 * Fires when the textarea is updated with content from the editor iframe.
23139 * @param {HtmlEditor} this
23140 * @param {String} html
23145 * Fires when the iframe editor is updated with content from the textarea.
23146 * @param {HtmlEditor} this
23147 * @param {String} html
23151 * @event editmodechange
23152 * Fires when the editor switches edit modes
23153 * @param {HtmlEditor} this
23154 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23156 editmodechange: true,
23158 * @event editorevent
23159 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23160 * @param {HtmlEditor} this
23164 * @event firstfocus
23165 * Fires when on first focus - needed by toolbars..
23166 * @param {HtmlEditor} this
23171 * Auto save the htmlEditor value as a file into Events
23172 * @param {HtmlEditor} this
23176 * @event savedpreview
23177 * preview the saved version of htmlEditor
23178 * @param {HtmlEditor} this
23185 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23189 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23194 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23199 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23204 * @cfg {Number} height (in pixels)
23208 * @cfg {Number} width (in pixels)
23213 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23216 stylesheets: false,
23221 // private properties
23222 validationEvent : false,
23224 initialized : false,
23227 onFocus : Roo.emptyFn,
23229 hideMode:'offsets',
23231 tbContainer : false,
23235 toolbarContainer :function() {
23236 return this.wrap.select('.x-html-editor-tb',true).first();
23240 * Protected method that will not generally be called directly. It
23241 * is called when the editor creates its toolbar. Override this method if you need to
23242 * add custom toolbar buttons.
23243 * @param {HtmlEditor} editor
23245 createToolbar : function(){
23246 Roo.log('renewing');
23247 Roo.log("create toolbars");
23249 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23250 this.toolbars[0].render(this.toolbarContainer());
23254 // if (!editor.toolbars || !editor.toolbars.length) {
23255 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23258 // for (var i =0 ; i < editor.toolbars.length;i++) {
23259 // editor.toolbars[i] = Roo.factory(
23260 // typeof(editor.toolbars[i]) == 'string' ?
23261 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23262 // Roo.bootstrap.HtmlEditor);
23263 // editor.toolbars[i].init(editor);
23269 onRender : function(ct, position)
23271 // Roo.log("Call onRender: " + this.xtype);
23273 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23275 this.wrap = this.inputEl().wrap({
23276 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23279 this.editorcore.onRender(ct, position);
23281 if (this.resizable) {
23282 this.resizeEl = new Roo.Resizable(this.wrap, {
23286 minHeight : this.height,
23287 height: this.height,
23288 handles : this.resizable,
23291 resize : function(r, w, h) {
23292 _t.onResize(w,h); // -something
23298 this.createToolbar(this);
23301 if(!this.width && this.resizable){
23302 this.setSize(this.wrap.getSize());
23304 if (this.resizeEl) {
23305 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23306 // should trigger onReize..
23312 onResize : function(w, h)
23314 Roo.log('resize: ' +w + ',' + h );
23315 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23319 if(this.inputEl() ){
23320 if(typeof w == 'number'){
23321 var aw = w - this.wrap.getFrameWidth('lr');
23322 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23325 if(typeof h == 'number'){
23326 var tbh = -11; // fixme it needs to tool bar size!
23327 for (var i =0; i < this.toolbars.length;i++) {
23328 // fixme - ask toolbars for heights?
23329 tbh += this.toolbars[i].el.getHeight();
23330 //if (this.toolbars[i].footer) {
23331 // tbh += this.toolbars[i].footer.el.getHeight();
23339 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23340 ah -= 5; // knock a few pixes off for look..
23341 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23345 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23346 this.editorcore.onResize(ew,eh);
23351 * Toggles the editor between standard and source edit mode.
23352 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23354 toggleSourceEdit : function(sourceEditMode)
23356 this.editorcore.toggleSourceEdit(sourceEditMode);
23358 if(this.editorcore.sourceEditMode){
23359 Roo.log('editor - showing textarea');
23362 // Roo.log(this.syncValue());
23364 this.inputEl().removeClass(['hide', 'x-hidden']);
23365 this.inputEl().dom.removeAttribute('tabIndex');
23366 this.inputEl().focus();
23368 Roo.log('editor - hiding textarea');
23370 // Roo.log(this.pushValue());
23373 this.inputEl().addClass(['hide', 'x-hidden']);
23374 this.inputEl().dom.setAttribute('tabIndex', -1);
23375 //this.deferFocus();
23378 if(this.resizable){
23379 this.setSize(this.wrap.getSize());
23382 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23385 // private (for BoxComponent)
23386 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23388 // private (for BoxComponent)
23389 getResizeEl : function(){
23393 // private (for BoxComponent)
23394 getPositionEl : function(){
23399 initEvents : function(){
23400 this.originalValue = this.getValue();
23404 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23407 // markInvalid : Roo.emptyFn,
23409 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23412 // clearInvalid : Roo.emptyFn,
23414 setValue : function(v){
23415 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23416 this.editorcore.pushValue();
23421 deferFocus : function(){
23422 this.focus.defer(10, this);
23426 focus : function(){
23427 this.editorcore.focus();
23433 onDestroy : function(){
23439 for (var i =0; i < this.toolbars.length;i++) {
23440 // fixme - ask toolbars for heights?
23441 this.toolbars[i].onDestroy();
23444 this.wrap.dom.innerHTML = '';
23445 this.wrap.remove();
23450 onFirstFocus : function(){
23451 //Roo.log("onFirstFocus");
23452 this.editorcore.onFirstFocus();
23453 for (var i =0; i < this.toolbars.length;i++) {
23454 this.toolbars[i].onFirstFocus();
23460 syncValue : function()
23462 this.editorcore.syncValue();
23465 pushValue : function()
23467 this.editorcore.pushValue();
23471 // hide stuff that is not compatible
23485 * @event specialkey
23489 * @cfg {String} fieldClass @hide
23492 * @cfg {String} focusClass @hide
23495 * @cfg {String} autoCreate @hide
23498 * @cfg {String} inputType @hide
23501 * @cfg {String} invalidClass @hide
23504 * @cfg {String} invalidText @hide
23507 * @cfg {String} msgFx @hide
23510 * @cfg {String} validateOnBlur @hide
23519 Roo.namespace('Roo.bootstrap.htmleditor');
23521 * @class Roo.bootstrap.HtmlEditorToolbar1
23526 new Roo.bootstrap.HtmlEditor({
23529 new Roo.bootstrap.HtmlEditorToolbar1({
23530 disable : { fonts: 1 , format: 1, ..., ... , ...],
23536 * @cfg {Object} disable List of elements to disable..
23537 * @cfg {Array} btns List of additional buttons.
23541 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23544 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23547 Roo.apply(this, config);
23549 // default disabled, based on 'good practice'..
23550 this.disable = this.disable || {};
23551 Roo.applyIf(this.disable, {
23554 specialElements : true
23556 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23558 this.editor = config.editor;
23559 this.editorcore = config.editor.editorcore;
23561 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23563 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23564 // dont call parent... till later.
23566 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23571 editorcore : false,
23576 "h1","h2","h3","h4","h5","h6",
23578 "abbr", "acronym", "address", "cite", "samp", "var",
23582 onRender : function(ct, position)
23584 // Roo.log("Call onRender: " + this.xtype);
23586 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23588 this.el.dom.style.marginBottom = '0';
23590 var editorcore = this.editorcore;
23591 var editor= this.editor;
23594 var btn = function(id,cmd , toggle, handler, html){
23596 var event = toggle ? 'toggle' : 'click';
23601 xns: Roo.bootstrap,
23604 enableToggle:toggle !== false,
23606 pressed : toggle ? false : null,
23609 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23610 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23616 // var cb_box = function...
23621 xns: Roo.bootstrap,
23622 glyphicon : 'font',
23626 xns: Roo.bootstrap,
23630 Roo.each(this.formats, function(f) {
23631 style.menu.items.push({
23633 xns: Roo.bootstrap,
23634 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23639 editorcore.insertTag(this.tagname);
23646 children.push(style);
23648 btn('bold',false,true);
23649 btn('italic',false,true);
23650 btn('align-left', 'justifyleft',true);
23651 btn('align-center', 'justifycenter',true);
23652 btn('align-right' , 'justifyright',true);
23653 btn('link', false, false, function(btn) {
23654 //Roo.log("create link?");
23655 var url = prompt(this.createLinkText, this.defaultLinkValue);
23656 if(url && url != 'http:/'+'/'){
23657 this.editorcore.relayCmd('createlink', url);
23660 btn('list','insertunorderedlist',true);
23661 btn('pencil', false,true, function(btn){
23663 this.toggleSourceEdit(btn.pressed);
23666 if (this.editor.btns.length > 0) {
23667 for (var i = 0; i<this.editor.btns.length; i++) {
23668 children.push(this.editor.btns[i]);
23676 xns: Roo.bootstrap,
23681 xns: Roo.bootstrap,
23686 cog.menu.items.push({
23688 xns: Roo.bootstrap,
23689 html : Clean styles,
23694 editorcore.insertTag(this.tagname);
23703 this.xtype = 'NavSimplebar';
23705 for(var i=0;i< children.length;i++) {
23707 this.buttons.add(this.addxtypeChild(children[i]));
23711 editor.on('editorevent', this.updateToolbar, this);
23713 onBtnClick : function(id)
23715 this.editorcore.relayCmd(id);
23716 this.editorcore.focus();
23720 * Protected method that will not generally be called directly. It triggers
23721 * a toolbar update by reading the markup state of the current selection in the editor.
23723 updateToolbar: function(){
23725 if(!this.editorcore.activated){
23726 this.editor.onFirstFocus(); // is this neeed?
23730 var btns = this.buttons;
23731 var doc = this.editorcore.doc;
23732 btns.get('bold').setActive(doc.queryCommandState('bold'));
23733 btns.get('italic').setActive(doc.queryCommandState('italic'));
23734 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23736 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23737 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23738 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23740 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23741 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23744 var ans = this.editorcore.getAllAncestors();
23745 if (this.formatCombo) {
23748 var store = this.formatCombo.store;
23749 this.formatCombo.setValue("");
23750 for (var i =0; i < ans.length;i++) {
23751 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23753 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23761 // hides menus... - so this cant be on a menu...
23762 Roo.bootstrap.MenuMgr.hideAll();
23764 Roo.bootstrap.MenuMgr.hideAll();
23765 //this.editorsyncValue();
23767 onFirstFocus: function() {
23768 this.buttons.each(function(item){
23772 toggleSourceEdit : function(sourceEditMode){
23775 if(sourceEditMode){
23776 Roo.log("disabling buttons");
23777 this.buttons.each( function(item){
23778 if(item.cmd != 'pencil'){
23784 Roo.log("enabling buttons");
23785 if(this.editorcore.initialized){
23786 this.buttons.each( function(item){
23792 Roo.log("calling toggole on editor");
23793 // tell the editor that it's been pressed..
23794 this.editor.toggleSourceEdit(sourceEditMode);
23804 * @class Roo.bootstrap.Table.AbstractSelectionModel
23805 * @extends Roo.util.Observable
23806 * Abstract base class for grid SelectionModels. It provides the interface that should be
23807 * implemented by descendant classes. This class should not be directly instantiated.
23810 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23811 this.locked = false;
23812 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23816 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23817 /** @ignore Called by the grid automatically. Do not call directly. */
23818 init : function(grid){
23824 * Locks the selections.
23827 this.locked = true;
23831 * Unlocks the selections.
23833 unlock : function(){
23834 this.locked = false;
23838 * Returns true if the selections are locked.
23839 * @return {Boolean}
23841 isLocked : function(){
23842 return this.locked;
23846 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23847 * @class Roo.bootstrap.Table.RowSelectionModel
23848 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23849 * It supports multiple selections and keyboard selection/navigation.
23851 * @param {Object} config
23854 Roo.bootstrap.Table.RowSelectionModel = function(config){
23855 Roo.apply(this, config);
23856 this.selections = new Roo.util.MixedCollection(false, function(o){
23861 this.lastActive = false;
23865 * @event selectionchange
23866 * Fires when the selection changes
23867 * @param {SelectionModel} this
23869 "selectionchange" : true,
23871 * @event afterselectionchange
23872 * Fires after the selection changes (eg. by key press or clicking)
23873 * @param {SelectionModel} this
23875 "afterselectionchange" : true,
23877 * @event beforerowselect
23878 * Fires when a row is selected being selected, return false to cancel.
23879 * @param {SelectionModel} this
23880 * @param {Number} rowIndex The selected index
23881 * @param {Boolean} keepExisting False if other selections will be cleared
23883 "beforerowselect" : true,
23886 * Fires when a row is selected.
23887 * @param {SelectionModel} this
23888 * @param {Number} rowIndex The selected index
23889 * @param {Roo.data.Record} r The record
23891 "rowselect" : true,
23893 * @event rowdeselect
23894 * Fires when a row is deselected.
23895 * @param {SelectionModel} this
23896 * @param {Number} rowIndex The selected index
23898 "rowdeselect" : true
23900 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23901 this.locked = false;
23904 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23906 * @cfg {Boolean} singleSelect
23907 * True to allow selection of only one row at a time (defaults to false)
23909 singleSelect : false,
23912 initEvents : function()
23915 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23916 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23917 //}else{ // allow click to work like normal
23918 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23920 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23921 this.grid.on("rowclick", this.handleMouseDown, this);
23923 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23924 "up" : function(e){
23926 this.selectPrevious(e.shiftKey);
23927 }else if(this.last !== false && this.lastActive !== false){
23928 var last = this.last;
23929 this.selectRange(this.last, this.lastActive-1);
23930 this.grid.getView().focusRow(this.lastActive);
23931 if(last !== false){
23935 this.selectFirstRow();
23937 this.fireEvent("afterselectionchange", this);
23939 "down" : function(e){
23941 this.selectNext(e.shiftKey);
23942 }else if(this.last !== false && this.lastActive !== false){
23943 var last = this.last;
23944 this.selectRange(this.last, this.lastActive+1);
23945 this.grid.getView().focusRow(this.lastActive);
23946 if(last !== false){
23950 this.selectFirstRow();
23952 this.fireEvent("afterselectionchange", this);
23956 this.grid.store.on('load', function(){
23957 this.selections.clear();
23960 var view = this.grid.view;
23961 view.on("refresh", this.onRefresh, this);
23962 view.on("rowupdated", this.onRowUpdated, this);
23963 view.on("rowremoved", this.onRemove, this);
23968 onRefresh : function()
23970 var ds = this.grid.store, i, v = this.grid.view;
23971 var s = this.selections;
23972 s.each(function(r){
23973 if((i = ds.indexOfId(r.id)) != -1){
23982 onRemove : function(v, index, r){
23983 this.selections.remove(r);
23987 onRowUpdated : function(v, index, r){
23988 if(this.isSelected(r)){
23989 v.onRowSelect(index);
23995 * @param {Array} records The records to select
23996 * @param {Boolean} keepExisting (optional) True to keep existing selections
23998 selectRecords : function(records, keepExisting)
24001 this.clearSelections();
24003 var ds = this.grid.store;
24004 for(var i = 0, len = records.length; i < len; i++){
24005 this.selectRow(ds.indexOf(records[i]), true);
24010 * Gets the number of selected rows.
24013 getCount : function(){
24014 return this.selections.length;
24018 * Selects the first row in the grid.
24020 selectFirstRow : function(){
24025 * Select the last row.
24026 * @param {Boolean} keepExisting (optional) True to keep existing selections
24028 selectLastRow : function(keepExisting){
24029 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24030 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24034 * Selects the row immediately following the last selected row.
24035 * @param {Boolean} keepExisting (optional) True to keep existing selections
24037 selectNext : function(keepExisting)
24039 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24040 this.selectRow(this.last+1, keepExisting);
24041 this.grid.getView().focusRow(this.last);
24046 * Selects the row that precedes the last selected row.
24047 * @param {Boolean} keepExisting (optional) True to keep existing selections
24049 selectPrevious : function(keepExisting){
24051 this.selectRow(this.last-1, keepExisting);
24052 this.grid.getView().focusRow(this.last);
24057 * Returns the selected records
24058 * @return {Array} Array of selected records
24060 getSelections : function(){
24061 return [].concat(this.selections.items);
24065 * Returns the first selected record.
24068 getSelected : function(){
24069 return this.selections.itemAt(0);
24074 * Clears all selections.
24076 clearSelections : function(fast)
24082 var ds = this.grid.store;
24083 var s = this.selections;
24084 s.each(function(r){
24085 this.deselectRow(ds.indexOfId(r.id));
24089 this.selections.clear();
24096 * Selects all rows.
24098 selectAll : function(){
24102 this.selections.clear();
24103 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24104 this.selectRow(i, true);
24109 * Returns True if there is a selection.
24110 * @return {Boolean}
24112 hasSelection : function(){
24113 return this.selections.length > 0;
24117 * Returns True if the specified row is selected.
24118 * @param {Number/Record} record The record or index of the record to check
24119 * @return {Boolean}
24121 isSelected : function(index){
24122 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24123 return (r && this.selections.key(r.id) ? true : false);
24127 * Returns True if the specified record id is selected.
24128 * @param {String} id The id of record to check
24129 * @return {Boolean}
24131 isIdSelected : function(id){
24132 return (this.selections.key(id) ? true : false);
24137 handleMouseDBClick : function(e, t){
24141 handleMouseDown : function(e, t)
24143 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24144 if(this.isLocked() || rowIndex < 0 ){
24147 if(e.shiftKey && this.last !== false){
24148 var last = this.last;
24149 this.selectRange(last, rowIndex, e.ctrlKey);
24150 this.last = last; // reset the last
24154 var isSelected = this.isSelected(rowIndex);
24155 //Roo.log("select row:" + rowIndex);
24157 this.deselectRow(rowIndex);
24159 this.selectRow(rowIndex, true);
24163 if(e.button !== 0 && isSelected){
24164 alert('rowIndex 2: ' + rowIndex);
24165 view.focusRow(rowIndex);
24166 }else if(e.ctrlKey && isSelected){
24167 this.deselectRow(rowIndex);
24168 }else if(!isSelected){
24169 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24170 view.focusRow(rowIndex);
24174 this.fireEvent("afterselectionchange", this);
24177 handleDragableRowClick : function(grid, rowIndex, e)
24179 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24180 this.selectRow(rowIndex, false);
24181 grid.view.focusRow(rowIndex);
24182 this.fireEvent("afterselectionchange", this);
24187 * Selects multiple rows.
24188 * @param {Array} rows Array of the indexes of the row to select
24189 * @param {Boolean} keepExisting (optional) True to keep existing selections
24191 selectRows : function(rows, keepExisting){
24193 this.clearSelections();
24195 for(var i = 0, len = rows.length; i < len; i++){
24196 this.selectRow(rows[i], true);
24201 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24202 * @param {Number} startRow The index of the first row in the range
24203 * @param {Number} endRow The index of the last row in the range
24204 * @param {Boolean} keepExisting (optional) True to retain existing selections
24206 selectRange : function(startRow, endRow, keepExisting){
24211 this.clearSelections();
24213 if(startRow <= endRow){
24214 for(var i = startRow; i <= endRow; i++){
24215 this.selectRow(i, true);
24218 for(var i = startRow; i >= endRow; i--){
24219 this.selectRow(i, true);
24225 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24226 * @param {Number} startRow The index of the first row in the range
24227 * @param {Number} endRow The index of the last row in the range
24229 deselectRange : function(startRow, endRow, preventViewNotify){
24233 for(var i = startRow; i <= endRow; i++){
24234 this.deselectRow(i, preventViewNotify);
24240 * @param {Number} row The index of the row to select
24241 * @param {Boolean} keepExisting (optional) True to keep existing selections
24243 selectRow : function(index, keepExisting, preventViewNotify)
24245 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24248 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24249 if(!keepExisting || this.singleSelect){
24250 this.clearSelections();
24253 var r = this.grid.store.getAt(index);
24254 //console.log('selectRow - record id :' + r.id);
24256 this.selections.add(r);
24257 this.last = this.lastActive = index;
24258 if(!preventViewNotify){
24259 var proxy = new Roo.Element(
24260 this.grid.getRowDom(index)
24262 proxy.addClass('bg-info info');
24264 this.fireEvent("rowselect", this, index, r);
24265 this.fireEvent("selectionchange", this);
24271 * @param {Number} row The index of the row to deselect
24273 deselectRow : function(index, preventViewNotify)
24278 if(this.last == index){
24281 if(this.lastActive == index){
24282 this.lastActive = false;
24285 var r = this.grid.store.getAt(index);
24290 this.selections.remove(r);
24291 //.console.log('deselectRow - record id :' + r.id);
24292 if(!preventViewNotify){
24294 var proxy = new Roo.Element(
24295 this.grid.getRowDom(index)
24297 proxy.removeClass('bg-info info');
24299 this.fireEvent("rowdeselect", this, index);
24300 this.fireEvent("selectionchange", this);
24304 restoreLast : function(){
24306 this.last = this._last;
24311 acceptsNav : function(row, col, cm){
24312 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24316 onEditorKey : function(field, e){
24317 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24322 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24324 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24326 }else if(k == e.ENTER && !e.ctrlKey){
24330 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24332 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24334 }else if(k == e.ESC){
24338 g.startEditing(newCell[0], newCell[1]);
24344 * Ext JS Library 1.1.1
24345 * Copyright(c) 2006-2007, Ext JS, LLC.
24347 * Originally Released Under LGPL - original licence link has changed is not relivant.
24350 * <script type="text/javascript">
24354 * @class Roo.bootstrap.PagingToolbar
24355 * @extends Roo.bootstrap.NavSimplebar
24356 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24358 * Create a new PagingToolbar
24359 * @param {Object} config The config object
24360 * @param {Roo.data.Store} store
24362 Roo.bootstrap.PagingToolbar = function(config)
24364 // old args format still supported... - xtype is prefered..
24365 // created from xtype...
24367 this.ds = config.dataSource;
24369 if (config.store && !this.ds) {
24370 this.store= Roo.factory(config.store, Roo.data);
24371 this.ds = this.store;
24372 this.ds.xmodule = this.xmodule || false;
24375 this.toolbarItems = [];
24376 if (config.items) {
24377 this.toolbarItems = config.items;
24380 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24385 this.bind(this.ds);
24388 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24392 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24394 * @cfg {Roo.data.Store} dataSource
24395 * The underlying data store providing the paged data
24398 * @cfg {String/HTMLElement/Element} container
24399 * container The id or element that will contain the toolbar
24402 * @cfg {Boolean} displayInfo
24403 * True to display the displayMsg (defaults to false)
24406 * @cfg {Number} pageSize
24407 * The number of records to display per page (defaults to 20)
24411 * @cfg {String} displayMsg
24412 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24414 displayMsg : 'Displaying {0} - {1} of {2}',
24416 * @cfg {String} emptyMsg
24417 * The message to display when no records are found (defaults to "No data to display")
24419 emptyMsg : 'No data to display',
24421 * Customizable piece of the default paging text (defaults to "Page")
24424 beforePageText : "Page",
24426 * Customizable piece of the default paging text (defaults to "of %0")
24429 afterPageText : "of {0}",
24431 * Customizable piece of the default paging text (defaults to "First Page")
24434 firstText : "First Page",
24436 * Customizable piece of the default paging text (defaults to "Previous Page")
24439 prevText : "Previous Page",
24441 * Customizable piece of the default paging text (defaults to "Next Page")
24444 nextText : "Next Page",
24446 * Customizable piece of the default paging text (defaults to "Last Page")
24449 lastText : "Last Page",
24451 * Customizable piece of the default paging text (defaults to "Refresh")
24454 refreshText : "Refresh",
24458 onRender : function(ct, position)
24460 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24461 this.navgroup.parentId = this.id;
24462 this.navgroup.onRender(this.el, null);
24463 // add the buttons to the navgroup
24465 if(this.displayInfo){
24466 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24467 this.displayEl = this.el.select('.x-paging-info', true).first();
24468 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24469 // this.displayEl = navel.el.select('span',true).first();
24475 Roo.each(_this.buttons, function(e){ // this might need to use render????
24476 Roo.factory(e).onRender(_this.el, null);
24480 Roo.each(_this.toolbarItems, function(e) {
24481 _this.navgroup.addItem(e);
24485 this.first = this.navgroup.addItem({
24486 tooltip: this.firstText,
24488 icon : 'fa fa-backward',
24490 preventDefault: true,
24491 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24494 this.prev = this.navgroup.addItem({
24495 tooltip: this.prevText,
24497 icon : 'fa fa-step-backward',
24499 preventDefault: true,
24500 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24502 //this.addSeparator();
24505 var field = this.navgroup.addItem( {
24507 cls : 'x-paging-position',
24509 html : this.beforePageText +
24510 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24511 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24514 this.field = field.el.select('input', true).first();
24515 this.field.on("keydown", this.onPagingKeydown, this);
24516 this.field.on("focus", function(){this.dom.select();});
24519 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24520 //this.field.setHeight(18);
24521 //this.addSeparator();
24522 this.next = this.navgroup.addItem({
24523 tooltip: this.nextText,
24525 html : ' <i class="fa fa-step-forward">',
24527 preventDefault: true,
24528 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24530 this.last = this.navgroup.addItem({
24531 tooltip: this.lastText,
24532 icon : 'fa fa-forward',
24535 preventDefault: true,
24536 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24538 //this.addSeparator();
24539 this.loading = this.navgroup.addItem({
24540 tooltip: this.refreshText,
24541 icon: 'fa fa-refresh',
24542 preventDefault: true,
24543 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24549 updateInfo : function(){
24550 if(this.displayEl){
24551 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24552 var msg = count == 0 ?
24556 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24558 this.displayEl.update(msg);
24563 onLoad : function(ds, r, o)
24565 this.cursor = o.params.start ? o.params.start : 0;
24567 var d = this.getPageData(),
24572 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24573 this.field.dom.value = ap;
24574 this.first.setDisabled(ap == 1);
24575 this.prev.setDisabled(ap == 1);
24576 this.next.setDisabled(ap == ps);
24577 this.last.setDisabled(ap == ps);
24578 this.loading.enable();
24583 getPageData : function(){
24584 var total = this.ds.getTotalCount();
24587 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24588 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24593 onLoadError : function(){
24594 this.loading.enable();
24598 onPagingKeydown : function(e){
24599 var k = e.getKey();
24600 var d = this.getPageData();
24602 var v = this.field.dom.value, pageNum;
24603 if(!v || isNaN(pageNum = parseInt(v, 10))){
24604 this.field.dom.value = d.activePage;
24607 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24608 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24611 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))
24613 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24614 this.field.dom.value = pageNum;
24615 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24618 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24620 var v = this.field.dom.value, pageNum;
24621 var increment = (e.shiftKey) ? 10 : 1;
24622 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24625 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24626 this.field.dom.value = d.activePage;
24629 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24631 this.field.dom.value = parseInt(v, 10) + increment;
24632 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24633 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24640 beforeLoad : function(){
24642 this.loading.disable();
24647 onClick : function(which){
24656 ds.load({params:{start: 0, limit: this.pageSize}});
24659 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24662 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24665 var total = ds.getTotalCount();
24666 var extra = total % this.pageSize;
24667 var lastStart = extra ? (total - extra) : total-this.pageSize;
24668 ds.load({params:{start: lastStart, limit: this.pageSize}});
24671 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24677 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24678 * @param {Roo.data.Store} store The data store to unbind
24680 unbind : function(ds){
24681 ds.un("beforeload", this.beforeLoad, this);
24682 ds.un("load", this.onLoad, this);
24683 ds.un("loadexception", this.onLoadError, this);
24684 ds.un("remove", this.updateInfo, this);
24685 ds.un("add", this.updateInfo, this);
24686 this.ds = undefined;
24690 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24691 * @param {Roo.data.Store} store The data store to bind
24693 bind : function(ds){
24694 ds.on("beforeload", this.beforeLoad, this);
24695 ds.on("load", this.onLoad, this);
24696 ds.on("loadexception", this.onLoadError, this);
24697 ds.on("remove", this.updateInfo, this);
24698 ds.on("add", this.updateInfo, this);
24709 * @class Roo.bootstrap.MessageBar
24710 * @extends Roo.bootstrap.Component
24711 * Bootstrap MessageBar class
24712 * @cfg {String} html contents of the MessageBar
24713 * @cfg {String} weight (info | success | warning | danger) default info
24714 * @cfg {String} beforeClass insert the bar before the given class
24715 * @cfg {Boolean} closable (true | false) default false
24716 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24719 * Create a new Element
24720 * @param {Object} config The config object
24723 Roo.bootstrap.MessageBar = function(config){
24724 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24727 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24733 beforeClass: 'bootstrap-sticky-wrap',
24735 getAutoCreate : function(){
24739 cls: 'alert alert-dismissable alert-' + this.weight,
24744 html: this.html || ''
24750 cfg.cls += ' alert-messages-fixed';
24764 onRender : function(ct, position)
24766 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24769 var cfg = Roo.apply({}, this.getAutoCreate());
24773 cfg.cls += ' ' + this.cls;
24776 cfg.style = this.style;
24778 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24780 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24783 this.el.select('>button.close').on('click', this.hide, this);
24789 if (!this.rendered) {
24795 this.fireEvent('show', this);
24801 if (!this.rendered) {
24807 this.fireEvent('hide', this);
24810 update : function()
24812 // var e = this.el.dom.firstChild;
24814 // if(this.closable){
24815 // e = e.nextSibling;
24818 // e.data = this.html || '';
24820 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24836 * @class Roo.bootstrap.Graph
24837 * @extends Roo.bootstrap.Component
24838 * Bootstrap Graph class
24842 @cfg {String} graphtype bar | vbar | pie
24843 @cfg {number} g_x coodinator | centre x (pie)
24844 @cfg {number} g_y coodinator | centre y (pie)
24845 @cfg {number} g_r radius (pie)
24846 @cfg {number} g_height height of the chart (respected by all elements in the set)
24847 @cfg {number} g_width width of the chart (respected by all elements in the set)
24848 @cfg {Object} title The title of the chart
24851 -opts (object) options for the chart
24853 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24854 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24856 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.
24857 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24859 o stretch (boolean)
24861 -opts (object) options for the pie
24864 o startAngle (number)
24865 o endAngle (number)
24869 * Create a new Input
24870 * @param {Object} config The config object
24873 Roo.bootstrap.Graph = function(config){
24874 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24880 * The img click event for the img.
24881 * @param {Roo.EventObject} e
24887 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24898 //g_colors: this.colors,
24905 getAutoCreate : function(){
24916 onRender : function(ct,position){
24919 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24921 if (typeof(Raphael) == 'undefined') {
24922 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24926 this.raphael = Raphael(this.el.dom);
24928 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24929 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24930 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24931 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24933 r.text(160, 10, "Single Series Chart").attr(txtattr);
24934 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24935 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24936 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24938 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24939 r.barchart(330, 10, 300, 220, data1);
24940 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24941 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24944 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24945 // r.barchart(30, 30, 560, 250, xdata, {
24946 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24947 // axis : "0 0 1 1",
24948 // axisxlabels : xdata
24949 // //yvalues : cols,
24952 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24954 // this.load(null,xdata,{
24955 // axis : "0 0 1 1",
24956 // axisxlabels : xdata
24961 load : function(graphtype,xdata,opts)
24963 this.raphael.clear();
24965 graphtype = this.graphtype;
24970 var r = this.raphael,
24971 fin = function () {
24972 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24974 fout = function () {
24975 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24977 pfin = function() {
24978 this.sector.stop();
24979 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24982 this.label[0].stop();
24983 this.label[0].attr({ r: 7.5 });
24984 this.label[1].attr({ "font-weight": 800 });
24987 pfout = function() {
24988 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24991 this.label[0].animate({ r: 5 }, 500, "bounce");
24992 this.label[1].attr({ "font-weight": 400 });
24998 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25001 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25004 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25005 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25007 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25014 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25019 setTitle: function(o)
25024 initEvents: function() {
25027 this.el.on('click', this.onClick, this);
25031 onClick : function(e)
25033 Roo.log('img onclick');
25034 this.fireEvent('click', this, e);
25046 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25049 * @class Roo.bootstrap.dash.NumberBox
25050 * @extends Roo.bootstrap.Component
25051 * Bootstrap NumberBox class
25052 * @cfg {String} headline Box headline
25053 * @cfg {String} content Box content
25054 * @cfg {String} icon Box icon
25055 * @cfg {String} footer Footer text
25056 * @cfg {String} fhref Footer href
25059 * Create a new NumberBox
25060 * @param {Object} config The config object
25064 Roo.bootstrap.dash.NumberBox = function(config){
25065 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25069 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25078 getAutoCreate : function(){
25082 cls : 'small-box ',
25090 cls : 'roo-headline',
25091 html : this.headline
25095 cls : 'roo-content',
25096 html : this.content
25110 cls : 'ion ' + this.icon
25119 cls : 'small-box-footer',
25120 href : this.fhref || '#',
25124 cfg.cn.push(footer);
25131 onRender : function(ct,position){
25132 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25139 setHeadline: function (value)
25141 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25144 setFooter: function (value, href)
25146 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25149 this.el.select('a.small-box-footer',true).first().attr('href', href);
25154 setContent: function (value)
25156 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25159 initEvents: function()
25173 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25176 * @class Roo.bootstrap.dash.TabBox
25177 * @extends Roo.bootstrap.Component
25178 * Bootstrap TabBox class
25179 * @cfg {String} title Title of the TabBox
25180 * @cfg {String} icon Icon of the TabBox
25181 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25182 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25185 * Create a new TabBox
25186 * @param {Object} config The config object
25190 Roo.bootstrap.dash.TabBox = function(config){
25191 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25196 * When a pane is added
25197 * @param {Roo.bootstrap.dash.TabPane} pane
25201 * @event activatepane
25202 * When a pane is activated
25203 * @param {Roo.bootstrap.dash.TabPane} pane
25205 "activatepane" : true
25213 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25218 tabScrollable : false,
25220 getChildContainer : function()
25222 return this.el.select('.tab-content', true).first();
25225 getAutoCreate : function(){
25229 cls: 'pull-left header',
25237 cls: 'fa ' + this.icon
25243 cls: 'nav nav-tabs pull-right',
25249 if(this.tabScrollable){
25256 cls: 'nav nav-tabs pull-right',
25267 cls: 'nav-tabs-custom',
25272 cls: 'tab-content no-padding',
25280 initEvents : function()
25282 //Roo.log('add add pane handler');
25283 this.on('addpane', this.onAddPane, this);
25286 * Updates the box title
25287 * @param {String} html to set the title to.
25289 setTitle : function(value)
25291 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25293 onAddPane : function(pane)
25295 this.panes.push(pane);
25296 //Roo.log('addpane');
25298 // tabs are rendere left to right..
25299 if(!this.showtabs){
25303 var ctr = this.el.select('.nav-tabs', true).first();
25306 var existing = ctr.select('.nav-tab',true);
25307 var qty = existing.getCount();;
25310 var tab = ctr.createChild({
25312 cls : 'nav-tab' + (qty ? '' : ' active'),
25320 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25323 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25325 pane.el.addClass('active');
25330 onTabClick : function(ev,un,ob,pane)
25332 //Roo.log('tab - prev default');
25333 ev.preventDefault();
25336 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25337 pane.tab.addClass('active');
25338 //Roo.log(pane.title);
25339 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25340 // technically we should have a deactivate event.. but maybe add later.
25341 // and it should not de-activate the selected tab...
25342 this.fireEvent('activatepane', pane);
25343 pane.el.addClass('active');
25344 pane.fireEvent('activate');
25349 getActivePane : function()
25352 Roo.each(this.panes, function(p) {
25353 if(p.el.hasClass('active')){
25374 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25376 * @class Roo.bootstrap.TabPane
25377 * @extends Roo.bootstrap.Component
25378 * Bootstrap TabPane class
25379 * @cfg {Boolean} active (false | true) Default false
25380 * @cfg {String} title title of panel
25384 * Create a new TabPane
25385 * @param {Object} config The config object
25388 Roo.bootstrap.dash.TabPane = function(config){
25389 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25395 * When a pane is activated
25396 * @param {Roo.bootstrap.dash.TabPane} pane
25403 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25408 // the tabBox that this is attached to.
25411 getAutoCreate : function()
25419 cfg.cls += ' active';
25424 initEvents : function()
25426 //Roo.log('trigger add pane handler');
25427 this.parent().fireEvent('addpane', this)
25431 * Updates the tab title
25432 * @param {String} html to set the title to.
25434 setTitle: function(str)
25440 this.tab.select('a', true).first().dom.innerHTML = str;
25457 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25460 * @class Roo.bootstrap.menu.Menu
25461 * @extends Roo.bootstrap.Component
25462 * Bootstrap Menu class - container for Menu
25463 * @cfg {String} html Text of the menu
25464 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25465 * @cfg {String} icon Font awesome icon
25466 * @cfg {String} pos Menu align to (top | bottom) default bottom
25470 * Create a new Menu
25471 * @param {Object} config The config object
25475 Roo.bootstrap.menu.Menu = function(config){
25476 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25480 * @event beforeshow
25481 * Fires before this menu is displayed
25482 * @param {Roo.bootstrap.menu.Menu} this
25486 * @event beforehide
25487 * Fires before this menu is hidden
25488 * @param {Roo.bootstrap.menu.Menu} this
25493 * Fires after this menu is displayed
25494 * @param {Roo.bootstrap.menu.Menu} this
25499 * Fires after this menu is hidden
25500 * @param {Roo.bootstrap.menu.Menu} this
25505 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25506 * @param {Roo.bootstrap.menu.Menu} this
25507 * @param {Roo.EventObject} e
25514 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25518 weight : 'default',
25523 getChildContainer : function() {
25524 if(this.isSubMenu){
25528 return this.el.select('ul.dropdown-menu', true).first();
25531 getAutoCreate : function()
25536 cls : 'roo-menu-text',
25544 cls : 'fa ' + this.icon
25555 cls : 'dropdown-button btn btn-' + this.weight,
25560 cls : 'dropdown-toggle btn btn-' + this.weight,
25570 cls : 'dropdown-menu'
25576 if(this.pos == 'top'){
25577 cfg.cls += ' dropup';
25580 if(this.isSubMenu){
25583 cls : 'dropdown-menu'
25590 onRender : function(ct, position)
25592 this.isSubMenu = ct.hasClass('dropdown-submenu');
25594 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25597 initEvents : function()
25599 if(this.isSubMenu){
25603 this.hidden = true;
25605 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25606 this.triggerEl.on('click', this.onTriggerPress, this);
25608 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25609 this.buttonEl.on('click', this.onClick, this);
25615 if(this.isSubMenu){
25619 return this.el.select('ul.dropdown-menu', true).first();
25622 onClick : function(e)
25624 this.fireEvent("click", this, e);
25627 onTriggerPress : function(e)
25629 if (this.isVisible()) {
25636 isVisible : function(){
25637 return !this.hidden;
25642 this.fireEvent("beforeshow", this);
25644 this.hidden = false;
25645 this.el.addClass('open');
25647 Roo.get(document).on("mouseup", this.onMouseUp, this);
25649 this.fireEvent("show", this);
25656 this.fireEvent("beforehide", this);
25658 this.hidden = true;
25659 this.el.removeClass('open');
25661 Roo.get(document).un("mouseup", this.onMouseUp);
25663 this.fireEvent("hide", this);
25666 onMouseUp : function()
25680 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25683 * @class Roo.bootstrap.menu.Item
25684 * @extends Roo.bootstrap.Component
25685 * Bootstrap MenuItem class
25686 * @cfg {Boolean} submenu (true | false) default false
25687 * @cfg {String} html text of the item
25688 * @cfg {String} href the link
25689 * @cfg {Boolean} disable (true | false) default false
25690 * @cfg {Boolean} preventDefault (true | false) default true
25691 * @cfg {String} icon Font awesome icon
25692 * @cfg {String} pos Submenu align to (left | right) default right
25696 * Create a new Item
25697 * @param {Object} config The config object
25701 Roo.bootstrap.menu.Item = function(config){
25702 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25706 * Fires when the mouse is hovering over this menu
25707 * @param {Roo.bootstrap.menu.Item} this
25708 * @param {Roo.EventObject} e
25713 * Fires when the mouse exits this menu
25714 * @param {Roo.bootstrap.menu.Item} this
25715 * @param {Roo.EventObject} e
25721 * The raw click event for the entire grid.
25722 * @param {Roo.EventObject} e
25728 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25733 preventDefault: true,
25738 getAutoCreate : function()
25743 cls : 'roo-menu-item-text',
25751 cls : 'fa ' + this.icon
25760 href : this.href || '#',
25767 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25771 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25773 if(this.pos == 'left'){
25774 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25781 initEvents : function()
25783 this.el.on('mouseover', this.onMouseOver, this);
25784 this.el.on('mouseout', this.onMouseOut, this);
25786 this.el.select('a', true).first().on('click', this.onClick, this);
25790 onClick : function(e)
25792 if(this.preventDefault){
25793 e.preventDefault();
25796 this.fireEvent("click", this, e);
25799 onMouseOver : function(e)
25801 if(this.submenu && this.pos == 'left'){
25802 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25805 this.fireEvent("mouseover", this, e);
25808 onMouseOut : function(e)
25810 this.fireEvent("mouseout", this, e);
25822 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25825 * @class Roo.bootstrap.menu.Separator
25826 * @extends Roo.bootstrap.Component
25827 * Bootstrap Separator class
25830 * Create a new Separator
25831 * @param {Object} config The config object
25835 Roo.bootstrap.menu.Separator = function(config){
25836 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25839 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25841 getAutoCreate : function(){
25862 * @class Roo.bootstrap.Tooltip
25863 * Bootstrap Tooltip class
25864 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25865 * to determine which dom element triggers the tooltip.
25867 * It needs to add support for additional attributes like tooltip-position
25870 * Create a new Toolti
25871 * @param {Object} config The config object
25874 Roo.bootstrap.Tooltip = function(config){
25875 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25877 this.alignment = Roo.bootstrap.Tooltip.alignment;
25879 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25880 this.alignment = config.alignment;
25885 Roo.apply(Roo.bootstrap.Tooltip, {
25887 * @function init initialize tooltip monitoring.
25891 currentTip : false,
25892 currentRegion : false,
25898 Roo.get(document).on('mouseover', this.enter ,this);
25899 Roo.get(document).on('mouseout', this.leave, this);
25902 this.currentTip = new Roo.bootstrap.Tooltip();
25905 enter : function(ev)
25907 var dom = ev.getTarget();
25909 //Roo.log(['enter',dom]);
25910 var el = Roo.fly(dom);
25911 if (this.currentEl) {
25913 //Roo.log(this.currentEl);
25914 //Roo.log(this.currentEl.contains(dom));
25915 if (this.currentEl == el) {
25918 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25924 if (this.currentTip.el) {
25925 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25929 if(!el || el.dom == document){
25935 // you can not look for children, as if el is the body.. then everythign is the child..
25936 if (!el.attr('tooltip')) { //
25937 if (!el.select("[tooltip]").elements.length) {
25940 // is the mouse over this child...?
25941 bindEl = el.select("[tooltip]").first();
25942 var xy = ev.getXY();
25943 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25944 //Roo.log("not in region.");
25947 //Roo.log("child element over..");
25950 this.currentEl = bindEl;
25951 this.currentTip.bind(bindEl);
25952 this.currentRegion = Roo.lib.Region.getRegion(dom);
25953 this.currentTip.enter();
25956 leave : function(ev)
25958 var dom = ev.getTarget();
25959 //Roo.log(['leave',dom]);
25960 if (!this.currentEl) {
25965 if (dom != this.currentEl.dom) {
25968 var xy = ev.getXY();
25969 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25972 // only activate leave if mouse cursor is outside... bounding box..
25977 if (this.currentTip) {
25978 this.currentTip.leave();
25980 //Roo.log('clear currentEl');
25981 this.currentEl = false;
25986 'left' : ['r-l', [-2,0], 'right'],
25987 'right' : ['l-r', [2,0], 'left'],
25988 'bottom' : ['t-b', [0,2], 'top'],
25989 'top' : [ 'b-t', [0,-2], 'bottom']
25995 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26000 delay : null, // can be { show : 300 , hide: 500}
26004 hoverState : null, //???
26006 placement : 'bottom',
26010 getAutoCreate : function(){
26017 cls : 'tooltip-arrow'
26020 cls : 'tooltip-inner'
26027 bind : function(el)
26033 enter : function () {
26035 if (this.timeout != null) {
26036 clearTimeout(this.timeout);
26039 this.hoverState = 'in';
26040 //Roo.log("enter - show");
26041 if (!this.delay || !this.delay.show) {
26046 this.timeout = setTimeout(function () {
26047 if (_t.hoverState == 'in') {
26050 }, this.delay.show);
26054 clearTimeout(this.timeout);
26056 this.hoverState = 'out';
26057 if (!this.delay || !this.delay.hide) {
26063 this.timeout = setTimeout(function () {
26064 //Roo.log("leave - timeout");
26066 if (_t.hoverState == 'out') {
26068 Roo.bootstrap.Tooltip.currentEl = false;
26073 show : function (msg)
26076 this.render(document.body);
26079 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26081 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26083 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26085 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26087 var placement = typeof this.placement == 'function' ?
26088 this.placement.call(this, this.el, on_el) :
26091 var autoToken = /\s?auto?\s?/i;
26092 var autoPlace = autoToken.test(placement);
26094 placement = placement.replace(autoToken, '') || 'top';
26098 //this.el.setXY([0,0]);
26100 //this.el.dom.style.display='block';
26102 //this.el.appendTo(on_el);
26104 var p = this.getPosition();
26105 var box = this.el.getBox();
26111 var align = this.alignment[placement];
26113 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26115 if(placement == 'top' || placement == 'bottom'){
26117 placement = 'right';
26120 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26121 placement = 'left';
26124 var scroll = Roo.select('body', true).first().getScroll();
26126 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26132 this.el.alignTo(this.bindEl, align[0],align[1]);
26133 //var arrow = this.el.select('.arrow',true).first();
26134 //arrow.set(align[2],
26136 this.el.addClass(placement);
26138 this.el.addClass('in fade');
26140 this.hoverState = null;
26142 if (this.el.hasClass('fade')) {
26153 //this.el.setXY([0,0]);
26154 this.el.removeClass('in');
26170 * @class Roo.bootstrap.LocationPicker
26171 * @extends Roo.bootstrap.Component
26172 * Bootstrap LocationPicker class
26173 * @cfg {Number} latitude Position when init default 0
26174 * @cfg {Number} longitude Position when init default 0
26175 * @cfg {Number} zoom default 15
26176 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26177 * @cfg {Boolean} mapTypeControl default false
26178 * @cfg {Boolean} disableDoubleClickZoom default false
26179 * @cfg {Boolean} scrollwheel default true
26180 * @cfg {Boolean} streetViewControl default false
26181 * @cfg {Number} radius default 0
26182 * @cfg {String} locationName
26183 * @cfg {Boolean} draggable default true
26184 * @cfg {Boolean} enableAutocomplete default false
26185 * @cfg {Boolean} enableReverseGeocode default true
26186 * @cfg {String} markerTitle
26189 * Create a new LocationPicker
26190 * @param {Object} config The config object
26194 Roo.bootstrap.LocationPicker = function(config){
26196 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26201 * Fires when the picker initialized.
26202 * @param {Roo.bootstrap.LocationPicker} this
26203 * @param {Google Location} location
26207 * @event positionchanged
26208 * Fires when the picker position changed.
26209 * @param {Roo.bootstrap.LocationPicker} this
26210 * @param {Google Location} location
26212 positionchanged : true,
26215 * Fires when the map resize.
26216 * @param {Roo.bootstrap.LocationPicker} this
26221 * Fires when the map show.
26222 * @param {Roo.bootstrap.LocationPicker} this
26227 * Fires when the map hide.
26228 * @param {Roo.bootstrap.LocationPicker} this
26233 * Fires when click the map.
26234 * @param {Roo.bootstrap.LocationPicker} this
26235 * @param {Map event} e
26239 * @event mapRightClick
26240 * Fires when right click the map.
26241 * @param {Roo.bootstrap.LocationPicker} this
26242 * @param {Map event} e
26244 mapRightClick : true,
26246 * @event markerClick
26247 * Fires when click the marker.
26248 * @param {Roo.bootstrap.LocationPicker} this
26249 * @param {Map event} e
26251 markerClick : true,
26253 * @event markerRightClick
26254 * Fires when right click the marker.
26255 * @param {Roo.bootstrap.LocationPicker} this
26256 * @param {Map event} e
26258 markerRightClick : true,
26260 * @event OverlayViewDraw
26261 * Fires when OverlayView Draw
26262 * @param {Roo.bootstrap.LocationPicker} this
26264 OverlayViewDraw : true,
26266 * @event OverlayViewOnAdd
26267 * Fires when OverlayView Draw
26268 * @param {Roo.bootstrap.LocationPicker} this
26270 OverlayViewOnAdd : true,
26272 * @event OverlayViewOnRemove
26273 * Fires when OverlayView Draw
26274 * @param {Roo.bootstrap.LocationPicker} this
26276 OverlayViewOnRemove : true,
26278 * @event OverlayViewShow
26279 * Fires when OverlayView Draw
26280 * @param {Roo.bootstrap.LocationPicker} this
26281 * @param {Pixel} cpx
26283 OverlayViewShow : true,
26285 * @event OverlayViewHide
26286 * Fires when OverlayView Draw
26287 * @param {Roo.bootstrap.LocationPicker} this
26289 OverlayViewHide : true,
26291 * @event loadexception
26292 * Fires when load google lib failed.
26293 * @param {Roo.bootstrap.LocationPicker} this
26295 loadexception : true
26300 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26302 gMapContext: false,
26308 mapTypeControl: false,
26309 disableDoubleClickZoom: false,
26311 streetViewControl: false,
26315 enableAutocomplete: false,
26316 enableReverseGeocode: true,
26319 getAutoCreate: function()
26324 cls: 'roo-location-picker'
26330 initEvents: function(ct, position)
26332 if(!this.el.getWidth() || this.isApplied()){
26336 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26341 initial: function()
26343 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26344 this.fireEvent('loadexception', this);
26348 if(!this.mapTypeId){
26349 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26352 this.gMapContext = this.GMapContext();
26354 this.initOverlayView();
26356 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26360 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26361 _this.setPosition(_this.gMapContext.marker.position);
26364 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26365 _this.fireEvent('mapClick', this, event);
26369 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26370 _this.fireEvent('mapRightClick', this, event);
26374 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26375 _this.fireEvent('markerClick', this, event);
26379 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26380 _this.fireEvent('markerRightClick', this, event);
26384 this.setPosition(this.gMapContext.location);
26386 this.fireEvent('initial', this, this.gMapContext.location);
26389 initOverlayView: function()
26393 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26397 _this.fireEvent('OverlayViewDraw', _this);
26402 _this.fireEvent('OverlayViewOnAdd', _this);
26405 onRemove: function()
26407 _this.fireEvent('OverlayViewOnRemove', _this);
26410 show: function(cpx)
26412 _this.fireEvent('OverlayViewShow', _this, cpx);
26417 _this.fireEvent('OverlayViewHide', _this);
26423 fromLatLngToContainerPixel: function(event)
26425 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26428 isApplied: function()
26430 return this.getGmapContext() == false ? false : true;
26433 getGmapContext: function()
26435 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26438 GMapContext: function()
26440 var position = new google.maps.LatLng(this.latitude, this.longitude);
26442 var _map = new google.maps.Map(this.el.dom, {
26445 mapTypeId: this.mapTypeId,
26446 mapTypeControl: this.mapTypeControl,
26447 disableDoubleClickZoom: this.disableDoubleClickZoom,
26448 scrollwheel: this.scrollwheel,
26449 streetViewControl: this.streetViewControl,
26450 locationName: this.locationName,
26451 draggable: this.draggable,
26452 enableAutocomplete: this.enableAutocomplete,
26453 enableReverseGeocode: this.enableReverseGeocode
26456 var _marker = new google.maps.Marker({
26457 position: position,
26459 title: this.markerTitle,
26460 draggable: this.draggable
26467 location: position,
26468 radius: this.radius,
26469 locationName: this.locationName,
26470 addressComponents: {
26471 formatted_address: null,
26472 addressLine1: null,
26473 addressLine2: null,
26475 streetNumber: null,
26479 stateOrProvince: null
26482 domContainer: this.el.dom,
26483 geodecoder: new google.maps.Geocoder()
26487 drawCircle: function(center, radius, options)
26489 if (this.gMapContext.circle != null) {
26490 this.gMapContext.circle.setMap(null);
26494 options = Roo.apply({}, options, {
26495 strokeColor: "#0000FF",
26496 strokeOpacity: .35,
26498 fillColor: "#0000FF",
26502 options.map = this.gMapContext.map;
26503 options.radius = radius;
26504 options.center = center;
26505 this.gMapContext.circle = new google.maps.Circle(options);
26506 return this.gMapContext.circle;
26512 setPosition: function(location)
26514 this.gMapContext.location = location;
26515 this.gMapContext.marker.setPosition(location);
26516 this.gMapContext.map.panTo(location);
26517 this.drawCircle(location, this.gMapContext.radius, {});
26521 if (this.gMapContext.settings.enableReverseGeocode) {
26522 this.gMapContext.geodecoder.geocode({
26523 latLng: this.gMapContext.location
26524 }, function(results, status) {
26526 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26527 _this.gMapContext.locationName = results[0].formatted_address;
26528 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26530 _this.fireEvent('positionchanged', this, location);
26537 this.fireEvent('positionchanged', this, location);
26542 google.maps.event.trigger(this.gMapContext.map, "resize");
26544 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26546 this.fireEvent('resize', this);
26549 setPositionByLatLng: function(latitude, longitude)
26551 this.setPosition(new google.maps.LatLng(latitude, longitude));
26554 getCurrentPosition: function()
26557 latitude: this.gMapContext.location.lat(),
26558 longitude: this.gMapContext.location.lng()
26562 getAddressName: function()
26564 return this.gMapContext.locationName;
26567 getAddressComponents: function()
26569 return this.gMapContext.addressComponents;
26572 address_component_from_google_geocode: function(address_components)
26576 for (var i = 0; i < address_components.length; i++) {
26577 var component = address_components[i];
26578 if (component.types.indexOf("postal_code") >= 0) {
26579 result.postalCode = component.short_name;
26580 } else if (component.types.indexOf("street_number") >= 0) {
26581 result.streetNumber = component.short_name;
26582 } else if (component.types.indexOf("route") >= 0) {
26583 result.streetName = component.short_name;
26584 } else if (component.types.indexOf("neighborhood") >= 0) {
26585 result.city = component.short_name;
26586 } else if (component.types.indexOf("locality") >= 0) {
26587 result.city = component.short_name;
26588 } else if (component.types.indexOf("sublocality") >= 0) {
26589 result.district = component.short_name;
26590 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26591 result.stateOrProvince = component.short_name;
26592 } else if (component.types.indexOf("country") >= 0) {
26593 result.country = component.short_name;
26597 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26598 result.addressLine2 = "";
26602 setZoomLevel: function(zoom)
26604 this.gMapContext.map.setZoom(zoom);
26617 this.fireEvent('show', this);
26628 this.fireEvent('hide', this);
26633 Roo.apply(Roo.bootstrap.LocationPicker, {
26635 OverlayView : function(map, options)
26637 options = options || {};
26651 * @class Roo.bootstrap.Alert
26652 * @extends Roo.bootstrap.Component
26653 * Bootstrap Alert class
26654 * @cfg {String} title The title of alert
26655 * @cfg {String} html The content of alert
26656 * @cfg {String} weight ( success | info | warning | danger )
26657 * @cfg {String} faicon font-awesomeicon
26660 * Create a new alert
26661 * @param {Object} config The config object
26665 Roo.bootstrap.Alert = function(config){
26666 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26670 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26677 getAutoCreate : function()
26686 cls : 'roo-alert-icon'
26691 cls : 'roo-alert-title',
26696 cls : 'roo-alert-text',
26703 cfg.cn[0].cls += ' fa ' + this.faicon;
26707 cfg.cls += ' alert-' + this.weight;
26713 initEvents: function()
26715 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26718 setTitle : function(str)
26720 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26723 setText : function(str)
26725 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26728 setWeight : function(weight)
26731 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26734 this.weight = weight;
26736 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26739 setIcon : function(icon)
26742 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26745 this.faicon = icon;
26747 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26768 * @class Roo.bootstrap.UploadCropbox
26769 * @extends Roo.bootstrap.Component
26770 * Bootstrap UploadCropbox class
26771 * @cfg {String} emptyText show when image has been loaded
26772 * @cfg {String} rotateNotify show when image too small to rotate
26773 * @cfg {Number} errorTimeout default 3000
26774 * @cfg {Number} minWidth default 300
26775 * @cfg {Number} minHeight default 300
26776 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26777 * @cfg {Boolean} isDocument (true|false) default false
26778 * @cfg {String} url action url
26779 * @cfg {String} paramName default 'imageUpload'
26780 * @cfg {String} method default POST
26781 * @cfg {Boolean} loadMask (true|false) default true
26782 * @cfg {Boolean} loadingText default 'Loading...'
26785 * Create a new UploadCropbox
26786 * @param {Object} config The config object
26789 Roo.bootstrap.UploadCropbox = function(config){
26790 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26794 * @event beforeselectfile
26795 * Fire before select file
26796 * @param {Roo.bootstrap.UploadCropbox} this
26798 "beforeselectfile" : true,
26801 * Fire after initEvent
26802 * @param {Roo.bootstrap.UploadCropbox} this
26807 * Fire after initEvent
26808 * @param {Roo.bootstrap.UploadCropbox} this
26809 * @param {String} data
26814 * Fire when preparing the file data
26815 * @param {Roo.bootstrap.UploadCropbox} this
26816 * @param {Object} file
26821 * Fire when get exception
26822 * @param {Roo.bootstrap.UploadCropbox} this
26823 * @param {XMLHttpRequest} xhr
26825 "exception" : true,
26827 * @event beforeloadcanvas
26828 * Fire before load the canvas
26829 * @param {Roo.bootstrap.UploadCropbox} this
26830 * @param {String} src
26832 "beforeloadcanvas" : true,
26835 * Fire when trash image
26836 * @param {Roo.bootstrap.UploadCropbox} this
26841 * Fire when download the image
26842 * @param {Roo.bootstrap.UploadCropbox} this
26846 * @event footerbuttonclick
26847 * Fire when footerbuttonclick
26848 * @param {Roo.bootstrap.UploadCropbox} this
26849 * @param {String} type
26851 "footerbuttonclick" : true,
26855 * @param {Roo.bootstrap.UploadCropbox} this
26860 * Fire when rotate the image
26861 * @param {Roo.bootstrap.UploadCropbox} this
26862 * @param {String} pos
26867 * Fire when inspect the file
26868 * @param {Roo.bootstrap.UploadCropbox} this
26869 * @param {Object} file
26874 * Fire when xhr upload the file
26875 * @param {Roo.bootstrap.UploadCropbox} this
26876 * @param {Object} data
26881 * Fire when arrange the file data
26882 * @param {Roo.bootstrap.UploadCropbox} this
26883 * @param {Object} formData
26888 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26891 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26893 emptyText : 'Click to upload image',
26894 rotateNotify : 'Image is too small to rotate',
26895 errorTimeout : 3000,
26909 cropType : 'image/jpeg',
26911 canvasLoaded : false,
26912 isDocument : false,
26914 paramName : 'imageUpload',
26916 loadingText : 'Loading...',
26919 getAutoCreate : function()
26923 cls : 'roo-upload-cropbox',
26927 cls : 'roo-upload-cropbox-selector',
26932 cls : 'roo-upload-cropbox-body',
26933 style : 'cursor:pointer',
26937 cls : 'roo-upload-cropbox-preview'
26941 cls : 'roo-upload-cropbox-thumb'
26945 cls : 'roo-upload-cropbox-empty-notify',
26946 html : this.emptyText
26950 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26951 html : this.rotateNotify
26957 cls : 'roo-upload-cropbox-footer',
26960 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26970 onRender : function(ct, position)
26972 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26974 if (this.buttons.length) {
26976 Roo.each(this.buttons, function(bb) {
26978 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26980 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26986 this.maskEl = this.el;
26990 initEvents : function()
26992 this.urlAPI = (window.createObjectURL && window) ||
26993 (window.URL && URL.revokeObjectURL && URL) ||
26994 (window.webkitURL && webkitURL);
26996 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26997 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26999 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27000 this.selectorEl.hide();
27002 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27003 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27005 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27006 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27007 this.thumbEl.hide();
27009 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27010 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27012 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27013 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27014 this.errorEl.hide();
27016 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27017 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27018 this.footerEl.hide();
27020 this.setThumbBoxSize();
27026 this.fireEvent('initial', this);
27033 window.addEventListener("resize", function() { _this.resize(); } );
27035 this.bodyEl.on('click', this.beforeSelectFile, this);
27038 this.bodyEl.on('touchstart', this.onTouchStart, this);
27039 this.bodyEl.on('touchmove', this.onTouchMove, this);
27040 this.bodyEl.on('touchend', this.onTouchEnd, this);
27044 this.bodyEl.on('mousedown', this.onMouseDown, this);
27045 this.bodyEl.on('mousemove', this.onMouseMove, this);
27046 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27047 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27048 Roo.get(document).on('mouseup', this.onMouseUp, this);
27051 this.selectorEl.on('change', this.onFileSelected, this);
27057 this.baseScale = 1;
27059 this.baseRotate = 1;
27060 this.dragable = false;
27061 this.pinching = false;
27064 this.cropData = false;
27065 this.notifyEl.dom.innerHTML = this.emptyText;
27067 this.selectorEl.dom.value = '';
27071 resize : function()
27073 if(this.fireEvent('resize', this) != false){
27074 this.setThumbBoxPosition();
27075 this.setCanvasPosition();
27079 onFooterButtonClick : function(e, el, o, type)
27082 case 'rotate-left' :
27083 this.onRotateLeft(e);
27085 case 'rotate-right' :
27086 this.onRotateRight(e);
27089 this.beforeSelectFile(e);
27104 this.fireEvent('footerbuttonclick', this, type);
27107 beforeSelectFile : function(e)
27109 e.preventDefault();
27111 if(this.fireEvent('beforeselectfile', this) != false){
27112 this.selectorEl.dom.click();
27116 onFileSelected : function(e)
27118 e.preventDefault();
27120 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27124 var file = this.selectorEl.dom.files[0];
27126 if(this.fireEvent('inspect', this, file) != false){
27127 this.prepare(file);
27132 trash : function(e)
27134 this.fireEvent('trash', this);
27137 download : function(e)
27139 this.fireEvent('download', this);
27142 loadCanvas : function(src)
27144 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27148 this.imageEl = document.createElement('img');
27152 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27154 this.imageEl.src = src;
27158 onLoadCanvas : function()
27160 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27161 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27163 this.bodyEl.un('click', this.beforeSelectFile, this);
27165 this.notifyEl.hide();
27166 this.thumbEl.show();
27167 this.footerEl.show();
27169 this.baseRotateLevel();
27171 if(this.isDocument){
27172 this.setThumbBoxSize();
27175 this.setThumbBoxPosition();
27177 this.baseScaleLevel();
27183 this.canvasLoaded = true;
27186 this.maskEl.unmask();
27191 setCanvasPosition : function()
27193 if(!this.canvasEl){
27197 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27198 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27200 this.previewEl.setLeft(pw);
27201 this.previewEl.setTop(ph);
27205 onMouseDown : function(e)
27209 this.dragable = true;
27210 this.pinching = false;
27212 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27213 this.dragable = false;
27217 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27218 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27222 onMouseMove : function(e)
27226 if(!this.canvasLoaded){
27230 if (!this.dragable){
27234 var minX = Math.ceil(this.thumbEl.getLeft(true));
27235 var minY = Math.ceil(this.thumbEl.getTop(true));
27237 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27238 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27240 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27241 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27243 x = x - this.mouseX;
27244 y = y - this.mouseY;
27246 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27247 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27249 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27250 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27252 this.previewEl.setLeft(bgX);
27253 this.previewEl.setTop(bgY);
27255 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27256 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27259 onMouseUp : function(e)
27263 this.dragable = false;
27266 onMouseWheel : function(e)
27270 this.startScale = this.scale;
27272 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27274 if(!this.zoomable()){
27275 this.scale = this.startScale;
27284 zoomable : function()
27286 var minScale = this.thumbEl.getWidth() / this.minWidth;
27288 if(this.minWidth < this.minHeight){
27289 minScale = this.thumbEl.getHeight() / this.minHeight;
27292 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27293 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27297 (this.rotate == 0 || this.rotate == 180) &&
27299 width > this.imageEl.OriginWidth ||
27300 height > this.imageEl.OriginHeight ||
27301 (width < this.minWidth && height < this.minHeight)
27309 (this.rotate == 90 || this.rotate == 270) &&
27311 width > this.imageEl.OriginWidth ||
27312 height > this.imageEl.OriginHeight ||
27313 (width < this.minHeight && height < this.minWidth)
27320 !this.isDocument &&
27321 (this.rotate == 0 || this.rotate == 180) &&
27323 width < this.minWidth ||
27324 width > this.imageEl.OriginWidth ||
27325 height < this.minHeight ||
27326 height > this.imageEl.OriginHeight
27333 !this.isDocument &&
27334 (this.rotate == 90 || this.rotate == 270) &&
27336 width < this.minHeight ||
27337 width > this.imageEl.OriginWidth ||
27338 height < this.minWidth ||
27339 height > this.imageEl.OriginHeight
27349 onRotateLeft : function(e)
27351 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27353 var minScale = this.thumbEl.getWidth() / this.minWidth;
27355 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27356 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27358 this.startScale = this.scale;
27360 while (this.getScaleLevel() < minScale){
27362 this.scale = this.scale + 1;
27364 if(!this.zoomable()){
27369 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27370 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27375 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27382 this.scale = this.startScale;
27384 this.onRotateFail();
27389 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27391 if(this.isDocument){
27392 this.setThumbBoxSize();
27393 this.setThumbBoxPosition();
27394 this.setCanvasPosition();
27399 this.fireEvent('rotate', this, 'left');
27403 onRotateRight : function(e)
27405 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27407 var minScale = this.thumbEl.getWidth() / this.minWidth;
27409 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27410 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27412 this.startScale = this.scale;
27414 while (this.getScaleLevel() < minScale){
27416 this.scale = this.scale + 1;
27418 if(!this.zoomable()){
27423 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27424 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27429 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27436 this.scale = this.startScale;
27438 this.onRotateFail();
27443 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27445 if(this.isDocument){
27446 this.setThumbBoxSize();
27447 this.setThumbBoxPosition();
27448 this.setCanvasPosition();
27453 this.fireEvent('rotate', this, 'right');
27456 onRotateFail : function()
27458 this.errorEl.show(true);
27462 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27467 this.previewEl.dom.innerHTML = '';
27469 var canvasEl = document.createElement("canvas");
27471 var contextEl = canvasEl.getContext("2d");
27473 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27474 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27475 var center = this.imageEl.OriginWidth / 2;
27477 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27478 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27479 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27480 center = this.imageEl.OriginHeight / 2;
27483 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27485 contextEl.translate(center, center);
27486 contextEl.rotate(this.rotate * Math.PI / 180);
27488 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27490 this.canvasEl = document.createElement("canvas");
27492 this.contextEl = this.canvasEl.getContext("2d");
27494 switch (this.rotate) {
27497 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27498 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27500 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27505 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27506 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27508 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27509 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);
27513 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27518 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27519 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27521 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27522 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);
27526 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);
27531 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27532 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27534 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27535 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27539 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);
27546 this.previewEl.appendChild(this.canvasEl);
27548 this.setCanvasPosition();
27553 if(!this.canvasLoaded){
27557 var imageCanvas = document.createElement("canvas");
27559 var imageContext = imageCanvas.getContext("2d");
27561 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27562 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27564 var center = imageCanvas.width / 2;
27566 imageContext.translate(center, center);
27568 imageContext.rotate(this.rotate * Math.PI / 180);
27570 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27572 var canvas = document.createElement("canvas");
27574 var context = canvas.getContext("2d");
27576 canvas.width = this.minWidth;
27577 canvas.height = this.minHeight;
27579 switch (this.rotate) {
27582 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27583 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27585 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27586 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27588 var targetWidth = this.minWidth - 2 * x;
27589 var targetHeight = this.minHeight - 2 * y;
27593 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27594 scale = targetWidth / width;
27597 if(x > 0 && y == 0){
27598 scale = targetHeight / height;
27601 if(x > 0 && y > 0){
27602 scale = targetWidth / width;
27604 if(width < height){
27605 scale = targetHeight / height;
27609 context.scale(scale, scale);
27611 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27612 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27614 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27615 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27617 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27622 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27623 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27625 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27626 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27628 var targetWidth = this.minWidth - 2 * x;
27629 var targetHeight = this.minHeight - 2 * y;
27633 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27634 scale = targetWidth / width;
27637 if(x > 0 && y == 0){
27638 scale = targetHeight / height;
27641 if(x > 0 && y > 0){
27642 scale = targetWidth / width;
27644 if(width < height){
27645 scale = targetHeight / height;
27649 context.scale(scale, scale);
27651 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27652 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27654 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27655 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27657 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27659 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27664 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27665 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27667 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27668 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27670 var targetWidth = this.minWidth - 2 * x;
27671 var targetHeight = this.minHeight - 2 * y;
27675 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27676 scale = targetWidth / width;
27679 if(x > 0 && y == 0){
27680 scale = targetHeight / height;
27683 if(x > 0 && y > 0){
27684 scale = targetWidth / width;
27686 if(width < height){
27687 scale = targetHeight / height;
27691 context.scale(scale, scale);
27693 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27694 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27696 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27697 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27699 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27700 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27702 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27707 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27708 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27710 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27711 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27713 var targetWidth = this.minWidth - 2 * x;
27714 var targetHeight = this.minHeight - 2 * y;
27718 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27719 scale = targetWidth / width;
27722 if(x > 0 && y == 0){
27723 scale = targetHeight / height;
27726 if(x > 0 && y > 0){
27727 scale = targetWidth / width;
27729 if(width < height){
27730 scale = targetHeight / height;
27734 context.scale(scale, scale);
27736 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27737 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27739 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27740 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27742 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27744 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27751 this.cropData = canvas.toDataURL(this.cropType);
27753 if(this.fireEvent('crop', this, this.cropData) !== false){
27754 this.process(this.file, this.cropData);
27761 setThumbBoxSize : function()
27765 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27766 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27767 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27769 this.minWidth = width;
27770 this.minHeight = height;
27772 if(this.rotate == 90 || this.rotate == 270){
27773 this.minWidth = height;
27774 this.minHeight = width;
27779 width = Math.ceil(this.minWidth * height / this.minHeight);
27781 if(this.minWidth > this.minHeight){
27783 height = Math.ceil(this.minHeight * width / this.minWidth);
27786 this.thumbEl.setStyle({
27787 width : width + 'px',
27788 height : height + 'px'
27795 setThumbBoxPosition : function()
27797 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27798 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27800 this.thumbEl.setLeft(x);
27801 this.thumbEl.setTop(y);
27805 baseRotateLevel : function()
27807 this.baseRotate = 1;
27810 typeof(this.exif) != 'undefined' &&
27811 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27812 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27814 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27817 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27821 baseScaleLevel : function()
27825 if(this.isDocument){
27827 if(this.baseRotate == 6 || this.baseRotate == 8){
27829 height = this.thumbEl.getHeight();
27830 this.baseScale = height / this.imageEl.OriginWidth;
27832 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27833 width = this.thumbEl.getWidth();
27834 this.baseScale = width / this.imageEl.OriginHeight;
27840 height = this.thumbEl.getHeight();
27841 this.baseScale = height / this.imageEl.OriginHeight;
27843 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27844 width = this.thumbEl.getWidth();
27845 this.baseScale = width / this.imageEl.OriginWidth;
27851 if(this.baseRotate == 6 || this.baseRotate == 8){
27853 width = this.thumbEl.getHeight();
27854 this.baseScale = width / this.imageEl.OriginHeight;
27856 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27857 height = this.thumbEl.getWidth();
27858 this.baseScale = height / this.imageEl.OriginHeight;
27861 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27862 height = this.thumbEl.getWidth();
27863 this.baseScale = height / this.imageEl.OriginHeight;
27865 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27866 width = this.thumbEl.getHeight();
27867 this.baseScale = width / this.imageEl.OriginWidth;
27874 width = this.thumbEl.getWidth();
27875 this.baseScale = width / this.imageEl.OriginWidth;
27877 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27878 height = this.thumbEl.getHeight();
27879 this.baseScale = height / this.imageEl.OriginHeight;
27882 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27884 height = this.thumbEl.getHeight();
27885 this.baseScale = height / this.imageEl.OriginHeight;
27887 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27888 width = this.thumbEl.getWidth();
27889 this.baseScale = width / this.imageEl.OriginWidth;
27897 getScaleLevel : function()
27899 return this.baseScale * Math.pow(1.1, this.scale);
27902 onTouchStart : function(e)
27904 if(!this.canvasLoaded){
27905 this.beforeSelectFile(e);
27909 var touches = e.browserEvent.touches;
27915 if(touches.length == 1){
27916 this.onMouseDown(e);
27920 if(touches.length != 2){
27926 for(var i = 0, finger; finger = touches[i]; i++){
27927 coords.push(finger.pageX, finger.pageY);
27930 var x = Math.pow(coords[0] - coords[2], 2);
27931 var y = Math.pow(coords[1] - coords[3], 2);
27933 this.startDistance = Math.sqrt(x + y);
27935 this.startScale = this.scale;
27937 this.pinching = true;
27938 this.dragable = false;
27942 onTouchMove : function(e)
27944 if(!this.pinching && !this.dragable){
27948 var touches = e.browserEvent.touches;
27955 this.onMouseMove(e);
27961 for(var i = 0, finger; finger = touches[i]; i++){
27962 coords.push(finger.pageX, finger.pageY);
27965 var x = Math.pow(coords[0] - coords[2], 2);
27966 var y = Math.pow(coords[1] - coords[3], 2);
27968 this.endDistance = Math.sqrt(x + y);
27970 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27972 if(!this.zoomable()){
27973 this.scale = this.startScale;
27981 onTouchEnd : function(e)
27983 this.pinching = false;
27984 this.dragable = false;
27988 process : function(file, crop)
27991 this.maskEl.mask(this.loadingText);
27994 this.xhr = new XMLHttpRequest();
27996 file.xhr = this.xhr;
27998 this.xhr.open(this.method, this.url, true);
28001 "Accept": "application/json",
28002 "Cache-Control": "no-cache",
28003 "X-Requested-With": "XMLHttpRequest"
28006 for (var headerName in headers) {
28007 var headerValue = headers[headerName];
28009 this.xhr.setRequestHeader(headerName, headerValue);
28015 this.xhr.onload = function()
28017 _this.xhrOnLoad(_this.xhr);
28020 this.xhr.onerror = function()
28022 _this.xhrOnError(_this.xhr);
28025 var formData = new FormData();
28027 formData.append('returnHTML', 'NO');
28030 formData.append('crop', crop);
28033 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28034 formData.append(this.paramName, file, file.name);
28037 if(typeof(file.filename) != 'undefined'){
28038 formData.append('filename', file.filename);
28041 if(typeof(file.mimetype) != 'undefined'){
28042 formData.append('mimetype', file.mimetype);
28045 if(this.fireEvent('arrange', this, formData) != false){
28046 this.xhr.send(formData);
28050 xhrOnLoad : function(xhr)
28053 this.maskEl.unmask();
28056 if (xhr.readyState !== 4) {
28057 this.fireEvent('exception', this, xhr);
28061 var response = Roo.decode(xhr.responseText);
28063 if(!response.success){
28064 this.fireEvent('exception', this, xhr);
28068 var response = Roo.decode(xhr.responseText);
28070 this.fireEvent('upload', this, response);
28074 xhrOnError : function()
28077 this.maskEl.unmask();
28080 Roo.log('xhr on error');
28082 var response = Roo.decode(xhr.responseText);
28088 prepare : function(file)
28091 this.maskEl.mask(this.loadingText);
28097 if(typeof(file) === 'string'){
28098 this.loadCanvas(file);
28102 if(!file || !this.urlAPI){
28107 this.cropType = file.type;
28111 if(this.fireEvent('prepare', this, this.file) != false){
28113 var reader = new FileReader();
28115 reader.onload = function (e) {
28116 if (e.target.error) {
28117 Roo.log(e.target.error);
28121 var buffer = e.target.result,
28122 dataView = new DataView(buffer),
28124 maxOffset = dataView.byteLength - 4,
28128 if (dataView.getUint16(0) === 0xffd8) {
28129 while (offset < maxOffset) {
28130 markerBytes = dataView.getUint16(offset);
28132 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28133 markerLength = dataView.getUint16(offset + 2) + 2;
28134 if (offset + markerLength > dataView.byteLength) {
28135 Roo.log('Invalid meta data: Invalid segment size.');
28139 if(markerBytes == 0xffe1){
28140 _this.parseExifData(
28147 offset += markerLength;
28157 var url = _this.urlAPI.createObjectURL(_this.file);
28159 _this.loadCanvas(url);
28164 reader.readAsArrayBuffer(this.file);
28170 parseExifData : function(dataView, offset, length)
28172 var tiffOffset = offset + 10,
28176 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28177 // No Exif data, might be XMP data instead
28181 // Check for the ASCII code for "Exif" (0x45786966):
28182 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28183 // No Exif data, might be XMP data instead
28186 if (tiffOffset + 8 > dataView.byteLength) {
28187 Roo.log('Invalid Exif data: Invalid segment size.');
28190 // Check for the two null bytes:
28191 if (dataView.getUint16(offset + 8) !== 0x0000) {
28192 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28195 // Check the byte alignment:
28196 switch (dataView.getUint16(tiffOffset)) {
28198 littleEndian = true;
28201 littleEndian = false;
28204 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28207 // Check for the TIFF tag marker (0x002A):
28208 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28209 Roo.log('Invalid Exif data: Missing TIFF marker.');
28212 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28213 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28215 this.parseExifTags(
28218 tiffOffset + dirOffset,
28223 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28228 if (dirOffset + 6 > dataView.byteLength) {
28229 Roo.log('Invalid Exif data: Invalid directory offset.');
28232 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28233 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28234 if (dirEndOffset + 4 > dataView.byteLength) {
28235 Roo.log('Invalid Exif data: Invalid directory size.');
28238 for (i = 0; i < tagsNumber; i += 1) {
28242 dirOffset + 2 + 12 * i, // tag offset
28246 // Return the offset to the next directory:
28247 return dataView.getUint32(dirEndOffset, littleEndian);
28250 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28252 var tag = dataView.getUint16(offset, littleEndian);
28254 this.exif[tag] = this.getExifValue(
28258 dataView.getUint16(offset + 2, littleEndian), // tag type
28259 dataView.getUint32(offset + 4, littleEndian), // tag length
28264 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28266 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28275 Roo.log('Invalid Exif data: Invalid tag type.');
28279 tagSize = tagType.size * length;
28280 // Determine if the value is contained in the dataOffset bytes,
28281 // or if the value at the dataOffset is a pointer to the actual data:
28282 dataOffset = tagSize > 4 ?
28283 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28284 if (dataOffset + tagSize > dataView.byteLength) {
28285 Roo.log('Invalid Exif data: Invalid data offset.');
28288 if (length === 1) {
28289 return tagType.getValue(dataView, dataOffset, littleEndian);
28292 for (i = 0; i < length; i += 1) {
28293 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28296 if (tagType.ascii) {
28298 // Concatenate the chars:
28299 for (i = 0; i < values.length; i += 1) {
28301 // Ignore the terminating NULL byte(s):
28302 if (c === '\u0000') {
28314 Roo.apply(Roo.bootstrap.UploadCropbox, {
28316 'Orientation': 0x0112
28320 1: 0, //'top-left',
28322 3: 180, //'bottom-right',
28323 // 4: 'bottom-left',
28325 6: 90, //'right-top',
28326 // 7: 'right-bottom',
28327 8: 270 //'left-bottom'
28331 // byte, 8-bit unsigned int:
28333 getValue: function (dataView, dataOffset) {
28334 return dataView.getUint8(dataOffset);
28338 // ascii, 8-bit byte:
28340 getValue: function (dataView, dataOffset) {
28341 return String.fromCharCode(dataView.getUint8(dataOffset));
28346 // short, 16 bit int:
28348 getValue: function (dataView, dataOffset, littleEndian) {
28349 return dataView.getUint16(dataOffset, littleEndian);
28353 // long, 32 bit int:
28355 getValue: function (dataView, dataOffset, littleEndian) {
28356 return dataView.getUint32(dataOffset, littleEndian);
28360 // rational = two long values, first is numerator, second is denominator:
28362 getValue: function (dataView, dataOffset, littleEndian) {
28363 return dataView.getUint32(dataOffset, littleEndian) /
28364 dataView.getUint32(dataOffset + 4, littleEndian);
28368 // slong, 32 bit signed int:
28370 getValue: function (dataView, dataOffset, littleEndian) {
28371 return dataView.getInt32(dataOffset, littleEndian);
28375 // srational, two slongs, first is numerator, second is denominator:
28377 getValue: function (dataView, dataOffset, littleEndian) {
28378 return dataView.getInt32(dataOffset, littleEndian) /
28379 dataView.getInt32(dataOffset + 4, littleEndian);
28389 cls : 'btn-group roo-upload-cropbox-rotate-left',
28390 action : 'rotate-left',
28394 cls : 'btn btn-default',
28395 html : '<i class="fa fa-undo"></i>'
28401 cls : 'btn-group roo-upload-cropbox-picture',
28402 action : 'picture',
28406 cls : 'btn btn-default',
28407 html : '<i class="fa fa-picture-o"></i>'
28413 cls : 'btn-group roo-upload-cropbox-rotate-right',
28414 action : 'rotate-right',
28418 cls : 'btn btn-default',
28419 html : '<i class="fa fa-repeat"></i>'
28427 cls : 'btn-group roo-upload-cropbox-rotate-left',
28428 action : 'rotate-left',
28432 cls : 'btn btn-default',
28433 html : '<i class="fa fa-undo"></i>'
28439 cls : 'btn-group roo-upload-cropbox-download',
28440 action : 'download',
28444 cls : 'btn btn-default',
28445 html : '<i class="fa fa-download"></i>'
28451 cls : 'btn-group roo-upload-cropbox-crop',
28456 cls : 'btn btn-default',
28457 html : '<i class="fa fa-crop"></i>'
28463 cls : 'btn-group roo-upload-cropbox-trash',
28468 cls : 'btn btn-default',
28469 html : '<i class="fa fa-trash"></i>'
28475 cls : 'btn-group roo-upload-cropbox-rotate-right',
28476 action : 'rotate-right',
28480 cls : 'btn btn-default',
28481 html : '<i class="fa fa-repeat"></i>'
28489 cls : 'btn-group roo-upload-cropbox-rotate-left',
28490 action : 'rotate-left',
28494 cls : 'btn btn-default',
28495 html : '<i class="fa fa-undo"></i>'
28501 cls : 'btn-group roo-upload-cropbox-rotate-right',
28502 action : 'rotate-right',
28506 cls : 'btn btn-default',
28507 html : '<i class="fa fa-repeat"></i>'
28520 * @class Roo.bootstrap.DocumentManager
28521 * @extends Roo.bootstrap.Component
28522 * Bootstrap DocumentManager class
28523 * @cfg {String} paramName default 'imageUpload'
28524 * @cfg {String} toolTipName default 'filename'
28525 * @cfg {String} method default POST
28526 * @cfg {String} url action url
28527 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28528 * @cfg {Boolean} multiple multiple upload default true
28529 * @cfg {Number} thumbSize default 300
28530 * @cfg {String} fieldLabel
28531 * @cfg {Number} labelWidth default 4
28532 * @cfg {String} labelAlign (left|top) default left
28533 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28534 * @cfg {Number} labellg set the width of label (1-12)
28535 * @cfg {Number} labelmd set the width of label (1-12)
28536 * @cfg {Number} labelsm set the width of label (1-12)
28537 * @cfg {Number} labelxs set the width of label (1-12)
28540 * Create a new DocumentManager
28541 * @param {Object} config The config object
28544 Roo.bootstrap.DocumentManager = function(config){
28545 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28548 this.delegates = [];
28553 * Fire when initial the DocumentManager
28554 * @param {Roo.bootstrap.DocumentManager} this
28559 * inspect selected file
28560 * @param {Roo.bootstrap.DocumentManager} this
28561 * @param {File} file
28566 * Fire when xhr load exception
28567 * @param {Roo.bootstrap.DocumentManager} this
28568 * @param {XMLHttpRequest} xhr
28570 "exception" : true,
28572 * @event afterupload
28573 * Fire when xhr load exception
28574 * @param {Roo.bootstrap.DocumentManager} this
28575 * @param {XMLHttpRequest} xhr
28577 "afterupload" : true,
28580 * prepare the form data
28581 * @param {Roo.bootstrap.DocumentManager} this
28582 * @param {Object} formData
28587 * Fire when remove the file
28588 * @param {Roo.bootstrap.DocumentManager} this
28589 * @param {Object} file
28594 * Fire after refresh the file
28595 * @param {Roo.bootstrap.DocumentManager} this
28600 * Fire after click the image
28601 * @param {Roo.bootstrap.DocumentManager} this
28602 * @param {Object} file
28607 * Fire when upload a image and editable set to true
28608 * @param {Roo.bootstrap.DocumentManager} this
28609 * @param {Object} file
28613 * @event beforeselectfile
28614 * Fire before select file
28615 * @param {Roo.bootstrap.DocumentManager} this
28617 "beforeselectfile" : true,
28620 * Fire before process file
28621 * @param {Roo.bootstrap.DocumentManager} this
28622 * @param {Object} file
28626 * @event previewrendered
28627 * Fire when preview rendered
28628 * @param {Roo.bootstrap.DocumentManager} this
28629 * @param {Object} file
28631 "previewrendered" : true
28636 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28645 paramName : 'imageUpload',
28646 toolTipName : 'filename',
28649 labelAlign : 'left',
28659 getAutoCreate : function()
28661 var managerWidget = {
28663 cls : 'roo-document-manager',
28667 cls : 'roo-document-manager-selector',
28672 cls : 'roo-document-manager-uploader',
28676 cls : 'roo-document-manager-upload-btn',
28677 html : '<i class="fa fa-plus"></i>'
28688 cls : 'column col-md-12',
28693 if(this.fieldLabel.length){
28698 cls : 'column col-md-12',
28699 html : this.fieldLabel
28703 cls : 'column col-md-12',
28708 if(this.labelAlign == 'left'){
28713 html : this.fieldLabel
28722 if(this.labelWidth > 12){
28723 content[0].style = "width: " + this.labelWidth + 'px';
28726 if(this.labelWidth < 13 && this.labelmd == 0){
28727 this.labelmd = this.labelWidth;
28730 if(this.labellg > 0){
28731 content[0].cls += ' col-lg-' + this.labellg;
28732 content[1].cls += ' col-lg-' + (12 - this.labellg);
28735 if(this.labelmd > 0){
28736 content[0].cls += ' col-md-' + this.labelmd;
28737 content[1].cls += ' col-md-' + (12 - this.labelmd);
28740 if(this.labelsm > 0){
28741 content[0].cls += ' col-sm-' + this.labelsm;
28742 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28745 if(this.labelxs > 0){
28746 content[0].cls += ' col-xs-' + this.labelxs;
28747 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28755 cls : 'row clearfix',
28763 initEvents : function()
28765 this.managerEl = this.el.select('.roo-document-manager', true).first();
28766 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28768 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28769 this.selectorEl.hide();
28772 this.selectorEl.attr('multiple', 'multiple');
28775 this.selectorEl.on('change', this.onFileSelected, this);
28777 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28778 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28780 this.uploader.on('click', this.onUploaderClick, this);
28782 this.renderProgressDialog();
28786 window.addEventListener("resize", function() { _this.refresh(); } );
28788 this.fireEvent('initial', this);
28791 renderProgressDialog : function()
28795 this.progressDialog = new Roo.bootstrap.Modal({
28796 cls : 'roo-document-manager-progress-dialog',
28797 allow_close : false,
28807 btnclick : function() {
28808 _this.uploadCancel();
28814 this.progressDialog.render(Roo.get(document.body));
28816 this.progress = new Roo.bootstrap.Progress({
28817 cls : 'roo-document-manager-progress',
28822 this.progress.render(this.progressDialog.getChildContainer());
28824 this.progressBar = new Roo.bootstrap.ProgressBar({
28825 cls : 'roo-document-manager-progress-bar',
28828 aria_valuemax : 12,
28832 this.progressBar.render(this.progress.getChildContainer());
28835 onUploaderClick : function(e)
28837 e.preventDefault();
28839 if(this.fireEvent('beforeselectfile', this) != false){
28840 this.selectorEl.dom.click();
28845 onFileSelected : function(e)
28847 e.preventDefault();
28849 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28853 Roo.each(this.selectorEl.dom.files, function(file){
28854 if(this.fireEvent('inspect', this, file) != false){
28855 this.files.push(file);
28865 this.selectorEl.dom.value = '';
28867 if(!this.files || !this.files.length){
28871 if(this.boxes > 0 && this.files.length > this.boxes){
28872 this.files = this.files.slice(0, this.boxes);
28875 this.uploader.show();
28877 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28878 this.uploader.hide();
28887 Roo.each(this.files, function(file){
28889 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28890 var f = this.renderPreview(file);
28895 if(file.type.indexOf('image') != -1){
28896 this.delegates.push(
28898 _this.process(file);
28899 }).createDelegate(this)
28907 _this.process(file);
28908 }).createDelegate(this)
28913 this.files = files;
28915 this.delegates = this.delegates.concat(docs);
28917 if(!this.delegates.length){
28922 this.progressBar.aria_valuemax = this.delegates.length;
28929 arrange : function()
28931 if(!this.delegates.length){
28932 this.progressDialog.hide();
28937 var delegate = this.delegates.shift();
28939 this.progressDialog.show();
28941 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28943 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28948 refresh : function()
28950 this.uploader.show();
28952 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28953 this.uploader.hide();
28956 Roo.isTouch ? this.closable(false) : this.closable(true);
28958 this.fireEvent('refresh', this);
28961 onRemove : function(e, el, o)
28963 e.preventDefault();
28965 this.fireEvent('remove', this, o);
28969 remove : function(o)
28973 Roo.each(this.files, function(file){
28974 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28983 this.files = files;
28990 Roo.each(this.files, function(file){
28995 file.target.remove();
29004 onClick : function(e, el, o)
29006 e.preventDefault();
29008 this.fireEvent('click', this, o);
29012 closable : function(closable)
29014 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29016 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29028 xhrOnLoad : function(xhr)
29030 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29034 if (xhr.readyState !== 4) {
29036 this.fireEvent('exception', this, xhr);
29040 var response = Roo.decode(xhr.responseText);
29042 if(!response.success){
29044 this.fireEvent('exception', this, xhr);
29048 var file = this.renderPreview(response.data);
29050 this.files.push(file);
29054 this.fireEvent('afterupload', this, xhr);
29058 xhrOnError : function(xhr)
29060 Roo.log('xhr on error');
29062 var response = Roo.decode(xhr.responseText);
29069 process : function(file)
29071 if(this.fireEvent('process', this, file) !== false){
29072 if(this.editable && file.type.indexOf('image') != -1){
29073 this.fireEvent('edit', this, file);
29077 this.uploadStart(file, false);
29084 uploadStart : function(file, crop)
29086 this.xhr = new XMLHttpRequest();
29088 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29093 file.xhr = this.xhr;
29095 this.managerEl.createChild({
29097 cls : 'roo-document-manager-loading',
29101 tooltip : file.name,
29102 cls : 'roo-document-manager-thumb',
29103 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29109 this.xhr.open(this.method, this.url, true);
29112 "Accept": "application/json",
29113 "Cache-Control": "no-cache",
29114 "X-Requested-With": "XMLHttpRequest"
29117 for (var headerName in headers) {
29118 var headerValue = headers[headerName];
29120 this.xhr.setRequestHeader(headerName, headerValue);
29126 this.xhr.onload = function()
29128 _this.xhrOnLoad(_this.xhr);
29131 this.xhr.onerror = function()
29133 _this.xhrOnError(_this.xhr);
29136 var formData = new FormData();
29138 formData.append('returnHTML', 'NO');
29141 formData.append('crop', crop);
29144 formData.append(this.paramName, file, file.name);
29151 if(this.fireEvent('prepare', this, formData, options) != false){
29153 if(options.manually){
29157 this.xhr.send(formData);
29161 this.uploadCancel();
29164 uploadCancel : function()
29170 this.delegates = [];
29172 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29179 renderPreview : function(file)
29181 if(typeof(file.target) != 'undefined' && file.target){
29185 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29187 var previewEl = this.managerEl.createChild({
29189 cls : 'roo-document-manager-preview',
29193 tooltip : file[this.toolTipName],
29194 cls : 'roo-document-manager-thumb',
29195 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29200 html : '<i class="fa fa-times-circle"></i>'
29205 var close = previewEl.select('button.close', true).first();
29207 close.on('click', this.onRemove, this, file);
29209 file.target = previewEl;
29211 var image = previewEl.select('img', true).first();
29215 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29217 image.on('click', this.onClick, this, file);
29219 this.fireEvent('previewrendered', this, file);
29225 onPreviewLoad : function(file, image)
29227 if(typeof(file.target) == 'undefined' || !file.target){
29231 var width = image.dom.naturalWidth || image.dom.width;
29232 var height = image.dom.naturalHeight || image.dom.height;
29234 if(width > height){
29235 file.target.addClass('wide');
29239 file.target.addClass('tall');
29244 uploadFromSource : function(file, crop)
29246 this.xhr = new XMLHttpRequest();
29248 this.managerEl.createChild({
29250 cls : 'roo-document-manager-loading',
29254 tooltip : file.name,
29255 cls : 'roo-document-manager-thumb',
29256 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29262 this.xhr.open(this.method, this.url, true);
29265 "Accept": "application/json",
29266 "Cache-Control": "no-cache",
29267 "X-Requested-With": "XMLHttpRequest"
29270 for (var headerName in headers) {
29271 var headerValue = headers[headerName];
29273 this.xhr.setRequestHeader(headerName, headerValue);
29279 this.xhr.onload = function()
29281 _this.xhrOnLoad(_this.xhr);
29284 this.xhr.onerror = function()
29286 _this.xhrOnError(_this.xhr);
29289 var formData = new FormData();
29291 formData.append('returnHTML', 'NO');
29293 formData.append('crop', crop);
29295 if(typeof(file.filename) != 'undefined'){
29296 formData.append('filename', file.filename);
29299 if(typeof(file.mimetype) != 'undefined'){
29300 formData.append('mimetype', file.mimetype);
29305 if(this.fireEvent('prepare', this, formData) != false){
29306 this.xhr.send(formData);
29316 * @class Roo.bootstrap.DocumentViewer
29317 * @extends Roo.bootstrap.Component
29318 * Bootstrap DocumentViewer class
29319 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29320 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29323 * Create a new DocumentViewer
29324 * @param {Object} config The config object
29327 Roo.bootstrap.DocumentViewer = function(config){
29328 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29333 * Fire after initEvent
29334 * @param {Roo.bootstrap.DocumentViewer} this
29340 * @param {Roo.bootstrap.DocumentViewer} this
29345 * Fire after download button
29346 * @param {Roo.bootstrap.DocumentViewer} this
29351 * Fire after trash button
29352 * @param {Roo.bootstrap.DocumentViewer} this
29359 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29361 showDownload : true,
29365 getAutoCreate : function()
29369 cls : 'roo-document-viewer',
29373 cls : 'roo-document-viewer-body',
29377 cls : 'roo-document-viewer-thumb',
29381 cls : 'roo-document-viewer-image'
29389 cls : 'roo-document-viewer-footer',
29392 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29396 cls : 'btn-group roo-document-viewer-download',
29400 cls : 'btn btn-default',
29401 html : '<i class="fa fa-download"></i>'
29407 cls : 'btn-group roo-document-viewer-trash',
29411 cls : 'btn btn-default',
29412 html : '<i class="fa fa-trash"></i>'
29425 initEvents : function()
29427 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29428 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29430 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29431 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29433 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29434 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29436 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29437 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29439 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29440 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29442 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29443 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29445 this.bodyEl.on('click', this.onClick, this);
29446 this.downloadBtn.on('click', this.onDownload, this);
29447 this.trashBtn.on('click', this.onTrash, this);
29449 this.downloadBtn.hide();
29450 this.trashBtn.hide();
29452 if(this.showDownload){
29453 this.downloadBtn.show();
29456 if(this.showTrash){
29457 this.trashBtn.show();
29460 if(!this.showDownload && !this.showTrash) {
29461 this.footerEl.hide();
29466 initial : function()
29468 this.fireEvent('initial', this);
29472 onClick : function(e)
29474 e.preventDefault();
29476 this.fireEvent('click', this);
29479 onDownload : function(e)
29481 e.preventDefault();
29483 this.fireEvent('download', this);
29486 onTrash : function(e)
29488 e.preventDefault();
29490 this.fireEvent('trash', this);
29502 * @class Roo.bootstrap.NavProgressBar
29503 * @extends Roo.bootstrap.Component
29504 * Bootstrap NavProgressBar class
29507 * Create a new nav progress bar
29508 * @param {Object} config The config object
29511 Roo.bootstrap.NavProgressBar = function(config){
29512 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29514 this.bullets = this.bullets || [];
29516 // Roo.bootstrap.NavProgressBar.register(this);
29520 * Fires when the active item changes
29521 * @param {Roo.bootstrap.NavProgressBar} this
29522 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29523 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29530 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29535 getAutoCreate : function()
29537 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29541 cls : 'roo-navigation-bar-group',
29545 cls : 'roo-navigation-top-bar'
29549 cls : 'roo-navigation-bullets-bar',
29553 cls : 'roo-navigation-bar'
29560 cls : 'roo-navigation-bottom-bar'
29570 initEvents: function()
29575 onRender : function(ct, position)
29577 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29579 if(this.bullets.length){
29580 Roo.each(this.bullets, function(b){
29589 addItem : function(cfg)
29591 var item = new Roo.bootstrap.NavProgressItem(cfg);
29593 item.parentId = this.id;
29594 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29597 var top = new Roo.bootstrap.Element({
29599 cls : 'roo-navigation-bar-text'
29602 var bottom = new Roo.bootstrap.Element({
29604 cls : 'roo-navigation-bar-text'
29607 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29608 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29610 var topText = new Roo.bootstrap.Element({
29612 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29615 var bottomText = new Roo.bootstrap.Element({
29617 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29620 topText.onRender(top.el, null);
29621 bottomText.onRender(bottom.el, null);
29624 item.bottomEl = bottom;
29627 this.barItems.push(item);
29632 getActive : function()
29634 var active = false;
29636 Roo.each(this.barItems, function(v){
29638 if (!v.isActive()) {
29650 setActiveItem : function(item)
29654 Roo.each(this.barItems, function(v){
29655 if (v.rid == item.rid) {
29659 if (v.isActive()) {
29660 v.setActive(false);
29665 item.setActive(true);
29667 this.fireEvent('changed', this, item, prev);
29670 getBarItem: function(rid)
29674 Roo.each(this.barItems, function(e) {
29675 if (e.rid != rid) {
29686 indexOfItem : function(item)
29690 Roo.each(this.barItems, function(v, i){
29692 if (v.rid != item.rid) {
29703 setActiveNext : function()
29705 var i = this.indexOfItem(this.getActive());
29707 if (i > this.barItems.length) {
29711 this.setActiveItem(this.barItems[i+1]);
29714 setActivePrev : function()
29716 var i = this.indexOfItem(this.getActive());
29722 this.setActiveItem(this.barItems[i-1]);
29725 format : function()
29727 if(!this.barItems.length){
29731 var width = 100 / this.barItems.length;
29733 Roo.each(this.barItems, function(i){
29734 i.el.setStyle('width', width + '%');
29735 i.topEl.el.setStyle('width', width + '%');
29736 i.bottomEl.el.setStyle('width', width + '%');
29745 * Nav Progress Item
29750 * @class Roo.bootstrap.NavProgressItem
29751 * @extends Roo.bootstrap.Component
29752 * Bootstrap NavProgressItem class
29753 * @cfg {String} rid the reference id
29754 * @cfg {Boolean} active (true|false) Is item active default false
29755 * @cfg {Boolean} disabled (true|false) Is item active default false
29756 * @cfg {String} html
29757 * @cfg {String} position (top|bottom) text position default bottom
29758 * @cfg {String} icon show icon instead of number
29761 * Create a new NavProgressItem
29762 * @param {Object} config The config object
29764 Roo.bootstrap.NavProgressItem = function(config){
29765 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29770 * The raw click event for the entire grid.
29771 * @param {Roo.bootstrap.NavProgressItem} this
29772 * @param {Roo.EventObject} e
29779 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29785 position : 'bottom',
29788 getAutoCreate : function()
29790 var iconCls = 'roo-navigation-bar-item-icon';
29792 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29796 cls: 'roo-navigation-bar-item',
29806 cfg.cls += ' active';
29809 cfg.cls += ' disabled';
29815 disable : function()
29817 this.setDisabled(true);
29820 enable : function()
29822 this.setDisabled(false);
29825 initEvents: function()
29827 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29829 this.iconEl.on('click', this.onClick, this);
29832 onClick : function(e)
29834 e.preventDefault();
29840 if(this.fireEvent('click', this, e) === false){
29844 this.parent().setActiveItem(this);
29847 isActive: function ()
29849 return this.active;
29852 setActive : function(state)
29854 if(this.active == state){
29858 this.active = state;
29861 this.el.addClass('active');
29865 this.el.removeClass('active');
29870 setDisabled : function(state)
29872 if(this.disabled == state){
29876 this.disabled = state;
29879 this.el.addClass('disabled');
29883 this.el.removeClass('disabled');
29886 tooltipEl : function()
29888 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29901 * @class Roo.bootstrap.FieldLabel
29902 * @extends Roo.bootstrap.Component
29903 * Bootstrap FieldLabel class
29904 * @cfg {String} html contents of the element
29905 * @cfg {String} tag tag of the element default label
29906 * @cfg {String} cls class of the element
29907 * @cfg {String} target label target
29908 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29909 * @cfg {String} invalidClass default "text-warning"
29910 * @cfg {String} validClass default "text-success"
29911 * @cfg {String} iconTooltip default "This field is required"
29912 * @cfg {String} indicatorpos (left|right) default left
29915 * Create a new FieldLabel
29916 * @param {Object} config The config object
29919 Roo.bootstrap.FieldLabel = function(config){
29920 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29925 * Fires after the field has been marked as invalid.
29926 * @param {Roo.form.FieldLabel} this
29927 * @param {String} msg The validation message
29932 * Fires after the field has been validated with no errors.
29933 * @param {Roo.form.FieldLabel} this
29939 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29946 invalidClass : 'has-warning',
29947 validClass : 'has-success',
29948 iconTooltip : 'This field is required',
29949 indicatorpos : 'left',
29951 getAutoCreate : function(){
29955 cls : 'roo-bootstrap-field-label ' + this.cls,
29960 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29961 tooltip : this.iconTooltip
29970 if(this.indicatorpos == 'right'){
29973 cls : 'roo-bootstrap-field-label ' + this.cls,
29982 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29983 tooltip : this.iconTooltip
29992 initEvents: function()
29994 Roo.bootstrap.Element.superclass.initEvents.call(this);
29996 this.indicator = this.indicatorEl();
29998 if(this.indicator){
29999 this.indicator.removeClass('visible');
30000 this.indicator.addClass('invisible');
30003 Roo.bootstrap.FieldLabel.register(this);
30006 indicatorEl : function()
30008 var indicator = this.el.select('i.roo-required-indicator',true).first();
30019 * Mark this field as valid
30021 markValid : function()
30023 if(this.indicator){
30024 this.indicator.removeClass('visible');
30025 this.indicator.addClass('invisible');
30028 this.el.removeClass(this.invalidClass);
30030 this.el.addClass(this.validClass);
30032 this.fireEvent('valid', this);
30036 * Mark this field as invalid
30037 * @param {String} msg The validation message
30039 markInvalid : function(msg)
30041 if(this.indicator){
30042 this.indicator.removeClass('invisible');
30043 this.indicator.addClass('visible');
30046 this.el.removeClass(this.validClass);
30048 this.el.addClass(this.invalidClass);
30050 this.fireEvent('invalid', this, msg);
30056 Roo.apply(Roo.bootstrap.FieldLabel, {
30061 * register a FieldLabel Group
30062 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30064 register : function(label)
30066 if(this.groups.hasOwnProperty(label.target)){
30070 this.groups[label.target] = label;
30074 * fetch a FieldLabel Group based on the target
30075 * @param {string} target
30076 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30078 get: function(target) {
30079 if (typeof(this.groups[target]) == 'undefined') {
30083 return this.groups[target] ;
30092 * page DateSplitField.
30098 * @class Roo.bootstrap.DateSplitField
30099 * @extends Roo.bootstrap.Component
30100 * Bootstrap DateSplitField class
30101 * @cfg {string} fieldLabel - the label associated
30102 * @cfg {Number} labelWidth set the width of label (0-12)
30103 * @cfg {String} labelAlign (top|left)
30104 * @cfg {Boolean} dayAllowBlank (true|false) default false
30105 * @cfg {Boolean} monthAllowBlank (true|false) default false
30106 * @cfg {Boolean} yearAllowBlank (true|false) default false
30107 * @cfg {string} dayPlaceholder
30108 * @cfg {string} monthPlaceholder
30109 * @cfg {string} yearPlaceholder
30110 * @cfg {string} dayFormat default 'd'
30111 * @cfg {string} monthFormat default 'm'
30112 * @cfg {string} yearFormat default 'Y'
30113 * @cfg {Number} labellg set the width of label (1-12)
30114 * @cfg {Number} labelmd set the width of label (1-12)
30115 * @cfg {Number} labelsm set the width of label (1-12)
30116 * @cfg {Number} labelxs set the width of label (1-12)
30120 * Create a new DateSplitField
30121 * @param {Object} config The config object
30124 Roo.bootstrap.DateSplitField = function(config){
30125 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30131 * getting the data of years
30132 * @param {Roo.bootstrap.DateSplitField} this
30133 * @param {Object} years
30138 * getting the data of days
30139 * @param {Roo.bootstrap.DateSplitField} this
30140 * @param {Object} days
30145 * Fires after the field has been marked as invalid.
30146 * @param {Roo.form.Field} this
30147 * @param {String} msg The validation message
30152 * Fires after the field has been validated with no errors.
30153 * @param {Roo.form.Field} this
30159 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30162 labelAlign : 'top',
30164 dayAllowBlank : false,
30165 monthAllowBlank : false,
30166 yearAllowBlank : false,
30167 dayPlaceholder : '',
30168 monthPlaceholder : '',
30169 yearPlaceholder : '',
30173 isFormField : true,
30179 getAutoCreate : function()
30183 cls : 'row roo-date-split-field-group',
30188 cls : 'form-hidden-field roo-date-split-field-group-value',
30194 var labelCls = 'col-md-12';
30195 var contentCls = 'col-md-4';
30197 if(this.fieldLabel){
30201 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30205 html : this.fieldLabel
30210 if(this.labelAlign == 'left'){
30212 if(this.labelWidth > 12){
30213 label.style = "width: " + this.labelWidth + 'px';
30216 if(this.labelWidth < 13 && this.labelmd == 0){
30217 this.labelmd = this.labelWidth;
30220 if(this.labellg > 0){
30221 labelCls = ' col-lg-' + this.labellg;
30222 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30225 if(this.labelmd > 0){
30226 labelCls = ' col-md-' + this.labelmd;
30227 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30230 if(this.labelsm > 0){
30231 labelCls = ' col-sm-' + this.labelsm;
30232 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30235 if(this.labelxs > 0){
30236 labelCls = ' col-xs-' + this.labelxs;
30237 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30241 label.cls += ' ' + labelCls;
30243 cfg.cn.push(label);
30246 Roo.each(['day', 'month', 'year'], function(t){
30249 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30256 inputEl: function ()
30258 return this.el.select('.roo-date-split-field-group-value', true).first();
30261 onRender : function(ct, position)
30265 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30267 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30269 this.dayField = new Roo.bootstrap.ComboBox({
30270 allowBlank : this.dayAllowBlank,
30271 alwaysQuery : true,
30272 displayField : 'value',
30275 forceSelection : true,
30277 placeholder : this.dayPlaceholder,
30278 selectOnFocus : true,
30279 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30280 triggerAction : 'all',
30282 valueField : 'value',
30283 store : new Roo.data.SimpleStore({
30284 data : (function() {
30286 _this.fireEvent('days', _this, days);
30289 fields : [ 'value' ]
30292 select : function (_self, record, index)
30294 _this.setValue(_this.getValue());
30299 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30301 this.monthField = new Roo.bootstrap.MonthField({
30302 after : '<i class=\"fa fa-calendar\"></i>',
30303 allowBlank : this.monthAllowBlank,
30304 placeholder : this.monthPlaceholder,
30307 render : function (_self)
30309 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30310 e.preventDefault();
30314 select : function (_self, oldvalue, newvalue)
30316 _this.setValue(_this.getValue());
30321 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30323 this.yearField = new Roo.bootstrap.ComboBox({
30324 allowBlank : this.yearAllowBlank,
30325 alwaysQuery : true,
30326 displayField : 'value',
30329 forceSelection : true,
30331 placeholder : this.yearPlaceholder,
30332 selectOnFocus : true,
30333 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30334 triggerAction : 'all',
30336 valueField : 'value',
30337 store : new Roo.data.SimpleStore({
30338 data : (function() {
30340 _this.fireEvent('years', _this, years);
30343 fields : [ 'value' ]
30346 select : function (_self, record, index)
30348 _this.setValue(_this.getValue());
30353 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30356 setValue : function(v, format)
30358 this.inputEl.dom.value = v;
30360 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30362 var d = Date.parseDate(v, f);
30369 this.setDay(d.format(this.dayFormat));
30370 this.setMonth(d.format(this.monthFormat));
30371 this.setYear(d.format(this.yearFormat));
30378 setDay : function(v)
30380 this.dayField.setValue(v);
30381 this.inputEl.dom.value = this.getValue();
30386 setMonth : function(v)
30388 this.monthField.setValue(v, true);
30389 this.inputEl.dom.value = this.getValue();
30394 setYear : function(v)
30396 this.yearField.setValue(v);
30397 this.inputEl.dom.value = this.getValue();
30402 getDay : function()
30404 return this.dayField.getValue();
30407 getMonth : function()
30409 return this.monthField.getValue();
30412 getYear : function()
30414 return this.yearField.getValue();
30417 getValue : function()
30419 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30421 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30431 this.inputEl.dom.value = '';
30436 validate : function()
30438 var d = this.dayField.validate();
30439 var m = this.monthField.validate();
30440 var y = this.yearField.validate();
30445 (!this.dayAllowBlank && !d) ||
30446 (!this.monthAllowBlank && !m) ||
30447 (!this.yearAllowBlank && !y)
30452 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30461 this.markInvalid();
30466 markValid : function()
30469 var label = this.el.select('label', true).first();
30470 var icon = this.el.select('i.fa-star', true).first();
30476 this.fireEvent('valid', this);
30480 * Mark this field as invalid
30481 * @param {String} msg The validation message
30483 markInvalid : function(msg)
30486 var label = this.el.select('label', true).first();
30487 var icon = this.el.select('i.fa-star', true).first();
30489 if(label && !icon){
30490 this.el.select('.roo-date-split-field-label', true).createChild({
30492 cls : 'text-danger fa fa-lg fa-star',
30493 tooltip : 'This field is required',
30494 style : 'margin-right:5px;'
30498 this.fireEvent('invalid', this, msg);
30501 clearInvalid : function()
30503 var label = this.el.select('label', true).first();
30504 var icon = this.el.select('i.fa-star', true).first();
30510 this.fireEvent('valid', this);
30513 getName: function()
30523 * http://masonry.desandro.com
30525 * The idea is to render all the bricks based on vertical width...
30527 * The original code extends 'outlayer' - we might need to use that....
30533 * @class Roo.bootstrap.LayoutMasonry
30534 * @extends Roo.bootstrap.Component
30535 * Bootstrap Layout Masonry class
30538 * Create a new Element
30539 * @param {Object} config The config object
30542 Roo.bootstrap.LayoutMasonry = function(config){
30544 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30548 Roo.bootstrap.LayoutMasonry.register(this);
30554 * Fire after layout the items
30555 * @param {Roo.bootstrap.LayoutMasonry} this
30556 * @param {Roo.EventObject} e
30563 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30566 * @cfg {Boolean} isLayoutInstant = no animation?
30568 isLayoutInstant : false, // needed?
30571 * @cfg {Number} boxWidth width of the columns
30576 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30581 * @cfg {Number} padWidth padding below box..
30586 * @cfg {Number} gutter gutter width..
30591 * @cfg {Number} maxCols maximum number of columns
30597 * @cfg {Boolean} isAutoInitial defalut true
30599 isAutoInitial : true,
30604 * @cfg {Boolean} isHorizontal defalut false
30606 isHorizontal : false,
30608 currentSize : null,
30614 bricks: null, //CompositeElement
30618 _isLayoutInited : false,
30620 // isAlternative : false, // only use for vertical layout...
30623 * @cfg {Number} alternativePadWidth padding below box..
30625 alternativePadWidth : 50,
30627 selectedBrick : [],
30629 getAutoCreate : function(){
30631 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30635 cls: 'blog-masonary-wrapper ' + this.cls,
30637 cls : 'mas-boxes masonary'
30644 getChildContainer: function( )
30646 if (this.boxesEl) {
30647 return this.boxesEl;
30650 this.boxesEl = this.el.select('.mas-boxes').first();
30652 return this.boxesEl;
30656 initEvents : function()
30660 if(this.isAutoInitial){
30661 Roo.log('hook children rendered');
30662 this.on('childrenrendered', function() {
30663 Roo.log('children rendered');
30669 initial : function()
30671 this.selectedBrick = [];
30673 this.currentSize = this.el.getBox(true);
30675 Roo.EventManager.onWindowResize(this.resize, this);
30677 if(!this.isAutoInitial){
30685 //this.layout.defer(500,this);
30689 resize : function()
30691 var cs = this.el.getBox(true);
30694 this.currentSize.width == cs.width &&
30695 this.currentSize.x == cs.x &&
30696 this.currentSize.height == cs.height &&
30697 this.currentSize.y == cs.y
30699 Roo.log("no change in with or X or Y");
30703 this.currentSize = cs;
30709 layout : function()
30711 this._resetLayout();
30713 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30715 this.layoutItems( isInstant );
30717 this._isLayoutInited = true;
30719 this.fireEvent('layout', this);
30723 _resetLayout : function()
30725 if(this.isHorizontal){
30726 this.horizontalMeasureColumns();
30730 this.verticalMeasureColumns();
30734 verticalMeasureColumns : function()
30736 this.getContainerWidth();
30738 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30739 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30743 var boxWidth = this.boxWidth + this.padWidth;
30745 if(this.containerWidth < this.boxWidth){
30746 boxWidth = this.containerWidth
30749 var containerWidth = this.containerWidth;
30751 var cols = Math.floor(containerWidth / boxWidth);
30753 this.cols = Math.max( cols, 1 );
30755 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30757 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30759 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30761 this.colWidth = boxWidth + avail - this.padWidth;
30763 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30764 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30767 horizontalMeasureColumns : function()
30769 this.getContainerWidth();
30771 var boxWidth = this.boxWidth;
30773 if(this.containerWidth < boxWidth){
30774 boxWidth = this.containerWidth;
30777 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30779 this.el.setHeight(boxWidth);
30783 getContainerWidth : function()
30785 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30788 layoutItems : function( isInstant )
30790 Roo.log(this.bricks);
30792 var items = Roo.apply([], this.bricks);
30794 if(this.isHorizontal){
30795 this._horizontalLayoutItems( items , isInstant );
30799 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30800 // this._verticalAlternativeLayoutItems( items , isInstant );
30804 this._verticalLayoutItems( items , isInstant );
30808 _verticalLayoutItems : function ( items , isInstant)
30810 if ( !items || !items.length ) {
30815 ['xs', 'xs', 'xs', 'tall'],
30816 ['xs', 'xs', 'tall'],
30817 ['xs', 'xs', 'sm'],
30818 ['xs', 'xs', 'xs'],
30824 ['sm', 'xs', 'xs'],
30828 ['tall', 'xs', 'xs', 'xs'],
30829 ['tall', 'xs', 'xs'],
30841 Roo.each(items, function(item, k){
30843 switch (item.size) {
30844 // these layouts take up a full box,
30855 boxes.push([item]);
30878 var filterPattern = function(box, length)
30886 var pattern = box.slice(0, length);
30890 Roo.each(pattern, function(i){
30891 format.push(i.size);
30894 Roo.each(standard, function(s){
30896 if(String(s) != String(format)){
30905 if(!match && length == 1){
30910 filterPattern(box, length - 1);
30914 queue.push(pattern);
30916 box = box.slice(length, box.length);
30918 filterPattern(box, 4);
30924 Roo.each(boxes, function(box, k){
30930 if(box.length == 1){
30935 filterPattern(box, 4);
30939 this._processVerticalLayoutQueue( queue, isInstant );
30943 // _verticalAlternativeLayoutItems : function( items , isInstant )
30945 // if ( !items || !items.length ) {
30949 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30953 _horizontalLayoutItems : function ( items , isInstant)
30955 if ( !items || !items.length || items.length < 3) {
30961 var eItems = items.slice(0, 3);
30963 items = items.slice(3, items.length);
30966 ['xs', 'xs', 'xs', 'wide'],
30967 ['xs', 'xs', 'wide'],
30968 ['xs', 'xs', 'sm'],
30969 ['xs', 'xs', 'xs'],
30975 ['sm', 'xs', 'xs'],
30979 ['wide', 'xs', 'xs', 'xs'],
30980 ['wide', 'xs', 'xs'],
30993 Roo.each(items, function(item, k){
30995 switch (item.size) {
31006 boxes.push([item]);
31030 var filterPattern = function(box, length)
31038 var pattern = box.slice(0, length);
31042 Roo.each(pattern, function(i){
31043 format.push(i.size);
31046 Roo.each(standard, function(s){
31048 if(String(s) != String(format)){
31057 if(!match && length == 1){
31062 filterPattern(box, length - 1);
31066 queue.push(pattern);
31068 box = box.slice(length, box.length);
31070 filterPattern(box, 4);
31076 Roo.each(boxes, function(box, k){
31082 if(box.length == 1){
31087 filterPattern(box, 4);
31094 var pos = this.el.getBox(true);
31098 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31100 var hit_end = false;
31102 Roo.each(queue, function(box){
31106 Roo.each(box, function(b){
31108 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31118 Roo.each(box, function(b){
31120 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31123 mx = Math.max(mx, b.x);
31127 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31131 Roo.each(box, function(b){
31133 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31147 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31150 /** Sets position of item in DOM
31151 * @param {Element} item
31152 * @param {Number} x - horizontal position
31153 * @param {Number} y - vertical position
31154 * @param {Boolean} isInstant - disables transitions
31156 _processVerticalLayoutQueue : function( queue, isInstant )
31158 var pos = this.el.getBox(true);
31163 for (var i = 0; i < this.cols; i++){
31167 Roo.each(queue, function(box, k){
31169 var col = k % this.cols;
31171 Roo.each(box, function(b,kk){
31173 b.el.position('absolute');
31175 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31176 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31178 if(b.size == 'md-left' || b.size == 'md-right'){
31179 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31180 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31183 b.el.setWidth(width);
31184 b.el.setHeight(height);
31186 b.el.select('iframe',true).setSize(width,height);
31190 for (var i = 0; i < this.cols; i++){
31192 if(maxY[i] < maxY[col]){
31197 col = Math.min(col, i);
31201 x = pos.x + col * (this.colWidth + this.padWidth);
31205 var positions = [];
31207 switch (box.length){
31209 positions = this.getVerticalOneBoxColPositions(x, y, box);
31212 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31215 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31218 positions = this.getVerticalFourBoxColPositions(x, y, box);
31224 Roo.each(box, function(b,kk){
31226 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31228 var sz = b.el.getSize();
31230 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31238 for (var i = 0; i < this.cols; i++){
31239 mY = Math.max(mY, maxY[i]);
31242 this.el.setHeight(mY - pos.y);
31246 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31248 // var pos = this.el.getBox(true);
31251 // var maxX = pos.right;
31253 // var maxHeight = 0;
31255 // Roo.each(items, function(item, k){
31259 // item.el.position('absolute');
31261 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31263 // item.el.setWidth(width);
31265 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31267 // item.el.setHeight(height);
31270 // item.el.setXY([x, y], isInstant ? false : true);
31272 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31275 // y = y + height + this.alternativePadWidth;
31277 // maxHeight = maxHeight + height + this.alternativePadWidth;
31281 // this.el.setHeight(maxHeight);
31285 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31287 var pos = this.el.getBox(true);
31292 var maxX = pos.right;
31294 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31296 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31298 Roo.each(queue, function(box, k){
31300 Roo.each(box, function(b, kk){
31302 b.el.position('absolute');
31304 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31305 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31307 if(b.size == 'md-left' || b.size == 'md-right'){
31308 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31309 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31312 b.el.setWidth(width);
31313 b.el.setHeight(height);
31321 var positions = [];
31323 switch (box.length){
31325 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31328 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31331 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31334 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31340 Roo.each(box, function(b,kk){
31342 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31344 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31352 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31354 Roo.each(eItems, function(b,k){
31356 b.size = (k == 0) ? 'sm' : 'xs';
31357 b.x = (k == 0) ? 2 : 1;
31358 b.y = (k == 0) ? 2 : 1;
31360 b.el.position('absolute');
31362 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31364 b.el.setWidth(width);
31366 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31368 b.el.setHeight(height);
31372 var positions = [];
31375 x : maxX - this.unitWidth * 2 - this.gutter,
31380 x : maxX - this.unitWidth,
31381 y : minY + (this.unitWidth + this.gutter) * 2
31385 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31389 Roo.each(eItems, function(b,k){
31391 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31397 getVerticalOneBoxColPositions : function(x, y, box)
31401 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31403 if(box[0].size == 'md-left'){
31407 if(box[0].size == 'md-right'){
31412 x : x + (this.unitWidth + this.gutter) * rand,
31419 getVerticalTwoBoxColPositions : function(x, y, box)
31423 if(box[0].size == 'xs'){
31427 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31431 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31445 x : x + (this.unitWidth + this.gutter) * 2,
31446 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31453 getVerticalThreeBoxColPositions : function(x, y, box)
31457 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31465 x : x + (this.unitWidth + this.gutter) * 1,
31470 x : x + (this.unitWidth + this.gutter) * 2,
31478 if(box[0].size == 'xs' && box[1].size == 'xs'){
31487 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31491 x : x + (this.unitWidth + this.gutter) * 1,
31505 x : x + (this.unitWidth + this.gutter) * 2,
31510 x : x + (this.unitWidth + this.gutter) * 2,
31511 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31518 getVerticalFourBoxColPositions : function(x, y, box)
31522 if(box[0].size == 'xs'){
31531 y : y + (this.unitHeight + this.gutter) * 1
31536 y : y + (this.unitHeight + this.gutter) * 2
31540 x : x + (this.unitWidth + this.gutter) * 1,
31554 x : x + (this.unitWidth + this.gutter) * 2,
31559 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31560 y : y + (this.unitHeight + this.gutter) * 1
31564 x : x + (this.unitWidth + this.gutter) * 2,
31565 y : y + (this.unitWidth + this.gutter) * 2
31572 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31576 if(box[0].size == 'md-left'){
31578 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31585 if(box[0].size == 'md-right'){
31587 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31588 y : minY + (this.unitWidth + this.gutter) * 1
31594 var rand = Math.floor(Math.random() * (4 - box[0].y));
31597 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31598 y : minY + (this.unitWidth + this.gutter) * rand
31605 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31609 if(box[0].size == 'xs'){
31612 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31617 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31618 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31626 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31631 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31632 y : minY + (this.unitWidth + this.gutter) * 2
31639 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31643 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31646 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31651 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31652 y : minY + (this.unitWidth + this.gutter) * 1
31656 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31657 y : minY + (this.unitWidth + this.gutter) * 2
31664 if(box[0].size == 'xs' && box[1].size == 'xs'){
31667 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31672 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31677 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31678 y : minY + (this.unitWidth + this.gutter) * 1
31686 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31691 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31692 y : minY + (this.unitWidth + this.gutter) * 2
31696 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31697 y : minY + (this.unitWidth + this.gutter) * 2
31704 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31708 if(box[0].size == 'xs'){
31711 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31716 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31721 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),
31726 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31727 y : minY + (this.unitWidth + this.gutter) * 1
31735 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31740 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31741 y : minY + (this.unitWidth + this.gutter) * 2
31745 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31746 y : minY + (this.unitWidth + this.gutter) * 2
31750 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),
31751 y : minY + (this.unitWidth + this.gutter) * 2
31759 * remove a Masonry Brick
31760 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31762 removeBrick : function(brick_id)
31768 for (var i = 0; i<this.bricks.length; i++) {
31769 if (this.bricks[i].id == brick_id) {
31770 this.bricks.splice(i,1);
31771 this.el.dom.removeChild(Roo.get(brick_id).dom);
31778 * adds a Masonry Brick
31779 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31781 addBrick : function(cfg)
31783 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31784 //this.register(cn);
31785 cn.parentId = this.id;
31786 cn.onRender(this.el, null);
31791 * register a Masonry Brick
31792 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31795 register : function(brick)
31797 this.bricks.push(brick);
31798 brick.masonryId = this.id;
31802 * clear all the Masonry Brick
31804 clearAll : function()
31807 //this.getChildContainer().dom.innerHTML = "";
31808 this.el.dom.innerHTML = '';
31811 getSelected : function()
31813 if (!this.selectedBrick) {
31817 return this.selectedBrick;
31821 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31825 * register a Masonry Layout
31826 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31829 register : function(layout)
31831 this.groups[layout.id] = layout;
31834 * fetch a Masonry Layout based on the masonry layout ID
31835 * @param {string} the masonry layout to add
31836 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31839 get: function(layout_id) {
31840 if (typeof(this.groups[layout_id]) == 'undefined') {
31843 return this.groups[layout_id] ;
31855 * http://masonry.desandro.com
31857 * The idea is to render all the bricks based on vertical width...
31859 * The original code extends 'outlayer' - we might need to use that....
31865 * @class Roo.bootstrap.LayoutMasonryAuto
31866 * @extends Roo.bootstrap.Component
31867 * Bootstrap Layout Masonry class
31870 * Create a new Element
31871 * @param {Object} config The config object
31874 Roo.bootstrap.LayoutMasonryAuto = function(config){
31875 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31878 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31881 * @cfg {Boolean} isFitWidth - resize the width..
31883 isFitWidth : false, // options..
31885 * @cfg {Boolean} isOriginLeft = left align?
31887 isOriginLeft : true,
31889 * @cfg {Boolean} isOriginTop = top align?
31891 isOriginTop : false,
31893 * @cfg {Boolean} isLayoutInstant = no animation?
31895 isLayoutInstant : false, // needed?
31897 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31899 isResizingContainer : true,
31901 * @cfg {Number} columnWidth width of the columns
31907 * @cfg {Number} maxCols maximum number of columns
31912 * @cfg {Number} padHeight padding below box..
31918 * @cfg {Boolean} isAutoInitial defalut true
31921 isAutoInitial : true,
31927 initialColumnWidth : 0,
31928 currentSize : null,
31930 colYs : null, // array.
31937 bricks: null, //CompositeElement
31938 cols : 0, // array?
31939 // element : null, // wrapped now this.el
31940 _isLayoutInited : null,
31943 getAutoCreate : function(){
31947 cls: 'blog-masonary-wrapper ' + this.cls,
31949 cls : 'mas-boxes masonary'
31956 getChildContainer: function( )
31958 if (this.boxesEl) {
31959 return this.boxesEl;
31962 this.boxesEl = this.el.select('.mas-boxes').first();
31964 return this.boxesEl;
31968 initEvents : function()
31972 if(this.isAutoInitial){
31973 Roo.log('hook children rendered');
31974 this.on('childrenrendered', function() {
31975 Roo.log('children rendered');
31982 initial : function()
31984 this.reloadItems();
31986 this.currentSize = this.el.getBox(true);
31988 /// was window resize... - let's see if this works..
31989 Roo.EventManager.onWindowResize(this.resize, this);
31991 if(!this.isAutoInitial){
31996 this.layout.defer(500,this);
31999 reloadItems: function()
32001 this.bricks = this.el.select('.masonry-brick', true);
32003 this.bricks.each(function(b) {
32004 //Roo.log(b.getSize());
32005 if (!b.attr('originalwidth')) {
32006 b.attr('originalwidth', b.getSize().width);
32011 Roo.log(this.bricks.elements.length);
32014 resize : function()
32017 var cs = this.el.getBox(true);
32019 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32020 Roo.log("no change in with or X");
32023 this.currentSize = cs;
32027 layout : function()
32030 this._resetLayout();
32031 //this._manageStamps();
32033 // don't animate first layout
32034 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32035 this.layoutItems( isInstant );
32037 // flag for initalized
32038 this._isLayoutInited = true;
32041 layoutItems : function( isInstant )
32043 //var items = this._getItemsForLayout( this.items );
32044 // original code supports filtering layout items.. we just ignore it..
32046 this._layoutItems( this.bricks , isInstant );
32048 this._postLayout();
32050 _layoutItems : function ( items , isInstant)
32052 //this.fireEvent( 'layout', this, items );
32055 if ( !items || !items.elements.length ) {
32056 // no items, emit event with empty array
32061 items.each(function(item) {
32062 Roo.log("layout item");
32064 // get x/y object from method
32065 var position = this._getItemLayoutPosition( item );
32067 position.item = item;
32068 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32069 queue.push( position );
32072 this._processLayoutQueue( queue );
32074 /** Sets position of item in DOM
32075 * @param {Element} item
32076 * @param {Number} x - horizontal position
32077 * @param {Number} y - vertical position
32078 * @param {Boolean} isInstant - disables transitions
32080 _processLayoutQueue : function( queue )
32082 for ( var i=0, len = queue.length; i < len; i++ ) {
32083 var obj = queue[i];
32084 obj.item.position('absolute');
32085 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32091 * Any logic you want to do after each layout,
32092 * i.e. size the container
32094 _postLayout : function()
32096 this.resizeContainer();
32099 resizeContainer : function()
32101 if ( !this.isResizingContainer ) {
32104 var size = this._getContainerSize();
32106 this.el.setSize(size.width,size.height);
32107 this.boxesEl.setSize(size.width,size.height);
32113 _resetLayout : function()
32115 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32116 this.colWidth = this.el.getWidth();
32117 //this.gutter = this.el.getWidth();
32119 this.measureColumns();
32125 this.colYs.push( 0 );
32131 measureColumns : function()
32133 this.getContainerWidth();
32134 // if columnWidth is 0, default to outerWidth of first item
32135 if ( !this.columnWidth ) {
32136 var firstItem = this.bricks.first();
32137 Roo.log(firstItem);
32138 this.columnWidth = this.containerWidth;
32139 if (firstItem && firstItem.attr('originalwidth') ) {
32140 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32142 // columnWidth fall back to item of first element
32143 Roo.log("set column width?");
32144 this.initialColumnWidth = this.columnWidth ;
32146 // if first elem has no width, default to size of container
32151 if (this.initialColumnWidth) {
32152 this.columnWidth = this.initialColumnWidth;
32157 // column width is fixed at the top - however if container width get's smaller we should
32160 // this bit calcs how man columns..
32162 var columnWidth = this.columnWidth += this.gutter;
32164 // calculate columns
32165 var containerWidth = this.containerWidth + this.gutter;
32167 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32168 // fix rounding errors, typically with gutters
32169 var excess = columnWidth - containerWidth % columnWidth;
32172 // if overshoot is less than a pixel, round up, otherwise floor it
32173 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32174 cols = Math[ mathMethod ]( cols );
32175 this.cols = Math.max( cols, 1 );
32176 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32178 // padding positioning..
32179 var totalColWidth = this.cols * this.columnWidth;
32180 var padavail = this.containerWidth - totalColWidth;
32181 // so for 2 columns - we need 3 'pads'
32183 var padNeeded = (1+this.cols) * this.padWidth;
32185 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32187 this.columnWidth += padExtra
32188 //this.padWidth = Math.floor(padavail / ( this.cols));
32190 // adjust colum width so that padding is fixed??
32192 // we have 3 columns ... total = width * 3
32193 // we have X left over... that should be used by
32195 //if (this.expandC) {
32203 getContainerWidth : function()
32205 /* // container is parent if fit width
32206 var container = this.isFitWidth ? this.element.parentNode : this.element;
32207 // check that this.size and size are there
32208 // IE8 triggers resize on body size change, so they might not be
32210 var size = getSize( container ); //FIXME
32211 this.containerWidth = size && size.innerWidth; //FIXME
32214 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32218 _getItemLayoutPosition : function( item ) // what is item?
32220 // we resize the item to our columnWidth..
32222 item.setWidth(this.columnWidth);
32223 item.autoBoxAdjust = false;
32225 var sz = item.getSize();
32227 // how many columns does this brick span
32228 var remainder = this.containerWidth % this.columnWidth;
32230 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32231 // round if off by 1 pixel, otherwise use ceil
32232 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32233 colSpan = Math.min( colSpan, this.cols );
32235 // normally this should be '1' as we dont' currently allow multi width columns..
32237 var colGroup = this._getColGroup( colSpan );
32238 // get the minimum Y value from the columns
32239 var minimumY = Math.min.apply( Math, colGroup );
32240 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32242 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32244 // position the brick
32246 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32247 y: this.currentSize.y + minimumY + this.padHeight
32251 // apply setHeight to necessary columns
32252 var setHeight = minimumY + sz.height + this.padHeight;
32253 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32255 var setSpan = this.cols + 1 - colGroup.length;
32256 for ( var i = 0; i < setSpan; i++ ) {
32257 this.colYs[ shortColIndex + i ] = setHeight ;
32264 * @param {Number} colSpan - number of columns the element spans
32265 * @returns {Array} colGroup
32267 _getColGroup : function( colSpan )
32269 if ( colSpan < 2 ) {
32270 // if brick spans only one column, use all the column Ys
32275 // how many different places could this brick fit horizontally
32276 var groupCount = this.cols + 1 - colSpan;
32277 // for each group potential horizontal position
32278 for ( var i = 0; i < groupCount; i++ ) {
32279 // make an array of colY values for that one group
32280 var groupColYs = this.colYs.slice( i, i + colSpan );
32281 // and get the max value of the array
32282 colGroup[i] = Math.max.apply( Math, groupColYs );
32287 _manageStamp : function( stamp )
32289 var stampSize = stamp.getSize();
32290 var offset = stamp.getBox();
32291 // get the columns that this stamp affects
32292 var firstX = this.isOriginLeft ? offset.x : offset.right;
32293 var lastX = firstX + stampSize.width;
32294 var firstCol = Math.floor( firstX / this.columnWidth );
32295 firstCol = Math.max( 0, firstCol );
32297 var lastCol = Math.floor( lastX / this.columnWidth );
32298 // lastCol should not go over if multiple of columnWidth #425
32299 lastCol -= lastX % this.columnWidth ? 0 : 1;
32300 lastCol = Math.min( this.cols - 1, lastCol );
32302 // set colYs to bottom of the stamp
32303 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32306 for ( var i = firstCol; i <= lastCol; i++ ) {
32307 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32312 _getContainerSize : function()
32314 this.maxY = Math.max.apply( Math, this.colYs );
32319 if ( this.isFitWidth ) {
32320 size.width = this._getContainerFitWidth();
32326 _getContainerFitWidth : function()
32328 var unusedCols = 0;
32329 // count unused columns
32332 if ( this.colYs[i] !== 0 ) {
32337 // fit container to columns that have been used
32338 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32341 needsResizeLayout : function()
32343 var previousWidth = this.containerWidth;
32344 this.getContainerWidth();
32345 return previousWidth !== this.containerWidth;
32360 * @class Roo.bootstrap.MasonryBrick
32361 * @extends Roo.bootstrap.Component
32362 * Bootstrap MasonryBrick class
32365 * Create a new MasonryBrick
32366 * @param {Object} config The config object
32369 Roo.bootstrap.MasonryBrick = function(config){
32371 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32373 Roo.bootstrap.MasonryBrick.register(this);
32379 * When a MasonryBrick is clcik
32380 * @param {Roo.bootstrap.MasonryBrick} this
32381 * @param {Roo.EventObject} e
32387 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32390 * @cfg {String} title
32394 * @cfg {String} html
32398 * @cfg {String} bgimage
32402 * @cfg {String} videourl
32406 * @cfg {String} cls
32410 * @cfg {String} href
32414 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32419 * @cfg {String} placetitle (center|bottom)
32424 * @cfg {Boolean} isFitContainer defalut true
32426 isFitContainer : true,
32429 * @cfg {Boolean} preventDefault defalut false
32431 preventDefault : false,
32434 * @cfg {Boolean} inverse defalut false
32436 maskInverse : false,
32438 getAutoCreate : function()
32440 if(!this.isFitContainer){
32441 return this.getSplitAutoCreate();
32444 var cls = 'masonry-brick masonry-brick-full';
32446 if(this.href.length){
32447 cls += ' masonry-brick-link';
32450 if(this.bgimage.length){
32451 cls += ' masonry-brick-image';
32454 if(this.maskInverse){
32455 cls += ' mask-inverse';
32458 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32459 cls += ' enable-mask';
32463 cls += ' masonry-' + this.size + '-brick';
32466 if(this.placetitle.length){
32468 switch (this.placetitle) {
32470 cls += ' masonry-center-title';
32473 cls += ' masonry-bottom-title';
32480 if(!this.html.length && !this.bgimage.length){
32481 cls += ' masonry-center-title';
32484 if(!this.html.length && this.bgimage.length){
32485 cls += ' masonry-bottom-title';
32490 cls += ' ' + this.cls;
32494 tag: (this.href.length) ? 'a' : 'div',
32499 cls: 'masonry-brick-mask'
32503 cls: 'masonry-brick-paragraph',
32509 if(this.href.length){
32510 cfg.href = this.href;
32513 var cn = cfg.cn[1].cn;
32515 if(this.title.length){
32518 cls: 'masonry-brick-title',
32523 if(this.html.length){
32526 cls: 'masonry-brick-text',
32531 if (!this.title.length && !this.html.length) {
32532 cfg.cn[1].cls += ' hide';
32535 if(this.bgimage.length){
32538 cls: 'masonry-brick-image-view',
32543 if(this.videourl.length){
32544 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32545 // youtube support only?
32548 cls: 'masonry-brick-image-view',
32551 allowfullscreen : true
32559 getSplitAutoCreate : function()
32561 var cls = 'masonry-brick masonry-brick-split';
32563 if(this.href.length){
32564 cls += ' masonry-brick-link';
32567 if(this.bgimage.length){
32568 cls += ' masonry-brick-image';
32572 cls += ' masonry-' + this.size + '-brick';
32575 switch (this.placetitle) {
32577 cls += ' masonry-center-title';
32580 cls += ' masonry-bottom-title';
32583 if(!this.bgimage.length){
32584 cls += ' masonry-center-title';
32587 if(this.bgimage.length){
32588 cls += ' masonry-bottom-title';
32594 cls += ' ' + this.cls;
32598 tag: (this.href.length) ? 'a' : 'div',
32603 cls: 'masonry-brick-split-head',
32607 cls: 'masonry-brick-paragraph',
32614 cls: 'masonry-brick-split-body',
32620 if(this.href.length){
32621 cfg.href = this.href;
32624 if(this.title.length){
32625 cfg.cn[0].cn[0].cn.push({
32627 cls: 'masonry-brick-title',
32632 if(this.html.length){
32633 cfg.cn[1].cn.push({
32635 cls: 'masonry-brick-text',
32640 if(this.bgimage.length){
32641 cfg.cn[0].cn.push({
32643 cls: 'masonry-brick-image-view',
32648 if(this.videourl.length){
32649 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32650 // youtube support only?
32651 cfg.cn[0].cn.cn.push({
32653 cls: 'masonry-brick-image-view',
32656 allowfullscreen : true
32663 initEvents: function()
32665 switch (this.size) {
32698 this.el.on('touchstart', this.onTouchStart, this);
32699 this.el.on('touchmove', this.onTouchMove, this);
32700 this.el.on('touchend', this.onTouchEnd, this);
32701 this.el.on('contextmenu', this.onContextMenu, this);
32703 this.el.on('mouseenter' ,this.enter, this);
32704 this.el.on('mouseleave', this.leave, this);
32705 this.el.on('click', this.onClick, this);
32708 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32709 this.parent().bricks.push(this);
32714 onClick: function(e, el)
32716 var time = this.endTimer - this.startTimer;
32717 // Roo.log(e.preventDefault());
32720 e.preventDefault();
32725 if(!this.preventDefault){
32729 e.preventDefault();
32731 if (this.activcClass != '') {
32732 this.selectBrick();
32735 this.fireEvent('click', this);
32738 enter: function(e, el)
32740 e.preventDefault();
32742 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32746 if(this.bgimage.length && this.html.length){
32747 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32751 leave: function(e, el)
32753 e.preventDefault();
32755 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32759 if(this.bgimage.length && this.html.length){
32760 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32764 onTouchStart: function(e, el)
32766 // e.preventDefault();
32768 this.touchmoved = false;
32770 if(!this.isFitContainer){
32774 if(!this.bgimage.length || !this.html.length){
32778 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32780 this.timer = new Date().getTime();
32784 onTouchMove: function(e, el)
32786 this.touchmoved = true;
32789 onContextMenu : function(e,el)
32791 e.preventDefault();
32792 e.stopPropagation();
32796 onTouchEnd: function(e, el)
32798 // e.preventDefault();
32800 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32807 if(!this.bgimage.length || !this.html.length){
32809 if(this.href.length){
32810 window.location.href = this.href;
32816 if(!this.isFitContainer){
32820 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32822 window.location.href = this.href;
32825 //selection on single brick only
32826 selectBrick : function() {
32828 if (!this.parentId) {
32832 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32833 var index = m.selectedBrick.indexOf(this.id);
32836 m.selectedBrick.splice(index,1);
32837 this.el.removeClass(this.activeClass);
32841 for(var i = 0; i < m.selectedBrick.length; i++) {
32842 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32843 b.el.removeClass(b.activeClass);
32846 m.selectedBrick = [];
32848 m.selectedBrick.push(this.id);
32849 this.el.addClass(this.activeClass);
32855 Roo.apply(Roo.bootstrap.MasonryBrick, {
32858 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32860 * register a Masonry Brick
32861 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32864 register : function(brick)
32866 //this.groups[brick.id] = brick;
32867 this.groups.add(brick.id, brick);
32870 * fetch a masonry brick based on the masonry brick ID
32871 * @param {string} the masonry brick to add
32872 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32875 get: function(brick_id)
32877 // if (typeof(this.groups[brick_id]) == 'undefined') {
32880 // return this.groups[brick_id] ;
32882 if(this.groups.key(brick_id)) {
32883 return this.groups.key(brick_id);
32901 * @class Roo.bootstrap.Brick
32902 * @extends Roo.bootstrap.Component
32903 * Bootstrap Brick class
32906 * Create a new Brick
32907 * @param {Object} config The config object
32910 Roo.bootstrap.Brick = function(config){
32911 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32917 * When a Brick is click
32918 * @param {Roo.bootstrap.Brick} this
32919 * @param {Roo.EventObject} e
32925 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32928 * @cfg {String} title
32932 * @cfg {String} html
32936 * @cfg {String} bgimage
32940 * @cfg {String} cls
32944 * @cfg {String} href
32948 * @cfg {String} video
32952 * @cfg {Boolean} square
32956 getAutoCreate : function()
32958 var cls = 'roo-brick';
32960 if(this.href.length){
32961 cls += ' roo-brick-link';
32964 if(this.bgimage.length){
32965 cls += ' roo-brick-image';
32968 if(!this.html.length && !this.bgimage.length){
32969 cls += ' roo-brick-center-title';
32972 if(!this.html.length && this.bgimage.length){
32973 cls += ' roo-brick-bottom-title';
32977 cls += ' ' + this.cls;
32981 tag: (this.href.length) ? 'a' : 'div',
32986 cls: 'roo-brick-paragraph',
32992 if(this.href.length){
32993 cfg.href = this.href;
32996 var cn = cfg.cn[0].cn;
32998 if(this.title.length){
33001 cls: 'roo-brick-title',
33006 if(this.html.length){
33009 cls: 'roo-brick-text',
33016 if(this.bgimage.length){
33019 cls: 'roo-brick-image-view',
33027 initEvents: function()
33029 if(this.title.length || this.html.length){
33030 this.el.on('mouseenter' ,this.enter, this);
33031 this.el.on('mouseleave', this.leave, this);
33034 Roo.EventManager.onWindowResize(this.resize, this);
33036 if(this.bgimage.length){
33037 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33038 this.imageEl.on('load', this.onImageLoad, this);
33045 onImageLoad : function()
33050 resize : function()
33052 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33054 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33056 if(this.bgimage.length){
33057 var image = this.el.select('.roo-brick-image-view', true).first();
33059 image.setWidth(paragraph.getWidth());
33062 image.setHeight(paragraph.getWidth());
33065 this.el.setHeight(image.getHeight());
33066 paragraph.setHeight(image.getHeight());
33072 enter: function(e, el)
33074 e.preventDefault();
33076 if(this.bgimage.length){
33077 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33078 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33082 leave: function(e, el)
33084 e.preventDefault();
33086 if(this.bgimage.length){
33087 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33088 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33103 * @class Roo.bootstrap.NumberField
33104 * @extends Roo.bootstrap.Input
33105 * Bootstrap NumberField class
33111 * Create a new NumberField
33112 * @param {Object} config The config object
33115 Roo.bootstrap.NumberField = function(config){
33116 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33119 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33122 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33124 allowDecimals : true,
33126 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33128 decimalSeparator : ".",
33130 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33132 decimalPrecision : 2,
33134 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33136 allowNegative : true,
33139 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33143 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33145 minValue : Number.NEGATIVE_INFINITY,
33147 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33149 maxValue : Number.MAX_VALUE,
33151 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33153 minText : "The minimum value for this field is {0}",
33155 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33157 maxText : "The maximum value for this field is {0}",
33159 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33160 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33162 nanText : "{0} is not a valid number",
33164 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33168 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33170 thousandsDelimiter : false,
33172 * @cfg {String} valueAlign alignment of value
33174 valueAlign : "left",
33176 getAutoCreate : function()
33178 var hiddenInput = {
33182 cls: 'hidden-number-input'
33186 hiddenInput.name = this.name;
33191 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33193 this.name = hiddenInput.name;
33195 if(cfg.cn.length > 0) {
33196 cfg.cn.push(hiddenInput);
33203 initEvents : function()
33205 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33207 var allowed = "0123456789";
33209 if(this.allowDecimals){
33210 allowed += this.decimalSeparator;
33213 if(this.allowNegative){
33217 if(this.thousandsDelimiter) {
33221 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33223 var keyPress = function(e){
33225 var k = e.getKey();
33227 var c = e.getCharCode();
33230 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33231 allowed.indexOf(String.fromCharCode(c)) === -1
33237 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33241 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33246 this.el.on("keypress", keyPress, this);
33249 validateValue : function(value)
33252 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33256 var num = this.parseValue(value);
33259 this.markInvalid(String.format(this.nanText, value));
33263 if(num < this.minValue){
33264 this.markInvalid(String.format(this.minText, this.minValue));
33268 if(num > this.maxValue){
33269 this.markInvalid(String.format(this.maxText, this.maxValue));
33276 getValue : function()
33278 var v = this.hiddenEl().getValue();
33280 return this.fixPrecision(this.parseValue(v));
33283 parseValue : function(value)
33285 if(this.thousandsDelimiter) {
33287 r = new RegExp(",", "g");
33288 value = value.replace(r, "");
33291 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33292 return isNaN(value) ? '' : value;
33295 fixPrecision : function(value)
33297 if(this.thousandsDelimiter) {
33299 r = new RegExp(",", "g");
33300 value = value.replace(r, "");
33303 var nan = isNaN(value);
33305 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33306 return nan ? '' : value;
33308 return parseFloat(value).toFixed(this.decimalPrecision);
33311 setValue : function(v)
33313 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33319 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33321 this.inputEl().dom.value = (v == '') ? '' :
33322 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33324 if(!this.allowZero && v === '0') {
33325 this.hiddenEl().dom.value = '';
33326 this.inputEl().dom.value = '';
33333 decimalPrecisionFcn : function(v)
33335 return Math.floor(v);
33338 beforeBlur : function()
33344 var v = this.parseValue(this.getRawValue());
33351 hiddenEl : function()
33353 return this.el.select('input.hidden-number-input',true).first();
33365 * @class Roo.bootstrap.DocumentSlider
33366 * @extends Roo.bootstrap.Component
33367 * Bootstrap DocumentSlider class
33370 * Create a new DocumentViewer
33371 * @param {Object} config The config object
33374 Roo.bootstrap.DocumentSlider = function(config){
33375 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33382 * Fire after initEvent
33383 * @param {Roo.bootstrap.DocumentSlider} this
33388 * Fire after update
33389 * @param {Roo.bootstrap.DocumentSlider} this
33395 * @param {Roo.bootstrap.DocumentSlider} this
33401 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33407 getAutoCreate : function()
33411 cls : 'roo-document-slider',
33415 cls : 'roo-document-slider-header',
33419 cls : 'roo-document-slider-header-title'
33425 cls : 'roo-document-slider-body',
33429 cls : 'roo-document-slider-prev',
33433 cls : 'fa fa-chevron-left'
33439 cls : 'roo-document-slider-thumb',
33443 cls : 'roo-document-slider-image'
33449 cls : 'roo-document-slider-next',
33453 cls : 'fa fa-chevron-right'
33465 initEvents : function()
33467 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33468 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33470 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33471 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33473 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33474 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33476 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33477 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33479 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33480 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33482 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33483 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33485 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33486 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33488 this.thumbEl.on('click', this.onClick, this);
33490 this.prevIndicator.on('click', this.prev, this);
33492 this.nextIndicator.on('click', this.next, this);
33496 initial : function()
33498 if(this.files.length){
33499 this.indicator = 1;
33503 this.fireEvent('initial', this);
33506 update : function()
33508 this.imageEl.attr('src', this.files[this.indicator - 1]);
33510 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33512 this.prevIndicator.show();
33514 if(this.indicator == 1){
33515 this.prevIndicator.hide();
33518 this.nextIndicator.show();
33520 if(this.indicator == this.files.length){
33521 this.nextIndicator.hide();
33524 this.thumbEl.scrollTo('top');
33526 this.fireEvent('update', this);
33529 onClick : function(e)
33531 e.preventDefault();
33533 this.fireEvent('click', this);
33538 e.preventDefault();
33540 this.indicator = Math.max(1, this.indicator - 1);
33547 e.preventDefault();
33549 this.indicator = Math.min(this.files.length, this.indicator + 1);
33563 * @class Roo.bootstrap.RadioSet
33564 * @extends Roo.bootstrap.Input
33565 * Bootstrap RadioSet class
33566 * @cfg {String} indicatorpos (left|right) default left
33567 * @cfg {Boolean} inline (true|false) inline the element (default true)
33568 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33570 * Create a new RadioSet
33571 * @param {Object} config The config object
33574 Roo.bootstrap.RadioSet = function(config){
33576 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33580 Roo.bootstrap.RadioSet.register(this);
33585 * Fires when the element is checked or unchecked.
33586 * @param {Roo.bootstrap.RadioSet} this This radio
33587 * @param {Roo.bootstrap.Radio} item The checked item
33592 * Fires when the element is click.
33593 * @param {Roo.bootstrap.RadioSet} this This radio set
33594 * @param {Roo.bootstrap.Radio} item The checked item
33595 * @param {Roo.EventObject} e The event object
33602 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33610 indicatorpos : 'left',
33612 getAutoCreate : function()
33616 cls : 'roo-radio-set-label',
33620 html : this.fieldLabel
33625 if(this.indicatorpos == 'left'){
33628 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33629 tooltip : 'This field is required'
33634 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33635 tooltip : 'This field is required'
33641 cls : 'roo-radio-set-items'
33644 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33646 if (align === 'left' && this.fieldLabel.length) {
33649 cls : "roo-radio-set-right",
33655 if(this.labelWidth > 12){
33656 label.style = "width: " + this.labelWidth + 'px';
33659 if(this.labelWidth < 13 && this.labelmd == 0){
33660 this.labelmd = this.labelWidth;
33663 if(this.labellg > 0){
33664 label.cls += ' col-lg-' + this.labellg;
33665 items.cls += ' col-lg-' + (12 - this.labellg);
33668 if(this.labelmd > 0){
33669 label.cls += ' col-md-' + this.labelmd;
33670 items.cls += ' col-md-' + (12 - this.labelmd);
33673 if(this.labelsm > 0){
33674 label.cls += ' col-sm-' + this.labelsm;
33675 items.cls += ' col-sm-' + (12 - this.labelsm);
33678 if(this.labelxs > 0){
33679 label.cls += ' col-xs-' + this.labelxs;
33680 items.cls += ' col-xs-' + (12 - this.labelxs);
33686 cls : 'roo-radio-set',
33690 cls : 'roo-radio-set-input',
33693 value : this.value ? this.value : ''
33700 if(this.weight.length){
33701 cfg.cls += ' roo-radio-' + this.weight;
33705 cfg.cls += ' roo-radio-set-inline';
33709 ['xs','sm','md','lg'].map(function(size){
33710 if (settings[size]) {
33711 cfg.cls += ' col-' + size + '-' + settings[size];
33719 initEvents : function()
33721 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33722 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33724 if(!this.fieldLabel.length){
33725 this.labelEl.hide();
33728 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33729 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33731 this.indicator = this.indicatorEl();
33733 if(this.indicator){
33734 this.indicator.addClass('invisible');
33737 this.originalValue = this.getValue();
33741 inputEl: function ()
33743 return this.el.select('.roo-radio-set-input', true).first();
33746 getChildContainer : function()
33748 return this.itemsEl;
33751 register : function(item)
33753 this.radioes.push(item);
33757 validate : function()
33759 if(this.getVisibilityEl().hasClass('hidden')){
33765 Roo.each(this.radioes, function(i){
33774 if(this.allowBlank) {
33778 if(this.disabled || valid){
33783 this.markInvalid();
33788 markValid : function()
33790 if(this.labelEl.isVisible(true)){
33791 this.indicatorEl().removeClass('visible');
33792 this.indicatorEl().addClass('invisible');
33795 this.el.removeClass([this.invalidClass, this.validClass]);
33796 this.el.addClass(this.validClass);
33798 this.fireEvent('valid', this);
33801 markInvalid : function(msg)
33803 if(this.allowBlank || this.disabled){
33807 if(this.labelEl.isVisible(true)){
33808 this.indicatorEl().removeClass('invisible');
33809 this.indicatorEl().addClass('visible');
33812 this.el.removeClass([this.invalidClass, this.validClass]);
33813 this.el.addClass(this.invalidClass);
33815 this.fireEvent('invalid', this, msg);
33819 setValue : function(v, suppressEvent)
33821 if(this.value === v){
33828 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33831 Roo.each(this.radioes, function(i){
33833 i.el.removeClass('checked');
33836 Roo.each(this.radioes, function(i){
33838 if(i.value === v || i.value.toString() === v.toString()){
33840 i.el.addClass('checked');
33842 if(suppressEvent !== true){
33843 this.fireEvent('check', this, i);
33854 clearInvalid : function(){
33856 if(!this.el || this.preventMark){
33860 this.el.removeClass([this.invalidClass]);
33862 this.fireEvent('valid', this);
33867 Roo.apply(Roo.bootstrap.RadioSet, {
33871 register : function(set)
33873 this.groups[set.name] = set;
33876 get: function(name)
33878 if (typeof(this.groups[name]) == 'undefined') {
33882 return this.groups[name] ;
33888 * Ext JS Library 1.1.1
33889 * Copyright(c) 2006-2007, Ext JS, LLC.
33891 * Originally Released Under LGPL - original licence link has changed is not relivant.
33894 * <script type="text/javascript">
33899 * @class Roo.bootstrap.SplitBar
33900 * @extends Roo.util.Observable
33901 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33905 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33906 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33907 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33908 split.minSize = 100;
33909 split.maxSize = 600;
33910 split.animate = true;
33911 split.on('moved', splitterMoved);
33914 * Create a new SplitBar
33915 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33916 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33917 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33918 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33919 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33920 position of the SplitBar).
33922 Roo.bootstrap.SplitBar = function(cfg){
33927 // dragElement : elm
33928 // resizingElement: el,
33930 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33931 // placement : Roo.bootstrap.SplitBar.LEFT ,
33932 // existingProxy ???
33935 this.el = Roo.get(cfg.dragElement, true);
33936 this.el.dom.unselectable = "on";
33938 this.resizingEl = Roo.get(cfg.resizingElement, true);
33942 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33943 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33946 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33949 * The minimum size of the resizing element. (Defaults to 0)
33955 * The maximum size of the resizing element. (Defaults to 2000)
33958 this.maxSize = 2000;
33961 * Whether to animate the transition to the new size
33964 this.animate = false;
33967 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33970 this.useShim = false;
33975 if(!cfg.existingProxy){
33977 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33979 this.proxy = Roo.get(cfg.existingProxy).dom;
33982 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33985 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33988 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33991 this.dragSpecs = {};
33994 * @private The adapter to use to positon and resize elements
33996 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33997 this.adapter.init(this);
33999 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34001 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34002 this.el.addClass("roo-splitbar-h");
34005 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34006 this.el.addClass("roo-splitbar-v");
34012 * Fires when the splitter is moved (alias for {@link #event-moved})
34013 * @param {Roo.bootstrap.SplitBar} this
34014 * @param {Number} newSize the new width or height
34019 * Fires when the splitter is moved
34020 * @param {Roo.bootstrap.SplitBar} this
34021 * @param {Number} newSize the new width or height
34025 * @event beforeresize
34026 * Fires before the splitter is dragged
34027 * @param {Roo.bootstrap.SplitBar} this
34029 "beforeresize" : true,
34031 "beforeapply" : true
34034 Roo.util.Observable.call(this);
34037 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34038 onStartProxyDrag : function(x, y){
34039 this.fireEvent("beforeresize", this);
34041 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34043 o.enableDisplayMode("block");
34044 // all splitbars share the same overlay
34045 Roo.bootstrap.SplitBar.prototype.overlay = o;
34047 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34048 this.overlay.show();
34049 Roo.get(this.proxy).setDisplayed("block");
34050 var size = this.adapter.getElementSize(this);
34051 this.activeMinSize = this.getMinimumSize();;
34052 this.activeMaxSize = this.getMaximumSize();;
34053 var c1 = size - this.activeMinSize;
34054 var c2 = Math.max(this.activeMaxSize - size, 0);
34055 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34056 this.dd.resetConstraints();
34057 this.dd.setXConstraint(
34058 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34059 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34061 this.dd.setYConstraint(0, 0);
34063 this.dd.resetConstraints();
34064 this.dd.setXConstraint(0, 0);
34065 this.dd.setYConstraint(
34066 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34067 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34070 this.dragSpecs.startSize = size;
34071 this.dragSpecs.startPoint = [x, y];
34072 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34076 * @private Called after the drag operation by the DDProxy
34078 onEndProxyDrag : function(e){
34079 Roo.get(this.proxy).setDisplayed(false);
34080 var endPoint = Roo.lib.Event.getXY(e);
34082 this.overlay.hide();
34085 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34086 newSize = this.dragSpecs.startSize +
34087 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34088 endPoint[0] - this.dragSpecs.startPoint[0] :
34089 this.dragSpecs.startPoint[0] - endPoint[0]
34092 newSize = this.dragSpecs.startSize +
34093 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34094 endPoint[1] - this.dragSpecs.startPoint[1] :
34095 this.dragSpecs.startPoint[1] - endPoint[1]
34098 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34099 if(newSize != this.dragSpecs.startSize){
34100 if(this.fireEvent('beforeapply', this, newSize) !== false){
34101 this.adapter.setElementSize(this, newSize);
34102 this.fireEvent("moved", this, newSize);
34103 this.fireEvent("resize", this, newSize);
34109 * Get the adapter this SplitBar uses
34110 * @return The adapter object
34112 getAdapter : function(){
34113 return this.adapter;
34117 * Set the adapter this SplitBar uses
34118 * @param {Object} adapter A SplitBar adapter object
34120 setAdapter : function(adapter){
34121 this.adapter = adapter;
34122 this.adapter.init(this);
34126 * Gets the minimum size for the resizing element
34127 * @return {Number} The minimum size
34129 getMinimumSize : function(){
34130 return this.minSize;
34134 * Sets the minimum size for the resizing element
34135 * @param {Number} minSize The minimum size
34137 setMinimumSize : function(minSize){
34138 this.minSize = minSize;
34142 * Gets the maximum size for the resizing element
34143 * @return {Number} The maximum size
34145 getMaximumSize : function(){
34146 return this.maxSize;
34150 * Sets the maximum size for the resizing element
34151 * @param {Number} maxSize The maximum size
34153 setMaximumSize : function(maxSize){
34154 this.maxSize = maxSize;
34158 * Sets the initialize size for the resizing element
34159 * @param {Number} size The initial size
34161 setCurrentSize : function(size){
34162 var oldAnimate = this.animate;
34163 this.animate = false;
34164 this.adapter.setElementSize(this, size);
34165 this.animate = oldAnimate;
34169 * Destroy this splitbar.
34170 * @param {Boolean} removeEl True to remove the element
34172 destroy : function(removeEl){
34174 this.shim.remove();
34177 this.proxy.parentNode.removeChild(this.proxy);
34185 * @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.
34187 Roo.bootstrap.SplitBar.createProxy = function(dir){
34188 var proxy = new Roo.Element(document.createElement("div"));
34189 proxy.unselectable();
34190 var cls = 'roo-splitbar-proxy';
34191 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34192 document.body.appendChild(proxy.dom);
34197 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34198 * Default Adapter. It assumes the splitter and resizing element are not positioned
34199 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34201 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34204 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34205 // do nothing for now
34206 init : function(s){
34210 * Called before drag operations to get the current size of the resizing element.
34211 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34213 getElementSize : function(s){
34214 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34215 return s.resizingEl.getWidth();
34217 return s.resizingEl.getHeight();
34222 * Called after drag operations to set the size of the resizing element.
34223 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34224 * @param {Number} newSize The new size to set
34225 * @param {Function} onComplete A function to be invoked when resizing is complete
34227 setElementSize : function(s, newSize, onComplete){
34228 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34230 s.resizingEl.setWidth(newSize);
34232 onComplete(s, newSize);
34235 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34240 s.resizingEl.setHeight(newSize);
34242 onComplete(s, newSize);
34245 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34252 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34253 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34254 * Adapter that moves the splitter element to align with the resized sizing element.
34255 * Used with an absolute positioned SplitBar.
34256 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34257 * document.body, make sure you assign an id to the body element.
34259 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34260 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34261 this.container = Roo.get(container);
34264 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34265 init : function(s){
34266 this.basic.init(s);
34269 getElementSize : function(s){
34270 return this.basic.getElementSize(s);
34273 setElementSize : function(s, newSize, onComplete){
34274 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34277 moveSplitter : function(s){
34278 var yes = Roo.bootstrap.SplitBar;
34279 switch(s.placement){
34281 s.el.setX(s.resizingEl.getRight());
34284 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34287 s.el.setY(s.resizingEl.getBottom());
34290 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34297 * Orientation constant - Create a vertical SplitBar
34301 Roo.bootstrap.SplitBar.VERTICAL = 1;
34304 * Orientation constant - Create a horizontal SplitBar
34308 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34311 * Placement constant - The resizing element is to the left of the splitter element
34315 Roo.bootstrap.SplitBar.LEFT = 1;
34318 * Placement constant - The resizing element is to the right of the splitter element
34322 Roo.bootstrap.SplitBar.RIGHT = 2;
34325 * Placement constant - The resizing element is positioned above the splitter element
34329 Roo.bootstrap.SplitBar.TOP = 3;
34332 * Placement constant - The resizing element is positioned under splitter element
34336 Roo.bootstrap.SplitBar.BOTTOM = 4;
34337 Roo.namespace("Roo.bootstrap.layout");/*
34339 * Ext JS Library 1.1.1
34340 * Copyright(c) 2006-2007, Ext JS, LLC.
34342 * Originally Released Under LGPL - original licence link has changed is not relivant.
34345 * <script type="text/javascript">
34349 * @class Roo.bootstrap.layout.Manager
34350 * @extends Roo.bootstrap.Component
34351 * Base class for layout managers.
34353 Roo.bootstrap.layout.Manager = function(config)
34355 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34361 /** false to disable window resize monitoring @type Boolean */
34362 this.monitorWindowResize = true;
34367 * Fires when a layout is performed.
34368 * @param {Roo.LayoutManager} this
34372 * @event regionresized
34373 * Fires when the user resizes a region.
34374 * @param {Roo.LayoutRegion} region The resized region
34375 * @param {Number} newSize The new size (width for east/west, height for north/south)
34377 "regionresized" : true,
34379 * @event regioncollapsed
34380 * Fires when a region is collapsed.
34381 * @param {Roo.LayoutRegion} region The collapsed region
34383 "regioncollapsed" : true,
34385 * @event regionexpanded
34386 * Fires when a region is expanded.
34387 * @param {Roo.LayoutRegion} region The expanded region
34389 "regionexpanded" : true
34391 this.updating = false;
34394 this.el = Roo.get(config.el);
34400 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34405 monitorWindowResize : true,
34411 onRender : function(ct, position)
34414 this.el = Roo.get(ct);
34417 //this.fireEvent('render',this);
34421 initEvents: function()
34425 // ie scrollbar fix
34426 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34427 document.body.scroll = "no";
34428 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34429 this.el.position('relative');
34431 this.id = this.el.id;
34432 this.el.addClass("roo-layout-container");
34433 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34434 if(this.el.dom != document.body ) {
34435 this.el.on('resize', this.layout,this);
34436 this.el.on('show', this.layout,this);
34442 * Returns true if this layout is currently being updated
34443 * @return {Boolean}
34445 isUpdating : function(){
34446 return this.updating;
34450 * Suspend the LayoutManager from doing auto-layouts while
34451 * making multiple add or remove calls
34453 beginUpdate : function(){
34454 this.updating = true;
34458 * Restore auto-layouts and optionally disable the manager from performing a layout
34459 * @param {Boolean} noLayout true to disable a layout update
34461 endUpdate : function(noLayout){
34462 this.updating = false;
34468 layout: function(){
34472 onRegionResized : function(region, newSize){
34473 this.fireEvent("regionresized", region, newSize);
34477 onRegionCollapsed : function(region){
34478 this.fireEvent("regioncollapsed", region);
34481 onRegionExpanded : function(region){
34482 this.fireEvent("regionexpanded", region);
34486 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34487 * performs box-model adjustments.
34488 * @return {Object} The size as an object {width: (the width), height: (the height)}
34490 getViewSize : function()
34493 if(this.el.dom != document.body){
34494 size = this.el.getSize();
34496 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34498 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34499 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34504 * Returns the Element this layout is bound to.
34505 * @return {Roo.Element}
34507 getEl : function(){
34512 * Returns the specified region.
34513 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34514 * @return {Roo.LayoutRegion}
34516 getRegion : function(target){
34517 return this.regions[target.toLowerCase()];
34520 onWindowResize : function(){
34521 if(this.monitorWindowResize){
34528 * Ext JS Library 1.1.1
34529 * Copyright(c) 2006-2007, Ext JS, LLC.
34531 * Originally Released Under LGPL - original licence link has changed is not relivant.
34534 * <script type="text/javascript">
34537 * @class Roo.bootstrap.layout.Border
34538 * @extends Roo.bootstrap.layout.Manager
34539 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34540 * please see: examples/bootstrap/nested.html<br><br>
34542 <b>The container the layout is rendered into can be either the body element or any other element.
34543 If it is not the body element, the container needs to either be an absolute positioned element,
34544 or you will need to add "position:relative" to the css of the container. You will also need to specify
34545 the container size if it is not the body element.</b>
34548 * Create a new Border
34549 * @param {Object} config Configuration options
34551 Roo.bootstrap.layout.Border = function(config){
34552 config = config || {};
34553 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34557 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34558 if(config[region]){
34559 config[region].region = region;
34560 this.addRegion(config[region]);
34566 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34568 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34570 * Creates and adds a new region if it doesn't already exist.
34571 * @param {String} target The target region key (north, south, east, west or center).
34572 * @param {Object} config The regions config object
34573 * @return {BorderLayoutRegion} The new region
34575 addRegion : function(config)
34577 if(!this.regions[config.region]){
34578 var r = this.factory(config);
34579 this.bindRegion(r);
34581 return this.regions[config.region];
34585 bindRegion : function(r){
34586 this.regions[r.config.region] = r;
34588 r.on("visibilitychange", this.layout, this);
34589 r.on("paneladded", this.layout, this);
34590 r.on("panelremoved", this.layout, this);
34591 r.on("invalidated", this.layout, this);
34592 r.on("resized", this.onRegionResized, this);
34593 r.on("collapsed", this.onRegionCollapsed, this);
34594 r.on("expanded", this.onRegionExpanded, this);
34598 * Performs a layout update.
34600 layout : function()
34602 if(this.updating) {
34606 // render all the rebions if they have not been done alreayd?
34607 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34608 if(this.regions[region] && !this.regions[region].bodyEl){
34609 this.regions[region].onRender(this.el)
34613 var size = this.getViewSize();
34614 var w = size.width;
34615 var h = size.height;
34620 //var x = 0, y = 0;
34622 var rs = this.regions;
34623 var north = rs["north"];
34624 var south = rs["south"];
34625 var west = rs["west"];
34626 var east = rs["east"];
34627 var center = rs["center"];
34628 //if(this.hideOnLayout){ // not supported anymore
34629 //c.el.setStyle("display", "none");
34631 if(north && north.isVisible()){
34632 var b = north.getBox();
34633 var m = north.getMargins();
34634 b.width = w - (m.left+m.right);
34637 centerY = b.height + b.y + m.bottom;
34638 centerH -= centerY;
34639 north.updateBox(this.safeBox(b));
34641 if(south && south.isVisible()){
34642 var b = south.getBox();
34643 var m = south.getMargins();
34644 b.width = w - (m.left+m.right);
34646 var totalHeight = (b.height + m.top + m.bottom);
34647 b.y = h - totalHeight + m.top;
34648 centerH -= totalHeight;
34649 south.updateBox(this.safeBox(b));
34651 if(west && west.isVisible()){
34652 var b = west.getBox();
34653 var m = west.getMargins();
34654 b.height = centerH - (m.top+m.bottom);
34656 b.y = centerY + m.top;
34657 var totalWidth = (b.width + m.left + m.right);
34658 centerX += totalWidth;
34659 centerW -= totalWidth;
34660 west.updateBox(this.safeBox(b));
34662 if(east && east.isVisible()){
34663 var b = east.getBox();
34664 var m = east.getMargins();
34665 b.height = centerH - (m.top+m.bottom);
34666 var totalWidth = (b.width + m.left + m.right);
34667 b.x = w - totalWidth + m.left;
34668 b.y = centerY + m.top;
34669 centerW -= totalWidth;
34670 east.updateBox(this.safeBox(b));
34673 var m = center.getMargins();
34675 x: centerX + m.left,
34676 y: centerY + m.top,
34677 width: centerW - (m.left+m.right),
34678 height: centerH - (m.top+m.bottom)
34680 //if(this.hideOnLayout){
34681 //center.el.setStyle("display", "block");
34683 center.updateBox(this.safeBox(centerBox));
34686 this.fireEvent("layout", this);
34690 safeBox : function(box){
34691 box.width = Math.max(0, box.width);
34692 box.height = Math.max(0, box.height);
34697 * Adds a ContentPanel (or subclass) to this layout.
34698 * @param {String} target The target region key (north, south, east, west or center).
34699 * @param {Roo.ContentPanel} panel The panel to add
34700 * @return {Roo.ContentPanel} The added panel
34702 add : function(target, panel){
34704 target = target.toLowerCase();
34705 return this.regions[target].add(panel);
34709 * Remove a ContentPanel (or subclass) to this layout.
34710 * @param {String} target The target region key (north, south, east, west or center).
34711 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34712 * @return {Roo.ContentPanel} The removed panel
34714 remove : function(target, panel){
34715 target = target.toLowerCase();
34716 return this.regions[target].remove(panel);
34720 * Searches all regions for a panel with the specified id
34721 * @param {String} panelId
34722 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34724 findPanel : function(panelId){
34725 var rs = this.regions;
34726 for(var target in rs){
34727 if(typeof rs[target] != "function"){
34728 var p = rs[target].getPanel(panelId);
34738 * Searches all regions for a panel with the specified id and activates (shows) it.
34739 * @param {String/ContentPanel} panelId The panels id or the panel itself
34740 * @return {Roo.ContentPanel} The shown panel or null
34742 showPanel : function(panelId) {
34743 var rs = this.regions;
34744 for(var target in rs){
34745 var r = rs[target];
34746 if(typeof r != "function"){
34747 if(r.hasPanel(panelId)){
34748 return r.showPanel(panelId);
34756 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34757 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34760 restoreState : function(provider){
34762 provider = Roo.state.Manager;
34764 var sm = new Roo.LayoutStateManager();
34765 sm.init(this, provider);
34771 * Adds a xtype elements to the layout.
34775 xtype : 'ContentPanel',
34782 xtype : 'NestedLayoutPanel',
34788 items : [ ... list of content panels or nested layout panels.. ]
34792 * @param {Object} cfg Xtype definition of item to add.
34794 addxtype : function(cfg)
34796 // basically accepts a pannel...
34797 // can accept a layout region..!?!?
34798 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34801 // theory? children can only be panels??
34803 //if (!cfg.xtype.match(/Panel$/)) {
34808 if (typeof(cfg.region) == 'undefined') {
34809 Roo.log("Failed to add Panel, region was not set");
34813 var region = cfg.region;
34819 xitems = cfg.items;
34826 case 'Content': // ContentPanel (el, cfg)
34827 case 'Scroll': // ContentPanel (el, cfg)
34829 cfg.autoCreate = true;
34830 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34832 // var el = this.el.createChild();
34833 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34836 this.add(region, ret);
34840 case 'TreePanel': // our new panel!
34841 cfg.el = this.el.createChild();
34842 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34843 this.add(region, ret);
34848 // create a new Layout (which is a Border Layout...
34850 var clayout = cfg.layout;
34851 clayout.el = this.el.createChild();
34852 clayout.items = clayout.items || [];
34856 // replace this exitems with the clayout ones..
34857 xitems = clayout.items;
34859 // force background off if it's in center...
34860 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34861 cfg.background = false;
34863 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34866 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34867 //console.log('adding nested layout panel ' + cfg.toSource());
34868 this.add(region, ret);
34869 nb = {}; /// find first...
34874 // needs grid and region
34876 //var el = this.getRegion(region).el.createChild();
34878 *var el = this.el.createChild();
34879 // create the grid first...
34880 cfg.grid.container = el;
34881 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34884 if (region == 'center' && this.active ) {
34885 cfg.background = false;
34888 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34890 this.add(region, ret);
34892 if (cfg.background) {
34893 // render grid on panel activation (if panel background)
34894 ret.on('activate', function(gp) {
34895 if (!gp.grid.rendered) {
34896 // gp.grid.render(el);
34900 // cfg.grid.render(el);
34906 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34907 // it was the old xcomponent building that caused this before.
34908 // espeically if border is the top element in the tree.
34918 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34920 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34921 this.add(region, ret);
34925 throw "Can not add '" + cfg.xtype + "' to Border";
34931 this.beginUpdate();
34935 Roo.each(xitems, function(i) {
34936 region = nb && i.region ? i.region : false;
34938 var add = ret.addxtype(i);
34941 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34942 if (!i.background) {
34943 abn[region] = nb[region] ;
34950 // make the last non-background panel active..
34951 //if (nb) { Roo.log(abn); }
34954 for(var r in abn) {
34955 region = this.getRegion(r);
34957 // tried using nb[r], but it does not work..
34959 region.showPanel(abn[r]);
34970 factory : function(cfg)
34973 var validRegions = Roo.bootstrap.layout.Border.regions;
34975 var target = cfg.region;
34978 var r = Roo.bootstrap.layout;
34982 return new r.North(cfg);
34984 return new r.South(cfg);
34986 return new r.East(cfg);
34988 return new r.West(cfg);
34990 return new r.Center(cfg);
34992 throw 'Layout region "'+target+'" not supported.';
34999 * Ext JS Library 1.1.1
35000 * Copyright(c) 2006-2007, Ext JS, LLC.
35002 * Originally Released Under LGPL - original licence link has changed is not relivant.
35005 * <script type="text/javascript">
35009 * @class Roo.bootstrap.layout.Basic
35010 * @extends Roo.util.Observable
35011 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35012 * and does not have a titlebar, tabs or any other features. All it does is size and position
35013 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35014 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35015 * @cfg {string} region the region that it inhabits..
35016 * @cfg {bool} skipConfig skip config?
35020 Roo.bootstrap.layout.Basic = function(config){
35022 this.mgr = config.mgr;
35024 this.position = config.region;
35026 var skipConfig = config.skipConfig;
35030 * @scope Roo.BasicLayoutRegion
35034 * @event beforeremove
35035 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35036 * @param {Roo.LayoutRegion} this
35037 * @param {Roo.ContentPanel} panel The panel
35038 * @param {Object} e The cancel event object
35040 "beforeremove" : true,
35042 * @event invalidated
35043 * Fires when the layout for this region is changed.
35044 * @param {Roo.LayoutRegion} this
35046 "invalidated" : true,
35048 * @event visibilitychange
35049 * Fires when this region is shown or hidden
35050 * @param {Roo.LayoutRegion} this
35051 * @param {Boolean} visibility true or false
35053 "visibilitychange" : true,
35055 * @event paneladded
35056 * Fires when a panel is added.
35057 * @param {Roo.LayoutRegion} this
35058 * @param {Roo.ContentPanel} panel The panel
35060 "paneladded" : true,
35062 * @event panelremoved
35063 * Fires when a panel is removed.
35064 * @param {Roo.LayoutRegion} this
35065 * @param {Roo.ContentPanel} panel The panel
35067 "panelremoved" : true,
35069 * @event beforecollapse
35070 * Fires when this region before collapse.
35071 * @param {Roo.LayoutRegion} this
35073 "beforecollapse" : true,
35076 * Fires when this region is collapsed.
35077 * @param {Roo.LayoutRegion} this
35079 "collapsed" : true,
35082 * Fires when this region is expanded.
35083 * @param {Roo.LayoutRegion} this
35088 * Fires when this region is slid into view.
35089 * @param {Roo.LayoutRegion} this
35091 "slideshow" : true,
35094 * Fires when this region slides out of view.
35095 * @param {Roo.LayoutRegion} this
35097 "slidehide" : true,
35099 * @event panelactivated
35100 * Fires when a panel is activated.
35101 * @param {Roo.LayoutRegion} this
35102 * @param {Roo.ContentPanel} panel The activated panel
35104 "panelactivated" : true,
35107 * Fires when the user resizes this region.
35108 * @param {Roo.LayoutRegion} this
35109 * @param {Number} newSize The new size (width for east/west, height for north/south)
35113 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35114 this.panels = new Roo.util.MixedCollection();
35115 this.panels.getKey = this.getPanelId.createDelegate(this);
35117 this.activePanel = null;
35118 // ensure listeners are added...
35120 if (config.listeners || config.events) {
35121 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35122 listeners : config.listeners || {},
35123 events : config.events || {}
35127 if(skipConfig !== true){
35128 this.applyConfig(config);
35132 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35134 getPanelId : function(p){
35138 applyConfig : function(config){
35139 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35140 this.config = config;
35145 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35146 * the width, for horizontal (north, south) the height.
35147 * @param {Number} newSize The new width or height
35149 resizeTo : function(newSize){
35150 var el = this.el ? this.el :
35151 (this.activePanel ? this.activePanel.getEl() : null);
35153 switch(this.position){
35156 el.setWidth(newSize);
35157 this.fireEvent("resized", this, newSize);
35161 el.setHeight(newSize);
35162 this.fireEvent("resized", this, newSize);
35168 getBox : function(){
35169 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35172 getMargins : function(){
35173 return this.margins;
35176 updateBox : function(box){
35178 var el = this.activePanel.getEl();
35179 el.dom.style.left = box.x + "px";
35180 el.dom.style.top = box.y + "px";
35181 this.activePanel.setSize(box.width, box.height);
35185 * Returns the container element for this region.
35186 * @return {Roo.Element}
35188 getEl : function(){
35189 return this.activePanel;
35193 * Returns true if this region is currently visible.
35194 * @return {Boolean}
35196 isVisible : function(){
35197 return this.activePanel ? true : false;
35200 setActivePanel : function(panel){
35201 panel = this.getPanel(panel);
35202 if(this.activePanel && this.activePanel != panel){
35203 this.activePanel.setActiveState(false);
35204 this.activePanel.getEl().setLeftTop(-10000,-10000);
35206 this.activePanel = panel;
35207 panel.setActiveState(true);
35209 panel.setSize(this.box.width, this.box.height);
35211 this.fireEvent("panelactivated", this, panel);
35212 this.fireEvent("invalidated");
35216 * Show the specified panel.
35217 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35218 * @return {Roo.ContentPanel} The shown panel or null
35220 showPanel : function(panel){
35221 panel = this.getPanel(panel);
35223 this.setActivePanel(panel);
35229 * Get the active panel for this region.
35230 * @return {Roo.ContentPanel} The active panel or null
35232 getActivePanel : function(){
35233 return this.activePanel;
35237 * Add the passed ContentPanel(s)
35238 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35239 * @return {Roo.ContentPanel} The panel added (if only one was added)
35241 add : function(panel){
35242 if(arguments.length > 1){
35243 for(var i = 0, len = arguments.length; i < len; i++) {
35244 this.add(arguments[i]);
35248 if(this.hasPanel(panel)){
35249 this.showPanel(panel);
35252 var el = panel.getEl();
35253 if(el.dom.parentNode != this.mgr.el.dom){
35254 this.mgr.el.dom.appendChild(el.dom);
35256 if(panel.setRegion){
35257 panel.setRegion(this);
35259 this.panels.add(panel);
35260 el.setStyle("position", "absolute");
35261 if(!panel.background){
35262 this.setActivePanel(panel);
35263 if(this.config.initialSize && this.panels.getCount()==1){
35264 this.resizeTo(this.config.initialSize);
35267 this.fireEvent("paneladded", this, panel);
35272 * Returns true if the panel is in this region.
35273 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35274 * @return {Boolean}
35276 hasPanel : function(panel){
35277 if(typeof panel == "object"){ // must be panel obj
35278 panel = panel.getId();
35280 return this.getPanel(panel) ? true : false;
35284 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35285 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35286 * @param {Boolean} preservePanel Overrides the config preservePanel option
35287 * @return {Roo.ContentPanel} The panel that was removed
35289 remove : function(panel, preservePanel){
35290 panel = this.getPanel(panel);
35295 this.fireEvent("beforeremove", this, panel, e);
35296 if(e.cancel === true){
35299 var panelId = panel.getId();
35300 this.panels.removeKey(panelId);
35305 * Returns the panel specified or null if it's not in this region.
35306 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35307 * @return {Roo.ContentPanel}
35309 getPanel : function(id){
35310 if(typeof id == "object"){ // must be panel obj
35313 return this.panels.get(id);
35317 * Returns this regions position (north/south/east/west/center).
35320 getPosition: function(){
35321 return this.position;
35325 * Ext JS Library 1.1.1
35326 * Copyright(c) 2006-2007, Ext JS, LLC.
35328 * Originally Released Under LGPL - original licence link has changed is not relivant.
35331 * <script type="text/javascript">
35335 * @class Roo.bootstrap.layout.Region
35336 * @extends Roo.bootstrap.layout.Basic
35337 * This class represents a region in a layout manager.
35339 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35340 * @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})
35341 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35342 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35343 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35344 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35345 * @cfg {String} title The title for the region (overrides panel titles)
35346 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35347 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35348 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35349 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35350 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35351 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35352 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35353 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35354 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35355 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35357 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35358 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35359 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35360 * @cfg {Number} width For East/West panels
35361 * @cfg {Number} height For North/South panels
35362 * @cfg {Boolean} split To show the splitter
35363 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35365 * @cfg {string} cls Extra CSS classes to add to region
35367 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35368 * @cfg {string} region the region that it inhabits..
35371 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35372 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35374 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35375 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35376 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35378 Roo.bootstrap.layout.Region = function(config)
35380 this.applyConfig(config);
35382 var mgr = config.mgr;
35383 var pos = config.region;
35384 config.skipConfig = true;
35385 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35388 this.onRender(mgr.el);
35391 this.visible = true;
35392 this.collapsed = false;
35393 this.unrendered_panels = [];
35396 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35398 position: '', // set by wrapper (eg. north/south etc..)
35399 unrendered_panels : null, // unrendered panels.
35400 createBody : function(){
35401 /** This region's body element
35402 * @type Roo.Element */
35403 this.bodyEl = this.el.createChild({
35405 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35409 onRender: function(ctr, pos)
35411 var dh = Roo.DomHelper;
35412 /** This region's container element
35413 * @type Roo.Element */
35414 this.el = dh.append(ctr.dom, {
35416 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35418 /** This region's title element
35419 * @type Roo.Element */
35421 this.titleEl = dh.append(this.el.dom,
35424 unselectable: "on",
35425 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35427 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35428 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35431 this.titleEl.enableDisplayMode();
35432 /** This region's title text element
35433 * @type HTMLElement */
35434 this.titleTextEl = this.titleEl.dom.firstChild;
35435 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35437 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35438 this.closeBtn.enableDisplayMode();
35439 this.closeBtn.on("click", this.closeClicked, this);
35440 this.closeBtn.hide();
35442 this.createBody(this.config);
35443 if(this.config.hideWhenEmpty){
35445 this.on("paneladded", this.validateVisibility, this);
35446 this.on("panelremoved", this.validateVisibility, this);
35448 if(this.autoScroll){
35449 this.bodyEl.setStyle("overflow", "auto");
35451 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35453 //if(c.titlebar !== false){
35454 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35455 this.titleEl.hide();
35457 this.titleEl.show();
35458 if(this.config.title){
35459 this.titleTextEl.innerHTML = this.config.title;
35463 if(this.config.collapsed){
35464 this.collapse(true);
35466 if(this.config.hidden){
35470 if (this.unrendered_panels && this.unrendered_panels.length) {
35471 for (var i =0;i< this.unrendered_panels.length; i++) {
35472 this.add(this.unrendered_panels[i]);
35474 this.unrendered_panels = null;
35480 applyConfig : function(c)
35483 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35484 var dh = Roo.DomHelper;
35485 if(c.titlebar !== false){
35486 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35487 this.collapseBtn.on("click", this.collapse, this);
35488 this.collapseBtn.enableDisplayMode();
35490 if(c.showPin === true || this.showPin){
35491 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35492 this.stickBtn.enableDisplayMode();
35493 this.stickBtn.on("click", this.expand, this);
35494 this.stickBtn.hide();
35499 /** This region's collapsed element
35500 * @type Roo.Element */
35503 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35504 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35507 if(c.floatable !== false){
35508 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35509 this.collapsedEl.on("click", this.collapseClick, this);
35512 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35513 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35514 id: "message", unselectable: "on", style:{"float":"left"}});
35515 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35517 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35518 this.expandBtn.on("click", this.expand, this);
35522 if(this.collapseBtn){
35523 this.collapseBtn.setVisible(c.collapsible == true);
35526 this.cmargins = c.cmargins || this.cmargins ||
35527 (this.position == "west" || this.position == "east" ?
35528 {top: 0, left: 2, right:2, bottom: 0} :
35529 {top: 2, left: 0, right:0, bottom: 2});
35531 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35534 this.bottomTabs = c.tabPosition != "top";
35536 this.autoScroll = c.autoScroll || false;
35541 this.duration = c.duration || .30;
35542 this.slideDuration = c.slideDuration || .45;
35547 * Returns true if this region is currently visible.
35548 * @return {Boolean}
35550 isVisible : function(){
35551 return this.visible;
35555 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35556 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35558 //setCollapsedTitle : function(title){
35559 // title = title || " ";
35560 // if(this.collapsedTitleTextEl){
35561 // this.collapsedTitleTextEl.innerHTML = title;
35565 getBox : function(){
35567 // if(!this.collapsed){
35568 b = this.el.getBox(false, true);
35570 // b = this.collapsedEl.getBox(false, true);
35575 getMargins : function(){
35576 return this.margins;
35577 //return this.collapsed ? this.cmargins : this.margins;
35580 highlight : function(){
35581 this.el.addClass("x-layout-panel-dragover");
35584 unhighlight : function(){
35585 this.el.removeClass("x-layout-panel-dragover");
35588 updateBox : function(box)
35590 if (!this.bodyEl) {
35591 return; // not rendered yet..
35595 if(!this.collapsed){
35596 this.el.dom.style.left = box.x + "px";
35597 this.el.dom.style.top = box.y + "px";
35598 this.updateBody(box.width, box.height);
35600 this.collapsedEl.dom.style.left = box.x + "px";
35601 this.collapsedEl.dom.style.top = box.y + "px";
35602 this.collapsedEl.setSize(box.width, box.height);
35605 this.tabs.autoSizeTabs();
35609 updateBody : function(w, h)
35612 this.el.setWidth(w);
35613 w -= this.el.getBorderWidth("rl");
35614 if(this.config.adjustments){
35615 w += this.config.adjustments[0];
35618 if(h !== null && h > 0){
35619 this.el.setHeight(h);
35620 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35621 h -= this.el.getBorderWidth("tb");
35622 if(this.config.adjustments){
35623 h += this.config.adjustments[1];
35625 this.bodyEl.setHeight(h);
35627 h = this.tabs.syncHeight(h);
35630 if(this.panelSize){
35631 w = w !== null ? w : this.panelSize.width;
35632 h = h !== null ? h : this.panelSize.height;
35634 if(this.activePanel){
35635 var el = this.activePanel.getEl();
35636 w = w !== null ? w : el.getWidth();
35637 h = h !== null ? h : el.getHeight();
35638 this.panelSize = {width: w, height: h};
35639 this.activePanel.setSize(w, h);
35641 if(Roo.isIE && this.tabs){
35642 this.tabs.el.repaint();
35647 * Returns the container element for this region.
35648 * @return {Roo.Element}
35650 getEl : function(){
35655 * Hides this region.
35658 //if(!this.collapsed){
35659 this.el.dom.style.left = "-2000px";
35662 // this.collapsedEl.dom.style.left = "-2000px";
35663 // this.collapsedEl.hide();
35665 this.visible = false;
35666 this.fireEvent("visibilitychange", this, false);
35670 * Shows this region if it was previously hidden.
35673 //if(!this.collapsed){
35676 // this.collapsedEl.show();
35678 this.visible = true;
35679 this.fireEvent("visibilitychange", this, true);
35682 closeClicked : function(){
35683 if(this.activePanel){
35684 this.remove(this.activePanel);
35688 collapseClick : function(e){
35690 e.stopPropagation();
35693 e.stopPropagation();
35699 * Collapses this region.
35700 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35703 collapse : function(skipAnim, skipCheck = false){
35704 if(this.collapsed) {
35708 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35710 this.collapsed = true;
35712 this.split.el.hide();
35714 if(this.config.animate && skipAnim !== true){
35715 this.fireEvent("invalidated", this);
35716 this.animateCollapse();
35718 this.el.setLocation(-20000,-20000);
35720 this.collapsedEl.show();
35721 this.fireEvent("collapsed", this);
35722 this.fireEvent("invalidated", this);
35728 animateCollapse : function(){
35733 * Expands this region if it was previously collapsed.
35734 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35735 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35738 expand : function(e, skipAnim){
35740 e.stopPropagation();
35742 if(!this.collapsed || this.el.hasActiveFx()) {
35746 this.afterSlideIn();
35749 this.collapsed = false;
35750 if(this.config.animate && skipAnim !== true){
35751 this.animateExpand();
35755 this.split.el.show();
35757 this.collapsedEl.setLocation(-2000,-2000);
35758 this.collapsedEl.hide();
35759 this.fireEvent("invalidated", this);
35760 this.fireEvent("expanded", this);
35764 animateExpand : function(){
35768 initTabs : function()
35770 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35772 var ts = new Roo.bootstrap.panel.Tabs({
35773 el: this.bodyEl.dom,
35774 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35775 disableTooltips: this.config.disableTabTips,
35776 toolbar : this.config.toolbar
35779 if(this.config.hideTabs){
35780 ts.stripWrap.setDisplayed(false);
35783 ts.resizeTabs = this.config.resizeTabs === true;
35784 ts.minTabWidth = this.config.minTabWidth || 40;
35785 ts.maxTabWidth = this.config.maxTabWidth || 250;
35786 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35787 ts.monitorResize = false;
35788 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35789 ts.bodyEl.addClass('roo-layout-tabs-body');
35790 this.panels.each(this.initPanelAsTab, this);
35793 initPanelAsTab : function(panel){
35794 var ti = this.tabs.addTab(
35798 this.config.closeOnTab && panel.isClosable(),
35801 if(panel.tabTip !== undefined){
35802 ti.setTooltip(panel.tabTip);
35804 ti.on("activate", function(){
35805 this.setActivePanel(panel);
35808 if(this.config.closeOnTab){
35809 ti.on("beforeclose", function(t, e){
35811 this.remove(panel);
35815 panel.tabItem = ti;
35820 updatePanelTitle : function(panel, title)
35822 if(this.activePanel == panel){
35823 this.updateTitle(title);
35826 var ti = this.tabs.getTab(panel.getEl().id);
35828 if(panel.tabTip !== undefined){
35829 ti.setTooltip(panel.tabTip);
35834 updateTitle : function(title){
35835 if(this.titleTextEl && !this.config.title){
35836 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35840 setActivePanel : function(panel)
35842 panel = this.getPanel(panel);
35843 if(this.activePanel && this.activePanel != panel){
35844 if(this.activePanel.setActiveState(false) === false){
35848 this.activePanel = panel;
35849 panel.setActiveState(true);
35850 if(this.panelSize){
35851 panel.setSize(this.panelSize.width, this.panelSize.height);
35854 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35856 this.updateTitle(panel.getTitle());
35858 this.fireEvent("invalidated", this);
35860 this.fireEvent("panelactivated", this, panel);
35864 * Shows the specified panel.
35865 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35866 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35868 showPanel : function(panel)
35870 panel = this.getPanel(panel);
35873 var tab = this.tabs.getTab(panel.getEl().id);
35874 if(tab.isHidden()){
35875 this.tabs.unhideTab(tab.id);
35879 this.setActivePanel(panel);
35886 * Get the active panel for this region.
35887 * @return {Roo.ContentPanel} The active panel or null
35889 getActivePanel : function(){
35890 return this.activePanel;
35893 validateVisibility : function(){
35894 if(this.panels.getCount() < 1){
35895 this.updateTitle(" ");
35896 this.closeBtn.hide();
35899 if(!this.isVisible()){
35906 * Adds the passed ContentPanel(s) to this region.
35907 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35908 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35910 add : function(panel)
35912 if(arguments.length > 1){
35913 for(var i = 0, len = arguments.length; i < len; i++) {
35914 this.add(arguments[i]);
35919 // if we have not been rendered yet, then we can not really do much of this..
35920 if (!this.bodyEl) {
35921 this.unrendered_panels.push(panel);
35928 if(this.hasPanel(panel)){
35929 this.showPanel(panel);
35932 panel.setRegion(this);
35933 this.panels.add(panel);
35934 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35935 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35936 // and hide them... ???
35937 this.bodyEl.dom.appendChild(panel.getEl().dom);
35938 if(panel.background !== true){
35939 this.setActivePanel(panel);
35941 this.fireEvent("paneladded", this, panel);
35948 this.initPanelAsTab(panel);
35952 if(panel.background !== true){
35953 this.tabs.activate(panel.getEl().id);
35955 this.fireEvent("paneladded", this, panel);
35960 * Hides the tab for the specified panel.
35961 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35963 hidePanel : function(panel){
35964 if(this.tabs && (panel = this.getPanel(panel))){
35965 this.tabs.hideTab(panel.getEl().id);
35970 * Unhides the tab for a previously hidden panel.
35971 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35973 unhidePanel : function(panel){
35974 if(this.tabs && (panel = this.getPanel(panel))){
35975 this.tabs.unhideTab(panel.getEl().id);
35979 clearPanels : function(){
35980 while(this.panels.getCount() > 0){
35981 this.remove(this.panels.first());
35986 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35987 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35988 * @param {Boolean} preservePanel Overrides the config preservePanel option
35989 * @return {Roo.ContentPanel} The panel that was removed
35991 remove : function(panel, preservePanel)
35993 panel = this.getPanel(panel);
35998 this.fireEvent("beforeremove", this, panel, e);
35999 if(e.cancel === true){
36002 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36003 var panelId = panel.getId();
36004 this.panels.removeKey(panelId);
36006 document.body.appendChild(panel.getEl().dom);
36009 this.tabs.removeTab(panel.getEl().id);
36010 }else if (!preservePanel){
36011 this.bodyEl.dom.removeChild(panel.getEl().dom);
36013 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36014 var p = this.panels.first();
36015 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36016 tempEl.appendChild(p.getEl().dom);
36017 this.bodyEl.update("");
36018 this.bodyEl.dom.appendChild(p.getEl().dom);
36020 this.updateTitle(p.getTitle());
36022 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36023 this.setActivePanel(p);
36025 panel.setRegion(null);
36026 if(this.activePanel == panel){
36027 this.activePanel = null;
36029 if(this.config.autoDestroy !== false && preservePanel !== true){
36030 try{panel.destroy();}catch(e){}
36032 this.fireEvent("panelremoved", this, panel);
36037 * Returns the TabPanel component used by this region
36038 * @return {Roo.TabPanel}
36040 getTabs : function(){
36044 createTool : function(parentEl, className){
36045 var btn = Roo.DomHelper.append(parentEl, {
36047 cls: "x-layout-tools-button",
36050 cls: "roo-layout-tools-button-inner " + className,
36054 btn.addClassOnOver("roo-layout-tools-button-over");
36059 * Ext JS Library 1.1.1
36060 * Copyright(c) 2006-2007, Ext JS, LLC.
36062 * Originally Released Under LGPL - original licence link has changed is not relivant.
36065 * <script type="text/javascript">
36071 * @class Roo.SplitLayoutRegion
36072 * @extends Roo.LayoutRegion
36073 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36075 Roo.bootstrap.layout.Split = function(config){
36076 this.cursor = config.cursor;
36077 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36080 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36082 splitTip : "Drag to resize.",
36083 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36084 useSplitTips : false,
36086 applyConfig : function(config){
36087 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36090 onRender : function(ctr,pos) {
36092 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36093 if(!this.config.split){
36098 var splitEl = Roo.DomHelper.append(ctr.dom, {
36100 id: this.el.id + "-split",
36101 cls: "roo-layout-split roo-layout-split-"+this.position,
36104 /** The SplitBar for this region
36105 * @type Roo.SplitBar */
36106 // does not exist yet...
36107 Roo.log([this.position, this.orientation]);
36109 this.split = new Roo.bootstrap.SplitBar({
36110 dragElement : splitEl,
36111 resizingElement: this.el,
36112 orientation : this.orientation
36115 this.split.on("moved", this.onSplitMove, this);
36116 this.split.useShim = this.config.useShim === true;
36117 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36118 if(this.useSplitTips){
36119 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36121 //if(config.collapsible){
36122 // this.split.el.on("dblclick", this.collapse, this);
36125 if(typeof this.config.minSize != "undefined"){
36126 this.split.minSize = this.config.minSize;
36128 if(typeof this.config.maxSize != "undefined"){
36129 this.split.maxSize = this.config.maxSize;
36131 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36132 this.hideSplitter();
36137 getHMaxSize : function(){
36138 var cmax = this.config.maxSize || 10000;
36139 var center = this.mgr.getRegion("center");
36140 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36143 getVMaxSize : function(){
36144 var cmax = this.config.maxSize || 10000;
36145 var center = this.mgr.getRegion("center");
36146 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36149 onSplitMove : function(split, newSize){
36150 this.fireEvent("resized", this, newSize);
36154 * Returns the {@link Roo.SplitBar} for this region.
36155 * @return {Roo.SplitBar}
36157 getSplitBar : function(){
36162 this.hideSplitter();
36163 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36166 hideSplitter : function(){
36168 this.split.el.setLocation(-2000,-2000);
36169 this.split.el.hide();
36175 this.split.el.show();
36177 Roo.bootstrap.layout.Split.superclass.show.call(this);
36180 beforeSlide: function(){
36181 if(Roo.isGecko){// firefox overflow auto bug workaround
36182 this.bodyEl.clip();
36184 this.tabs.bodyEl.clip();
36186 if(this.activePanel){
36187 this.activePanel.getEl().clip();
36189 if(this.activePanel.beforeSlide){
36190 this.activePanel.beforeSlide();
36196 afterSlide : function(){
36197 if(Roo.isGecko){// firefox overflow auto bug workaround
36198 this.bodyEl.unclip();
36200 this.tabs.bodyEl.unclip();
36202 if(this.activePanel){
36203 this.activePanel.getEl().unclip();
36204 if(this.activePanel.afterSlide){
36205 this.activePanel.afterSlide();
36211 initAutoHide : function(){
36212 if(this.autoHide !== false){
36213 if(!this.autoHideHd){
36214 var st = new Roo.util.DelayedTask(this.slideIn, this);
36215 this.autoHideHd = {
36216 "mouseout": function(e){
36217 if(!e.within(this.el, true)){
36221 "mouseover" : function(e){
36227 this.el.on(this.autoHideHd);
36231 clearAutoHide : function(){
36232 if(this.autoHide !== false){
36233 this.el.un("mouseout", this.autoHideHd.mouseout);
36234 this.el.un("mouseover", this.autoHideHd.mouseover);
36238 clearMonitor : function(){
36239 Roo.get(document).un("click", this.slideInIf, this);
36242 // these names are backwards but not changed for compat
36243 slideOut : function(){
36244 if(this.isSlid || this.el.hasActiveFx()){
36247 this.isSlid = true;
36248 if(this.collapseBtn){
36249 this.collapseBtn.hide();
36251 this.closeBtnState = this.closeBtn.getStyle('display');
36252 this.closeBtn.hide();
36254 this.stickBtn.show();
36257 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36258 this.beforeSlide();
36259 this.el.setStyle("z-index", 10001);
36260 this.el.slideIn(this.getSlideAnchor(), {
36261 callback: function(){
36263 this.initAutoHide();
36264 Roo.get(document).on("click", this.slideInIf, this);
36265 this.fireEvent("slideshow", this);
36272 afterSlideIn : function(){
36273 this.clearAutoHide();
36274 this.isSlid = false;
36275 this.clearMonitor();
36276 this.el.setStyle("z-index", "");
36277 if(this.collapseBtn){
36278 this.collapseBtn.show();
36280 this.closeBtn.setStyle('display', this.closeBtnState);
36282 this.stickBtn.hide();
36284 this.fireEvent("slidehide", this);
36287 slideIn : function(cb){
36288 if(!this.isSlid || this.el.hasActiveFx()){
36292 this.isSlid = false;
36293 this.beforeSlide();
36294 this.el.slideOut(this.getSlideAnchor(), {
36295 callback: function(){
36296 this.el.setLeftTop(-10000, -10000);
36298 this.afterSlideIn();
36306 slideInIf : function(e){
36307 if(!e.within(this.el)){
36312 animateCollapse : function(){
36313 this.beforeSlide();
36314 this.el.setStyle("z-index", 20000);
36315 var anchor = this.getSlideAnchor();
36316 this.el.slideOut(anchor, {
36317 callback : function(){
36318 this.el.setStyle("z-index", "");
36319 this.collapsedEl.slideIn(anchor, {duration:.3});
36321 this.el.setLocation(-10000,-10000);
36323 this.fireEvent("collapsed", this);
36330 animateExpand : function(){
36331 this.beforeSlide();
36332 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36333 this.el.setStyle("z-index", 20000);
36334 this.collapsedEl.hide({
36337 this.el.slideIn(this.getSlideAnchor(), {
36338 callback : function(){
36339 this.el.setStyle("z-index", "");
36342 this.split.el.show();
36344 this.fireEvent("invalidated", this);
36345 this.fireEvent("expanded", this);
36373 getAnchor : function(){
36374 return this.anchors[this.position];
36377 getCollapseAnchor : function(){
36378 return this.canchors[this.position];
36381 getSlideAnchor : function(){
36382 return this.sanchors[this.position];
36385 getAlignAdj : function(){
36386 var cm = this.cmargins;
36387 switch(this.position){
36403 getExpandAdj : function(){
36404 var c = this.collapsedEl, cm = this.cmargins;
36405 switch(this.position){
36407 return [-(cm.right+c.getWidth()+cm.left), 0];
36410 return [cm.right+c.getWidth()+cm.left, 0];
36413 return [0, -(cm.top+cm.bottom+c.getHeight())];
36416 return [0, cm.top+cm.bottom+c.getHeight()];
36422 * Ext JS Library 1.1.1
36423 * Copyright(c) 2006-2007, Ext JS, LLC.
36425 * Originally Released Under LGPL - original licence link has changed is not relivant.
36428 * <script type="text/javascript">
36431 * These classes are private internal classes
36433 Roo.bootstrap.layout.Center = function(config){
36434 config.region = "center";
36435 Roo.bootstrap.layout.Region.call(this, config);
36436 this.visible = true;
36437 this.minWidth = config.minWidth || 20;
36438 this.minHeight = config.minHeight || 20;
36441 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36443 // center panel can't be hidden
36447 // center panel can't be hidden
36450 getMinWidth: function(){
36451 return this.minWidth;
36454 getMinHeight: function(){
36455 return this.minHeight;
36468 Roo.bootstrap.layout.North = function(config)
36470 config.region = 'north';
36471 config.cursor = 'n-resize';
36473 Roo.bootstrap.layout.Split.call(this, config);
36477 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36478 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36479 this.split.el.addClass("roo-layout-split-v");
36481 var size = config.initialSize || config.height;
36482 if(typeof size != "undefined"){
36483 this.el.setHeight(size);
36486 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36488 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36492 getBox : function(){
36493 if(this.collapsed){
36494 return this.collapsedEl.getBox();
36496 var box = this.el.getBox();
36498 box.height += this.split.el.getHeight();
36503 updateBox : function(box){
36504 if(this.split && !this.collapsed){
36505 box.height -= this.split.el.getHeight();
36506 this.split.el.setLeft(box.x);
36507 this.split.el.setTop(box.y+box.height);
36508 this.split.el.setWidth(box.width);
36510 if(this.collapsed){
36511 this.updateBody(box.width, null);
36513 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36521 Roo.bootstrap.layout.South = function(config){
36522 config.region = 'south';
36523 config.cursor = 's-resize';
36524 Roo.bootstrap.layout.Split.call(this, config);
36526 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36527 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36528 this.split.el.addClass("roo-layout-split-v");
36530 var size = config.initialSize || config.height;
36531 if(typeof size != "undefined"){
36532 this.el.setHeight(size);
36536 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36537 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36538 getBox : function(){
36539 if(this.collapsed){
36540 return this.collapsedEl.getBox();
36542 var box = this.el.getBox();
36544 var sh = this.split.el.getHeight();
36551 updateBox : function(box){
36552 if(this.split && !this.collapsed){
36553 var sh = this.split.el.getHeight();
36556 this.split.el.setLeft(box.x);
36557 this.split.el.setTop(box.y-sh);
36558 this.split.el.setWidth(box.width);
36560 if(this.collapsed){
36561 this.updateBody(box.width, null);
36563 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36567 Roo.bootstrap.layout.East = function(config){
36568 config.region = "east";
36569 config.cursor = "e-resize";
36570 Roo.bootstrap.layout.Split.call(this, config);
36572 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36573 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36574 this.split.el.addClass("roo-layout-split-h");
36576 var size = config.initialSize || config.width;
36577 if(typeof size != "undefined"){
36578 this.el.setWidth(size);
36581 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36582 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36583 getBox : function(){
36584 if(this.collapsed){
36585 return this.collapsedEl.getBox();
36587 var box = this.el.getBox();
36589 var sw = this.split.el.getWidth();
36596 updateBox : function(box){
36597 if(this.split && !this.collapsed){
36598 var sw = this.split.el.getWidth();
36600 this.split.el.setLeft(box.x);
36601 this.split.el.setTop(box.y);
36602 this.split.el.setHeight(box.height);
36605 if(this.collapsed){
36606 this.updateBody(null, box.height);
36608 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36612 Roo.bootstrap.layout.West = function(config){
36613 config.region = "west";
36614 config.cursor = "w-resize";
36616 Roo.bootstrap.layout.Split.call(this, config);
36618 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36619 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36620 this.split.el.addClass("roo-layout-split-h");
36624 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36625 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36627 onRender: function(ctr, pos)
36629 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36630 var size = this.config.initialSize || this.config.width;
36631 if(typeof size != "undefined"){
36632 this.el.setWidth(size);
36636 getBox : function(){
36637 if(this.collapsed){
36638 return this.collapsedEl.getBox();
36640 var box = this.el.getBox();
36642 box.width += this.split.el.getWidth();
36647 updateBox : function(box){
36648 if(this.split && !this.collapsed){
36649 var sw = this.split.el.getWidth();
36651 this.split.el.setLeft(box.x+box.width);
36652 this.split.el.setTop(box.y);
36653 this.split.el.setHeight(box.height);
36655 if(this.collapsed){
36656 this.updateBody(null, box.height);
36658 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36661 Roo.namespace("Roo.bootstrap.panel");/*
36663 * Ext JS Library 1.1.1
36664 * Copyright(c) 2006-2007, Ext JS, LLC.
36666 * Originally Released Under LGPL - original licence link has changed is not relivant.
36669 * <script type="text/javascript">
36672 * @class Roo.ContentPanel
36673 * @extends Roo.util.Observable
36674 * A basic ContentPanel element.
36675 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36676 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36677 * @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
36678 * @cfg {Boolean} closable True if the panel can be closed/removed
36679 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36680 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36681 * @cfg {Toolbar} toolbar A toolbar for this panel
36682 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36683 * @cfg {String} title The title for this panel
36684 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36685 * @cfg {String} url Calls {@link #setUrl} with this value
36686 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36687 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36688 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36689 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36690 * @cfg {Boolean} badges render the badges
36693 * Create a new ContentPanel.
36694 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36695 * @param {String/Object} config A string to set only the title or a config object
36696 * @param {String} content (optional) Set the HTML content for this panel
36697 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36699 Roo.bootstrap.panel.Content = function( config){
36701 this.tpl = config.tpl || false;
36703 var el = config.el;
36704 var content = config.content;
36706 if(config.autoCreate){ // xtype is available if this is called from factory
36709 this.el = Roo.get(el);
36710 if(!this.el && config && config.autoCreate){
36711 if(typeof config.autoCreate == "object"){
36712 if(!config.autoCreate.id){
36713 config.autoCreate.id = config.id||el;
36715 this.el = Roo.DomHelper.append(document.body,
36716 config.autoCreate, true);
36718 var elcfg = { tag: "div",
36719 cls: "roo-layout-inactive-content",
36723 elcfg.html = config.html;
36727 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36730 this.closable = false;
36731 this.loaded = false;
36732 this.active = false;
36735 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36737 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36739 this.wrapEl = this.el; //this.el.wrap();
36741 if (config.toolbar.items) {
36742 ti = config.toolbar.items ;
36743 delete config.toolbar.items ;
36747 this.toolbar.render(this.wrapEl, 'before');
36748 for(var i =0;i < ti.length;i++) {
36749 // Roo.log(['add child', items[i]]);
36750 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36752 this.toolbar.items = nitems;
36753 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36754 delete config.toolbar;
36758 // xtype created footer. - not sure if will work as we normally have to render first..
36759 if (this.footer && !this.footer.el && this.footer.xtype) {
36760 if (!this.wrapEl) {
36761 this.wrapEl = this.el.wrap();
36764 this.footer.container = this.wrapEl.createChild();
36766 this.footer = Roo.factory(this.footer, Roo);
36771 if(typeof config == "string"){
36772 this.title = config;
36774 Roo.apply(this, config);
36778 this.resizeEl = Roo.get(this.resizeEl, true);
36780 this.resizeEl = this.el;
36782 // handle view.xtype
36790 * Fires when this panel is activated.
36791 * @param {Roo.ContentPanel} this
36795 * @event deactivate
36796 * Fires when this panel is activated.
36797 * @param {Roo.ContentPanel} this
36799 "deactivate" : true,
36803 * Fires when this panel is resized if fitToFrame is true.
36804 * @param {Roo.ContentPanel} this
36805 * @param {Number} width The width after any component adjustments
36806 * @param {Number} height The height after any component adjustments
36812 * Fires when this tab is created
36813 * @param {Roo.ContentPanel} this
36824 if(this.autoScroll){
36825 this.resizeEl.setStyle("overflow", "auto");
36827 // fix randome scrolling
36828 //this.el.on('scroll', function() {
36829 // Roo.log('fix random scolling');
36830 // this.scrollTo('top',0);
36833 content = content || this.content;
36835 this.setContent(content);
36837 if(config && config.url){
36838 this.setUrl(this.url, this.params, this.loadOnce);
36843 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36845 if (this.view && typeof(this.view.xtype) != 'undefined') {
36846 this.view.el = this.el.appendChild(document.createElement("div"));
36847 this.view = Roo.factory(this.view);
36848 this.view.render && this.view.render(false, '');
36852 this.fireEvent('render', this);
36855 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36859 setRegion : function(region){
36860 this.region = region;
36861 this.setActiveClass(region && !this.background);
36865 setActiveClass: function(state)
36868 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36869 this.el.setStyle('position','relative');
36871 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36872 this.el.setStyle('position', 'absolute');
36877 * Returns the toolbar for this Panel if one was configured.
36878 * @return {Roo.Toolbar}
36880 getToolbar : function(){
36881 return this.toolbar;
36884 setActiveState : function(active)
36886 this.active = active;
36887 this.setActiveClass(active);
36889 if(this.fireEvent("deactivate", this) === false){
36894 this.fireEvent("activate", this);
36898 * Updates this panel's element
36899 * @param {String} content The new content
36900 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36902 setContent : function(content, loadScripts){
36903 this.el.update(content, loadScripts);
36906 ignoreResize : function(w, h){
36907 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36910 this.lastSize = {width: w, height: h};
36915 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36916 * @return {Roo.UpdateManager} The UpdateManager
36918 getUpdateManager : function(){
36919 return this.el.getUpdateManager();
36922 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36923 * @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:
36926 url: "your-url.php",
36927 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36928 callback: yourFunction,
36929 scope: yourObject, //(optional scope)
36932 text: "Loading...",
36937 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36938 * 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.
36939 * @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}
36940 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36941 * @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.
36942 * @return {Roo.ContentPanel} this
36945 var um = this.el.getUpdateManager();
36946 um.update.apply(um, arguments);
36952 * 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.
36953 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36954 * @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)
36955 * @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)
36956 * @return {Roo.UpdateManager} The UpdateManager
36958 setUrl : function(url, params, loadOnce){
36959 if(this.refreshDelegate){
36960 this.removeListener("activate", this.refreshDelegate);
36962 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36963 this.on("activate", this.refreshDelegate);
36964 return this.el.getUpdateManager();
36967 _handleRefresh : function(url, params, loadOnce){
36968 if(!loadOnce || !this.loaded){
36969 var updater = this.el.getUpdateManager();
36970 updater.update(url, params, this._setLoaded.createDelegate(this));
36974 _setLoaded : function(){
36975 this.loaded = true;
36979 * Returns this panel's id
36982 getId : function(){
36987 * Returns this panel's element - used by regiosn to add.
36988 * @return {Roo.Element}
36990 getEl : function(){
36991 return this.wrapEl || this.el;
36996 adjustForComponents : function(width, height)
36998 //Roo.log('adjustForComponents ');
36999 if(this.resizeEl != this.el){
37000 width -= this.el.getFrameWidth('lr');
37001 height -= this.el.getFrameWidth('tb');
37004 var te = this.toolbar.getEl();
37005 te.setWidth(width);
37006 height -= te.getHeight();
37009 var te = this.footer.getEl();
37010 te.setWidth(width);
37011 height -= te.getHeight();
37015 if(this.adjustments){
37016 width += this.adjustments[0];
37017 height += this.adjustments[1];
37019 return {"width": width, "height": height};
37022 setSize : function(width, height){
37023 if(this.fitToFrame && !this.ignoreResize(width, height)){
37024 if(this.fitContainer && this.resizeEl != this.el){
37025 this.el.setSize(width, height);
37027 var size = this.adjustForComponents(width, height);
37028 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37029 this.fireEvent('resize', this, size.width, size.height);
37034 * Returns this panel's title
37037 getTitle : function(){
37039 if (typeof(this.title) != 'object') {
37044 for (var k in this.title) {
37045 if (!this.title.hasOwnProperty(k)) {
37049 if (k.indexOf('-') >= 0) {
37050 var s = k.split('-');
37051 for (var i = 0; i<s.length; i++) {
37052 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37055 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37062 * Set this panel's title
37063 * @param {String} title
37065 setTitle : function(title){
37066 this.title = title;
37068 this.region.updatePanelTitle(this, title);
37073 * Returns true is this panel was configured to be closable
37074 * @return {Boolean}
37076 isClosable : function(){
37077 return this.closable;
37080 beforeSlide : function(){
37082 this.resizeEl.clip();
37085 afterSlide : function(){
37087 this.resizeEl.unclip();
37091 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37092 * Will fail silently if the {@link #setUrl} method has not been called.
37093 * This does not activate the panel, just updates its content.
37095 refresh : function(){
37096 if(this.refreshDelegate){
37097 this.loaded = false;
37098 this.refreshDelegate();
37103 * Destroys this panel
37105 destroy : function(){
37106 this.el.removeAllListeners();
37107 var tempEl = document.createElement("span");
37108 tempEl.appendChild(this.el.dom);
37109 tempEl.innerHTML = "";
37115 * form - if the content panel contains a form - this is a reference to it.
37116 * @type {Roo.form.Form}
37120 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37121 * This contains a reference to it.
37127 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37137 * @param {Object} cfg Xtype definition of item to add.
37141 getChildContainer: function () {
37142 return this.getEl();
37147 var ret = new Roo.factory(cfg);
37152 if (cfg.xtype.match(/^Form$/)) {
37155 //if (this.footer) {
37156 // el = this.footer.container.insertSibling(false, 'before');
37158 el = this.el.createChild();
37161 this.form = new Roo.form.Form(cfg);
37164 if ( this.form.allItems.length) {
37165 this.form.render(el.dom);
37169 // should only have one of theses..
37170 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37171 // views.. should not be just added - used named prop 'view''
37173 cfg.el = this.el.appendChild(document.createElement("div"));
37176 var ret = new Roo.factory(cfg);
37178 ret.render && ret.render(false, ''); // render blank..
37188 * @class Roo.bootstrap.panel.Grid
37189 * @extends Roo.bootstrap.panel.Content
37191 * Create a new GridPanel.
37192 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37193 * @param {Object} config A the config object
37199 Roo.bootstrap.panel.Grid = function(config)
37203 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37204 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37206 config.el = this.wrapper;
37207 //this.el = this.wrapper;
37209 if (config.container) {
37210 // ctor'ed from a Border/panel.grid
37213 this.wrapper.setStyle("overflow", "hidden");
37214 this.wrapper.addClass('roo-grid-container');
37219 if(config.toolbar){
37220 var tool_el = this.wrapper.createChild();
37221 this.toolbar = Roo.factory(config.toolbar);
37223 if (config.toolbar.items) {
37224 ti = config.toolbar.items ;
37225 delete config.toolbar.items ;
37229 this.toolbar.render(tool_el);
37230 for(var i =0;i < ti.length;i++) {
37231 // Roo.log(['add child', items[i]]);
37232 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37234 this.toolbar.items = nitems;
37236 delete config.toolbar;
37239 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37240 config.grid.scrollBody = true;;
37241 config.grid.monitorWindowResize = false; // turn off autosizing
37242 config.grid.autoHeight = false;
37243 config.grid.autoWidth = false;
37245 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37247 if (config.background) {
37248 // render grid on panel activation (if panel background)
37249 this.on('activate', function(gp) {
37250 if (!gp.grid.rendered) {
37251 gp.grid.render(this.wrapper);
37252 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37257 this.grid.render(this.wrapper);
37258 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37261 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37262 // ??? needed ??? config.el = this.wrapper;
37267 // xtype created footer. - not sure if will work as we normally have to render first..
37268 if (this.footer && !this.footer.el && this.footer.xtype) {
37270 var ctr = this.grid.getView().getFooterPanel(true);
37271 this.footer.dataSource = this.grid.dataSource;
37272 this.footer = Roo.factory(this.footer, Roo);
37273 this.footer.render(ctr);
37283 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37284 getId : function(){
37285 return this.grid.id;
37289 * Returns the grid for this panel
37290 * @return {Roo.bootstrap.Table}
37292 getGrid : function(){
37296 setSize : function(width, height){
37297 if(!this.ignoreResize(width, height)){
37298 var grid = this.grid;
37299 var size = this.adjustForComponents(width, height);
37300 var gridel = grid.getGridEl();
37301 gridel.setSize(size.width, size.height);
37303 var thd = grid.getGridEl().select('thead',true).first();
37304 var tbd = grid.getGridEl().select('tbody', true).first();
37306 tbd.setSize(width, height - thd.getHeight());
37315 beforeSlide : function(){
37316 this.grid.getView().scroller.clip();
37319 afterSlide : function(){
37320 this.grid.getView().scroller.unclip();
37323 destroy : function(){
37324 this.grid.destroy();
37326 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37331 * @class Roo.bootstrap.panel.Nest
37332 * @extends Roo.bootstrap.panel.Content
37334 * Create a new Panel, that can contain a layout.Border.
37337 * @param {Roo.BorderLayout} layout The layout for this panel
37338 * @param {String/Object} config A string to set only the title or a config object
37340 Roo.bootstrap.panel.Nest = function(config)
37342 // construct with only one argument..
37343 /* FIXME - implement nicer consturctors
37344 if (layout.layout) {
37346 layout = config.layout;
37347 delete config.layout;
37349 if (layout.xtype && !layout.getEl) {
37350 // then layout needs constructing..
37351 layout = Roo.factory(layout, Roo);
37355 config.el = config.layout.getEl();
37357 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37359 config.layout.monitorWindowResize = false; // turn off autosizing
37360 this.layout = config.layout;
37361 this.layout.getEl().addClass("roo-layout-nested-layout");
37368 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37370 setSize : function(width, height){
37371 if(!this.ignoreResize(width, height)){
37372 var size = this.adjustForComponents(width, height);
37373 var el = this.layout.getEl();
37374 if (size.height < 1) {
37375 el.setWidth(size.width);
37377 el.setSize(size.width, size.height);
37379 var touch = el.dom.offsetWidth;
37380 this.layout.layout();
37381 // ie requires a double layout on the first pass
37382 if(Roo.isIE && !this.initialized){
37383 this.initialized = true;
37384 this.layout.layout();
37389 // activate all subpanels if not currently active..
37391 setActiveState : function(active){
37392 this.active = active;
37393 this.setActiveClass(active);
37396 this.fireEvent("deactivate", this);
37400 this.fireEvent("activate", this);
37401 // not sure if this should happen before or after..
37402 if (!this.layout) {
37403 return; // should not happen..
37406 for (var r in this.layout.regions) {
37407 reg = this.layout.getRegion(r);
37408 if (reg.getActivePanel()) {
37409 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37410 reg.setActivePanel(reg.getActivePanel());
37413 if (!reg.panels.length) {
37416 reg.showPanel(reg.getPanel(0));
37425 * Returns the nested BorderLayout for this panel
37426 * @return {Roo.BorderLayout}
37428 getLayout : function(){
37429 return this.layout;
37433 * Adds a xtype elements to the layout of the nested panel
37437 xtype : 'ContentPanel',
37444 xtype : 'NestedLayoutPanel',
37450 items : [ ... list of content panels or nested layout panels.. ]
37454 * @param {Object} cfg Xtype definition of item to add.
37456 addxtype : function(cfg) {
37457 return this.layout.addxtype(cfg);
37462 * Ext JS Library 1.1.1
37463 * Copyright(c) 2006-2007, Ext JS, LLC.
37465 * Originally Released Under LGPL - original licence link has changed is not relivant.
37468 * <script type="text/javascript">
37471 * @class Roo.TabPanel
37472 * @extends Roo.util.Observable
37473 * A lightweight tab container.
37477 // basic tabs 1, built from existing content
37478 var tabs = new Roo.TabPanel("tabs1");
37479 tabs.addTab("script", "View Script");
37480 tabs.addTab("markup", "View Markup");
37481 tabs.activate("script");
37483 // more advanced tabs, built from javascript
37484 var jtabs = new Roo.TabPanel("jtabs");
37485 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37487 // set up the UpdateManager
37488 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37489 var updater = tab2.getUpdateManager();
37490 updater.setDefaultUrl("ajax1.htm");
37491 tab2.on('activate', updater.refresh, updater, true);
37493 // Use setUrl for Ajax loading
37494 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37495 tab3.setUrl("ajax2.htm", null, true);
37498 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37501 jtabs.activate("jtabs-1");
37504 * Create a new TabPanel.
37505 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37506 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37508 Roo.bootstrap.panel.Tabs = function(config){
37510 * The container element for this TabPanel.
37511 * @type Roo.Element
37513 this.el = Roo.get(config.el);
37516 if(typeof config == "boolean"){
37517 this.tabPosition = config ? "bottom" : "top";
37519 Roo.apply(this, config);
37523 if(this.tabPosition == "bottom"){
37524 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37525 this.el.addClass("roo-tabs-bottom");
37527 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37528 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37529 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37531 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37533 if(this.tabPosition != "bottom"){
37534 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37535 * @type Roo.Element
37537 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37538 this.el.addClass("roo-tabs-top");
37542 this.bodyEl.setStyle("position", "relative");
37544 this.active = null;
37545 this.activateDelegate = this.activate.createDelegate(this);
37550 * Fires when the active tab changes
37551 * @param {Roo.TabPanel} this
37552 * @param {Roo.TabPanelItem} activePanel The new active tab
37556 * @event beforetabchange
37557 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37558 * @param {Roo.TabPanel} this
37559 * @param {Object} e Set cancel to true on this object to cancel the tab change
37560 * @param {Roo.TabPanelItem} tab The tab being changed to
37562 "beforetabchange" : true
37565 Roo.EventManager.onWindowResize(this.onResize, this);
37566 this.cpad = this.el.getPadding("lr");
37567 this.hiddenCount = 0;
37570 // toolbar on the tabbar support...
37571 if (this.toolbar) {
37572 alert("no toolbar support yet");
37573 this.toolbar = false;
37575 var tcfg = this.toolbar;
37576 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37577 this.toolbar = new Roo.Toolbar(tcfg);
37578 if (Roo.isSafari) {
37579 var tbl = tcfg.container.child('table', true);
37580 tbl.setAttribute('width', '100%');
37588 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37591 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37593 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37595 tabPosition : "top",
37597 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37599 currentTabWidth : 0,
37601 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37605 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37609 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37611 preferredTabWidth : 175,
37613 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37615 resizeTabs : false,
37617 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37619 monitorResize : true,
37621 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37626 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37627 * @param {String} id The id of the div to use <b>or create</b>
37628 * @param {String} text The text for the tab
37629 * @param {String} content (optional) Content to put in the TabPanelItem body
37630 * @param {Boolean} closable (optional) True to create a close icon on the tab
37631 * @return {Roo.TabPanelItem} The created TabPanelItem
37633 addTab : function(id, text, content, closable, tpl)
37635 var item = new Roo.bootstrap.panel.TabItem({
37639 closable : closable,
37642 this.addTabItem(item);
37644 item.setContent(content);
37650 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37651 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37652 * @return {Roo.TabPanelItem}
37654 getTab : function(id){
37655 return this.items[id];
37659 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37660 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37662 hideTab : function(id){
37663 var t = this.items[id];
37666 this.hiddenCount++;
37667 this.autoSizeTabs();
37672 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37673 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37675 unhideTab : function(id){
37676 var t = this.items[id];
37678 t.setHidden(false);
37679 this.hiddenCount--;
37680 this.autoSizeTabs();
37685 * Adds an existing {@link Roo.TabPanelItem}.
37686 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37688 addTabItem : function(item){
37689 this.items[item.id] = item;
37690 this.items.push(item);
37691 // if(this.resizeTabs){
37692 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37693 // this.autoSizeTabs();
37695 // item.autoSize();
37700 * Removes a {@link Roo.TabPanelItem}.
37701 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37703 removeTab : function(id){
37704 var items = this.items;
37705 var tab = items[id];
37706 if(!tab) { return; }
37707 var index = items.indexOf(tab);
37708 if(this.active == tab && items.length > 1){
37709 var newTab = this.getNextAvailable(index);
37714 this.stripEl.dom.removeChild(tab.pnode.dom);
37715 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37716 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37718 items.splice(index, 1);
37719 delete this.items[tab.id];
37720 tab.fireEvent("close", tab);
37721 tab.purgeListeners();
37722 this.autoSizeTabs();
37725 getNextAvailable : function(start){
37726 var items = this.items;
37728 // look for a next tab that will slide over to
37729 // replace the one being removed
37730 while(index < items.length){
37731 var item = items[++index];
37732 if(item && !item.isHidden()){
37736 // if one isn't found select the previous tab (on the left)
37739 var item = items[--index];
37740 if(item && !item.isHidden()){
37748 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37749 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37751 disableTab : function(id){
37752 var tab = this.items[id];
37753 if(tab && this.active != tab){
37759 * Enables a {@link Roo.TabPanelItem} that is disabled.
37760 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37762 enableTab : function(id){
37763 var tab = this.items[id];
37768 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37769 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37770 * @return {Roo.TabPanelItem} The TabPanelItem.
37772 activate : function(id){
37773 var tab = this.items[id];
37777 if(tab == this.active || tab.disabled){
37781 this.fireEvent("beforetabchange", this, e, tab);
37782 if(e.cancel !== true && !tab.disabled){
37784 this.active.hide();
37786 this.active = this.items[id];
37787 this.active.show();
37788 this.fireEvent("tabchange", this, this.active);
37794 * Gets the active {@link Roo.TabPanelItem}.
37795 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37797 getActiveTab : function(){
37798 return this.active;
37802 * Updates the tab body element to fit the height of the container element
37803 * for overflow scrolling
37804 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37806 syncHeight : function(targetHeight){
37807 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37808 var bm = this.bodyEl.getMargins();
37809 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37810 this.bodyEl.setHeight(newHeight);
37814 onResize : function(){
37815 if(this.monitorResize){
37816 this.autoSizeTabs();
37821 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37823 beginUpdate : function(){
37824 this.updating = true;
37828 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37830 endUpdate : function(){
37831 this.updating = false;
37832 this.autoSizeTabs();
37836 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37838 autoSizeTabs : function(){
37839 var count = this.items.length;
37840 var vcount = count - this.hiddenCount;
37841 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37844 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37845 var availWidth = Math.floor(w / vcount);
37846 var b = this.stripBody;
37847 if(b.getWidth() > w){
37848 var tabs = this.items;
37849 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37850 if(availWidth < this.minTabWidth){
37851 /*if(!this.sleft){ // incomplete scrolling code
37852 this.createScrollButtons();
37855 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37858 if(this.currentTabWidth < this.preferredTabWidth){
37859 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37865 * Returns the number of tabs in this TabPanel.
37868 getCount : function(){
37869 return this.items.length;
37873 * Resizes all the tabs to the passed width
37874 * @param {Number} The new width
37876 setTabWidth : function(width){
37877 this.currentTabWidth = width;
37878 for(var i = 0, len = this.items.length; i < len; i++) {
37879 if(!this.items[i].isHidden()) {
37880 this.items[i].setWidth(width);
37886 * Destroys this TabPanel
37887 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37889 destroy : function(removeEl){
37890 Roo.EventManager.removeResizeListener(this.onResize, this);
37891 for(var i = 0, len = this.items.length; i < len; i++){
37892 this.items[i].purgeListeners();
37894 if(removeEl === true){
37895 this.el.update("");
37900 createStrip : function(container)
37902 var strip = document.createElement("nav");
37903 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37904 container.appendChild(strip);
37908 createStripList : function(strip)
37910 // div wrapper for retard IE
37911 // returns the "tr" element.
37912 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37913 //'<div class="x-tabs-strip-wrap">'+
37914 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37915 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37916 return strip.firstChild; //.firstChild.firstChild.firstChild;
37918 createBody : function(container)
37920 var body = document.createElement("div");
37921 Roo.id(body, "tab-body");
37922 //Roo.fly(body).addClass("x-tabs-body");
37923 Roo.fly(body).addClass("tab-content");
37924 container.appendChild(body);
37927 createItemBody :function(bodyEl, id){
37928 var body = Roo.getDom(id);
37930 body = document.createElement("div");
37933 //Roo.fly(body).addClass("x-tabs-item-body");
37934 Roo.fly(body).addClass("tab-pane");
37935 bodyEl.insertBefore(body, bodyEl.firstChild);
37939 createStripElements : function(stripEl, text, closable, tpl)
37941 var td = document.createElement("li"); // was td..
37944 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37947 stripEl.appendChild(td);
37949 td.className = "x-tabs-closable";
37950 if(!this.closeTpl){
37951 this.closeTpl = new Roo.Template(
37952 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37953 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37954 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37957 var el = this.closeTpl.overwrite(td, {"text": text});
37958 var close = el.getElementsByTagName("div")[0];
37959 var inner = el.getElementsByTagName("em")[0];
37960 return {"el": el, "close": close, "inner": inner};
37963 // not sure what this is..
37964 // if(!this.tabTpl){
37965 //this.tabTpl = new Roo.Template(
37966 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37967 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37969 // this.tabTpl = new Roo.Template(
37970 // '<a href="#">' +
37971 // '<span unselectable="on"' +
37972 // (this.disableTooltips ? '' : ' title="{text}"') +
37973 // ' >{text}</span></a>'
37979 var template = tpl || this.tabTpl || false;
37983 template = new Roo.Template(
37985 '<span unselectable="on"' +
37986 (this.disableTooltips ? '' : ' title="{text}"') +
37987 ' >{text}</span></a>'
37991 switch (typeof(template)) {
37995 template = new Roo.Template(template);
38001 var el = template.overwrite(td, {"text": text});
38003 var inner = el.getElementsByTagName("span")[0];
38005 return {"el": el, "inner": inner};
38013 * @class Roo.TabPanelItem
38014 * @extends Roo.util.Observable
38015 * Represents an individual item (tab plus body) in a TabPanel.
38016 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38017 * @param {String} id The id of this TabPanelItem
38018 * @param {String} text The text for the tab of this TabPanelItem
38019 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38021 Roo.bootstrap.panel.TabItem = function(config){
38023 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38024 * @type Roo.TabPanel
38026 this.tabPanel = config.panel;
38028 * The id for this TabPanelItem
38031 this.id = config.id;
38033 this.disabled = false;
38035 this.text = config.text;
38037 this.loaded = false;
38038 this.closable = config.closable;
38041 * The body element for this TabPanelItem.
38042 * @type Roo.Element
38044 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38045 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38046 this.bodyEl.setStyle("display", "block");
38047 this.bodyEl.setStyle("zoom", "1");
38048 //this.hideAction();
38050 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38052 this.el = Roo.get(els.el);
38053 this.inner = Roo.get(els.inner, true);
38054 this.textEl = Roo.get(this.el.dom.firstChild, true);
38055 this.pnode = Roo.get(els.el.parentNode, true);
38056 // this.el.on("mousedown", this.onTabMouseDown, this);
38057 this.el.on("click", this.onTabClick, this);
38059 if(config.closable){
38060 var c = Roo.get(els.close, true);
38061 c.dom.title = this.closeText;
38062 c.addClassOnOver("close-over");
38063 c.on("click", this.closeClick, this);
38069 * Fires when this tab becomes the active tab.
38070 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38071 * @param {Roo.TabPanelItem} this
38075 * @event beforeclose
38076 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38077 * @param {Roo.TabPanelItem} this
38078 * @param {Object} e Set cancel to true on this object to cancel the close.
38080 "beforeclose": true,
38083 * Fires when this tab is closed.
38084 * @param {Roo.TabPanelItem} this
38088 * @event deactivate
38089 * Fires when this tab is no longer the active tab.
38090 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38091 * @param {Roo.TabPanelItem} this
38093 "deactivate" : true
38095 this.hidden = false;
38097 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38100 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38102 purgeListeners : function(){
38103 Roo.util.Observable.prototype.purgeListeners.call(this);
38104 this.el.removeAllListeners();
38107 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38110 this.pnode.addClass("active");
38113 this.tabPanel.stripWrap.repaint();
38115 this.fireEvent("activate", this.tabPanel, this);
38119 * Returns true if this tab is the active tab.
38120 * @return {Boolean}
38122 isActive : function(){
38123 return this.tabPanel.getActiveTab() == this;
38127 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38130 this.pnode.removeClass("active");
38132 this.fireEvent("deactivate", this.tabPanel, this);
38135 hideAction : function(){
38136 this.bodyEl.hide();
38137 this.bodyEl.setStyle("position", "absolute");
38138 this.bodyEl.setLeft("-20000px");
38139 this.bodyEl.setTop("-20000px");
38142 showAction : function(){
38143 this.bodyEl.setStyle("position", "relative");
38144 this.bodyEl.setTop("");
38145 this.bodyEl.setLeft("");
38146 this.bodyEl.show();
38150 * Set the tooltip for the tab.
38151 * @param {String} tooltip The tab's tooltip
38153 setTooltip : function(text){
38154 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38155 this.textEl.dom.qtip = text;
38156 this.textEl.dom.removeAttribute('title');
38158 this.textEl.dom.title = text;
38162 onTabClick : function(e){
38163 e.preventDefault();
38164 this.tabPanel.activate(this.id);
38167 onTabMouseDown : function(e){
38168 e.preventDefault();
38169 this.tabPanel.activate(this.id);
38172 getWidth : function(){
38173 return this.inner.getWidth();
38176 setWidth : function(width){
38177 var iwidth = width - this.pnode.getPadding("lr");
38178 this.inner.setWidth(iwidth);
38179 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38180 this.pnode.setWidth(width);
38184 * Show or hide the tab
38185 * @param {Boolean} hidden True to hide or false to show.
38187 setHidden : function(hidden){
38188 this.hidden = hidden;
38189 this.pnode.setStyle("display", hidden ? "none" : "");
38193 * Returns true if this tab is "hidden"
38194 * @return {Boolean}
38196 isHidden : function(){
38197 return this.hidden;
38201 * Returns the text for this tab
38204 getText : function(){
38208 autoSize : function(){
38209 //this.el.beginMeasure();
38210 this.textEl.setWidth(1);
38212 * #2804 [new] Tabs in Roojs
38213 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38215 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38216 //this.el.endMeasure();
38220 * Sets the text for the tab (Note: this also sets the tooltip text)
38221 * @param {String} text The tab's text and tooltip
38223 setText : function(text){
38225 this.textEl.update(text);
38226 this.setTooltip(text);
38227 //if(!this.tabPanel.resizeTabs){
38228 // this.autoSize();
38232 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38234 activate : function(){
38235 this.tabPanel.activate(this.id);
38239 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38241 disable : function(){
38242 if(this.tabPanel.active != this){
38243 this.disabled = true;
38244 this.pnode.addClass("disabled");
38249 * Enables this TabPanelItem if it was previously disabled.
38251 enable : function(){
38252 this.disabled = false;
38253 this.pnode.removeClass("disabled");
38257 * Sets the content for this TabPanelItem.
38258 * @param {String} content The content
38259 * @param {Boolean} loadScripts true to look for and load scripts
38261 setContent : function(content, loadScripts){
38262 this.bodyEl.update(content, loadScripts);
38266 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38267 * @return {Roo.UpdateManager} The UpdateManager
38269 getUpdateManager : function(){
38270 return this.bodyEl.getUpdateManager();
38274 * Set a URL to be used to load the content for this TabPanelItem.
38275 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38276 * @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)
38277 * @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)
38278 * @return {Roo.UpdateManager} The UpdateManager
38280 setUrl : function(url, params, loadOnce){
38281 if(this.refreshDelegate){
38282 this.un('activate', this.refreshDelegate);
38284 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38285 this.on("activate", this.refreshDelegate);
38286 return this.bodyEl.getUpdateManager();
38290 _handleRefresh : function(url, params, loadOnce){
38291 if(!loadOnce || !this.loaded){
38292 var updater = this.bodyEl.getUpdateManager();
38293 updater.update(url, params, this._setLoaded.createDelegate(this));
38298 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38299 * Will fail silently if the setUrl method has not been called.
38300 * This does not activate the panel, just updates its content.
38302 refresh : function(){
38303 if(this.refreshDelegate){
38304 this.loaded = false;
38305 this.refreshDelegate();
38310 _setLoaded : function(){
38311 this.loaded = true;
38315 closeClick : function(e){
38318 this.fireEvent("beforeclose", this, o);
38319 if(o.cancel !== true){
38320 this.tabPanel.removeTab(this.id);
38324 * The text displayed in the tooltip for the close icon.
38327 closeText : "Close this tab"
38330 * This script refer to:
38331 * Title: International Telephone Input
38332 * Author: Jack O'Connor
38333 * Code version: v12.1.12
38334 * Availability: https://github.com/jackocnr/intl-tel-input.git
38337 Roo.bootstrap.PhoneInputData = function() {
38340 "Afghanistan (افغانستان)",
38345 "Albania (Shqipëri)",
38350 "Algeria (الجزائر)",
38375 "Antigua and Barbuda",
38385 "Armenia (Հայաստան)",
38401 "Austria (Österreich)",
38406 "Azerbaijan (Azərbaycan)",
38416 "Bahrain (البحرين)",
38421 "Bangladesh (বাংলাদেশ)",
38431 "Belarus (Беларусь)",
38436 "Belgium (België)",
38466 "Bosnia and Herzegovina (Босна и Херцеговина)",
38481 "British Indian Ocean Territory",
38486 "British Virgin Islands",
38496 "Bulgaria (България)",
38506 "Burundi (Uburundi)",
38511 "Cambodia (កម្ពុជា)",
38516 "Cameroon (Cameroun)",
38525 ["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"]
38528 "Cape Verde (Kabu Verdi)",
38533 "Caribbean Netherlands",
38544 "Central African Republic (République centrafricaine)",
38564 "Christmas Island",
38570 "Cocos (Keeling) Islands",
38581 "Comoros (جزر القمر)",
38586 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38591 "Congo (Republic) (Congo-Brazzaville)",
38611 "Croatia (Hrvatska)",
38632 "Czech Republic (Česká republika)",
38637 "Denmark (Danmark)",
38652 "Dominican Republic (República Dominicana)",
38656 ["809", "829", "849"]
38674 "Equatorial Guinea (Guinea Ecuatorial)",
38694 "Falkland Islands (Islas Malvinas)",
38699 "Faroe Islands (Føroyar)",
38720 "French Guiana (Guyane française)",
38725 "French Polynesia (Polynésie française)",
38740 "Georgia (საქართველო)",
38745 "Germany (Deutschland)",
38765 "Greenland (Kalaallit Nunaat)",
38802 "Guinea-Bissau (Guiné Bissau)",
38827 "Hungary (Magyarország)",
38832 "Iceland (Ísland)",
38852 "Iraq (العراق)",
38868 "Israel (ישראל)",
38895 "Jordan (الأردن)",
38900 "Kazakhstan (Казахстан)",
38921 "Kuwait (الكويت)",
38926 "Kyrgyzstan (Кыргызстан)",
38936 "Latvia (Latvija)",
38941 "Lebanon (لبنان)",
38956 "Libya (ليبيا)",
38966 "Lithuania (Lietuva)",
38981 "Macedonia (FYROM) (Македонија)",
38986 "Madagascar (Madagasikara)",
39016 "Marshall Islands",
39026 "Mauritania (موريتانيا)",
39031 "Mauritius (Moris)",
39052 "Moldova (Republica Moldova)",
39062 "Mongolia (Монгол)",
39067 "Montenegro (Crna Gora)",
39077 "Morocco (المغرب)",
39083 "Mozambique (Moçambique)",
39088 "Myanmar (Burma) (မြန်မာ)",
39093 "Namibia (Namibië)",
39108 "Netherlands (Nederland)",
39113 "New Caledonia (Nouvelle-Calédonie)",
39148 "North Korea (조선 민주주의 인민 공화국)",
39153 "Northern Mariana Islands",
39169 "Pakistan (پاکستان)",
39179 "Palestine (فلسطين)",
39189 "Papua New Guinea",
39231 "Réunion (La Réunion)",
39237 "Romania (România)",
39253 "Saint Barthélemy",
39264 "Saint Kitts and Nevis",
39274 "Saint Martin (Saint-Martin (partie française))",
39280 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39285 "Saint Vincent and the Grenadines",
39300 "São Tomé and Príncipe (São Tomé e Príncipe)",
39305 "Saudi Arabia (المملكة العربية السعودية)",
39310 "Senegal (Sénégal)",
39340 "Slovakia (Slovensko)",
39345 "Slovenia (Slovenija)",
39355 "Somalia (Soomaaliya)",
39365 "South Korea (대한민국)",
39370 "South Sudan (جنوب السودان)",
39380 "Sri Lanka (ශ්රී ලංකාව)",
39385 "Sudan (السودان)",
39395 "Svalbard and Jan Mayen",
39406 "Sweden (Sverige)",
39411 "Switzerland (Schweiz)",
39416 "Syria (سوريا)",
39461 "Trinidad and Tobago",
39466 "Tunisia (تونس)",
39471 "Turkey (Türkiye)",
39481 "Turks and Caicos Islands",
39491 "U.S. Virgin Islands",
39501 "Ukraine (Україна)",
39506 "United Arab Emirates (الإمارات العربية المتحدة)",
39528 "Uzbekistan (Oʻzbekiston)",
39538 "Vatican City (Città del Vaticano)",
39549 "Vietnam (Việt Nam)",
39554 "Wallis and Futuna (Wallis-et-Futuna)",
39559 "Western Sahara (الصحراء الغربية)",
39565 "Yemen (اليمن)",
39589 * This script refer to:
39590 * Title: International Telephone Input
39591 * Author: Jack O'Connor
39592 * Code version: v12.1.12
39593 * Availability: https://github.com/jackocnr/intl-tel-input.git
39597 * @class Roo.bootstrap.PhoneInput
39598 * @extends Roo.bootstrap.TriggerField
39599 * An input with International dial-code selection
39601 * @cfg {String} defaultDialCode default '+852'
39602 * @cfg {Array} preferedCountries default []
39605 * Create a new PhoneInput.
39606 * @param {Object} config Configuration options
39609 Roo.bootstrap.PhoneInput = function(config) {
39610 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39613 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39615 listWidth: undefined,
39617 selectedClass: 'active',
39619 invalidClass : "has-warning",
39621 validClass: 'has-success',
39623 allowed: '0123456789',
39626 * @cfg {String} defaultDialCode The default dial code when initializing the input
39628 defaultDialCode: '+852',
39631 * @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
39633 preferedCountries: false,
39635 getAutoCreate : function()
39637 var data = Roo.bootstrap.PhoneInputData();
39638 var align = this.labelAlign || this.parentLabelAlign();
39641 this.allCountries = [];
39642 this.dialCodeMapping = [];
39644 for (var i = 0; i < data.length; i++) {
39646 this.allCountries[i] = {
39650 priority: c[3] || 0,
39651 areaCodes: c[4] || null
39653 this.dialCodeMapping[c[2]] = {
39656 priority: c[3] || 0,
39657 areaCodes: c[4] || null
39669 cls : 'form-control tel-input',
39670 autocomplete: 'new-password'
39673 var hiddenInput = {
39676 cls: 'hidden-tel-input'
39680 hiddenInput.name = this.name;
39683 if (this.disabled) {
39684 input.disabled = true;
39687 var flag_container = {
39704 cls: this.hasFeedback ? 'has-feedback' : '',
39710 cls: 'dial-code-holder',
39717 cls: 'roo-select2-container input-group',
39724 if (this.fieldLabel.length) {
39727 tooltip: 'This field is required'
39733 cls: 'control-label',
39739 html: this.fieldLabel
39742 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39748 if(this.indicatorpos == 'right') {
39749 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39756 if(align == 'left') {
39764 if(this.labelWidth > 12){
39765 label.style = "width: " + this.labelWidth + 'px';
39767 if(this.labelWidth < 13 && this.labelmd == 0){
39768 this.labelmd = this.labelWidth;
39770 if(this.labellg > 0){
39771 label.cls += ' col-lg-' + this.labellg;
39772 input.cls += ' col-lg-' + (12 - this.labellg);
39774 if(this.labelmd > 0){
39775 label.cls += ' col-md-' + this.labelmd;
39776 container.cls += ' col-md-' + (12 - this.labelmd);
39778 if(this.labelsm > 0){
39779 label.cls += ' col-sm-' + this.labelsm;
39780 container.cls += ' col-sm-' + (12 - this.labelsm);
39782 if(this.labelxs > 0){
39783 label.cls += ' col-xs-' + this.labelxs;
39784 container.cls += ' col-xs-' + (12 - this.labelxs);
39794 var settings = this;
39796 ['xs','sm','md','lg'].map(function(size){
39797 if (settings[size]) {
39798 cfg.cls += ' col-' + size + '-' + settings[size];
39802 this.store = new Roo.data.Store({
39803 proxy : new Roo.data.MemoryProxy({}),
39804 reader : new Roo.data.JsonReader({
39815 'name' : 'dialCode',
39819 'name' : 'priority',
39823 'name' : 'areaCodes',
39830 if(!this.preferedCountries) {
39831 this.preferedCountries = [
39838 var p = this.preferedCountries.reverse();
39841 for (var i = 0; i < p.length; i++) {
39842 for (var j = 0; j < this.allCountries.length; j++) {
39843 if(this.allCountries[j].iso2 == p[i]) {
39844 var t = this.allCountries[j];
39845 this.allCountries.splice(j,1);
39846 this.allCountries.unshift(t);
39852 this.store.proxy.data = {
39854 data: this.allCountries
39860 initEvents : function()
39863 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39865 this.indicator = this.indicatorEl();
39866 this.flag = this.flagEl();
39867 this.dialCodeHolder = this.dialCodeHolderEl();
39869 this.trigger = this.el.select('div.flag-box',true).first();
39870 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39875 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39876 _this.list.setWidth(lw);
39879 this.list.on('mouseover', this.onViewOver, this);
39880 this.list.on('mousemove', this.onViewMove, this);
39881 this.inputEl().on("keyup", this.onKeyUp, this);
39883 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39885 this.view = new Roo.View(this.list, this.tpl, {
39886 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39889 this.view.on('click', this.onViewClick, this);
39890 this.setValue(this.defaultDialCode);
39893 onTriggerClick : function(e)
39895 Roo.log('trigger click');
39900 if(this.isExpanded()){
39902 this.hasFocus = false;
39904 this.store.load({});
39905 this.hasFocus = true;
39910 isExpanded : function()
39912 return this.list.isVisible();
39915 collapse : function()
39917 if(!this.isExpanded()){
39921 Roo.get(document).un('mousedown', this.collapseIf, this);
39922 Roo.get(document).un('mousewheel', this.collapseIf, this);
39923 this.fireEvent('collapse', this);
39927 expand : function()
39931 if(this.isExpanded() || !this.hasFocus){
39935 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39936 this.list.setWidth(lw);
39939 this.restrictHeight();
39941 Roo.get(document).on('mousedown', this.collapseIf, this);
39942 Roo.get(document).on('mousewheel', this.collapseIf, this);
39944 this.fireEvent('expand', this);
39947 restrictHeight : function()
39949 this.list.alignTo(this.inputEl(), this.listAlign);
39950 this.list.alignTo(this.inputEl(), this.listAlign);
39953 onViewOver : function(e, t)
39955 if(this.inKeyMode){
39958 var item = this.view.findItemFromChild(t);
39961 var index = this.view.indexOf(item);
39962 this.select(index, false);
39967 onViewClick : function(view, doFocus, el, e)
39969 var index = this.view.getSelectedIndexes()[0];
39971 var r = this.store.getAt(index);
39974 this.onSelect(r, index);
39976 if(doFocus !== false && !this.blockFocus){
39977 this.inputEl().focus();
39981 onViewMove : function(e, t)
39983 this.inKeyMode = false;
39986 select : function(index, scrollIntoView)
39988 this.selectedIndex = index;
39989 this.view.select(index);
39990 if(scrollIntoView !== false){
39991 var el = this.view.getNode(index);
39993 this.list.scrollChildIntoView(el, false);
39998 createList : function()
40000 this.list = Roo.get(document.body).createChild({
40002 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40003 style: 'display:none'
40005 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40008 collapseIf : function(e)
40010 var in_combo = e.within(this.el);
40011 var in_list = e.within(this.list);
40012 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40014 if (in_combo || in_list || is_list) {
40020 onSelect : function(record, index)
40022 if(this.fireEvent('beforeselect', this, record, index) !== false){
40024 this.setFlagClass(record.data.iso2);
40025 this.setDialCode(record.data.dialCode);
40026 this.hasFocus = false;
40028 this.fireEvent('select', this, record, index);
40032 flagEl : function()
40034 var flag = this.el.select('div.flag',true).first();
40041 dialCodeHolderEl : function()
40043 var d = this.el.select('input.dial-code-holder',true).first();
40050 setDialCode : function(v)
40052 this.dialCodeHolder.dom.value = '+'+v;
40055 setFlagClass : function(n)
40057 this.flag.dom.className = 'flag '+n;
40060 getValue : function()
40062 var v = this.inputEl().getValue();
40063 if(this.dialCodeHolder) {
40064 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40069 setValue : function(v)
40071 var d = this.getDialCode(v);
40073 //invalid dial code
40074 if(v.length == 0 || !d || d.length == 0) {
40076 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40077 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40083 this.setFlagClass(this.dialCodeMapping[d].iso2);
40084 this.setDialCode(d);
40085 this.inputEl().dom.value = v.replace('+'+d,'');
40086 this.hiddenEl().dom.value = this.getValue();
40091 getDialCode : function(v = '')
40093 if (v.length == 0) {
40094 return this.dialCodeHolder.dom.value;
40098 if (v.charAt(0) != "+") {
40101 var numericChars = "";
40102 for (var i = 1; i < v.length; i++) {
40103 var c = v.charAt(i);
40106 if (this.dialCodeMapping[numericChars]) {
40107 dialCode = v.substr(1, i);
40109 if (numericChars.length == 4) {
40119 this.setValue(this.defaultDialCode);
40123 hiddenEl : function()
40125 return this.el.select('input.hidden-tel-input',true).first();
40128 onKeyUp : function(e){
40130 var k = e.getKey();
40131 var c = e.getCharCode();
40134 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40135 this.allowed.indexOf(String.fromCharCode(c)) === -1
40140 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40143 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40147 this.setValue(this.getValue());
40152 * @class Roo.bootstrap.MoneyField
40153 * @extends Roo.bootstrap.ComboBox
40154 * Bootstrap MoneyField class
40157 * Create a new MoneyField.
40158 * @param {Object} config Configuration options
40161 Roo.bootstrap.MoneyField = function(config) {
40163 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40167 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40170 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40172 allowDecimals : true,
40174 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40176 decimalSeparator : ".",
40178 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40180 decimalPrecision : 0,
40182 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40184 allowNegative : true,
40186 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40188 minValue : Number.NEGATIVE_INFINITY,
40190 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40192 maxValue : Number.MAX_VALUE,
40194 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40196 minText : "The minimum value for this field is {0}",
40198 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40200 maxText : "The maximum value for this field is {0}",
40202 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40203 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40205 nanText : "{0} is not a valid number",
40207 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40211 * @cfg {String} defaults currency of the MoneyField
40212 * value should be in lkey
40214 defaultCurrency : false,
40216 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40218 thousandsDelimiter : false,
40228 getAutoCreate : function()
40230 var align = this.labelAlign || this.parentLabelAlign();
40242 cls : 'form-control roo-money-amount-input',
40243 autocomplete: 'new-password'
40246 var hiddenInput = {
40250 cls: 'hidden-number-input'
40254 hiddenInput.name = this.name;
40257 if (this.disabled) {
40258 input.disabled = true;
40261 var clg = 12 - this.inputlg;
40262 var cmd = 12 - this.inputmd;
40263 var csm = 12 - this.inputsm;
40264 var cxs = 12 - this.inputxs;
40268 cls : 'row roo-money-field',
40272 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40276 cls: 'roo-select2-container input-group',
40280 cls : 'form-control roo-money-currency-input',
40281 autocomplete: 'new-password',
40283 name : this.currencyName
40287 cls : 'input-group-addon',
40301 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40305 cls: this.hasFeedback ? 'has-feedback' : '',
40316 if (this.fieldLabel.length) {
40319 tooltip: 'This field is required'
40325 cls: 'control-label',
40331 html: this.fieldLabel
40334 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40340 if(this.indicatorpos == 'right') {
40341 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40348 if(align == 'left') {
40356 if(this.labelWidth > 12){
40357 label.style = "width: " + this.labelWidth + 'px';
40359 if(this.labelWidth < 13 && this.labelmd == 0){
40360 this.labelmd = this.labelWidth;
40362 if(this.labellg > 0){
40363 label.cls += ' col-lg-' + this.labellg;
40364 input.cls += ' col-lg-' + (12 - this.labellg);
40366 if(this.labelmd > 0){
40367 label.cls += ' col-md-' + this.labelmd;
40368 container.cls += ' col-md-' + (12 - this.labelmd);
40370 if(this.labelsm > 0){
40371 label.cls += ' col-sm-' + this.labelsm;
40372 container.cls += ' col-sm-' + (12 - this.labelsm);
40374 if(this.labelxs > 0){
40375 label.cls += ' col-xs-' + this.labelxs;
40376 container.cls += ' col-xs-' + (12 - this.labelxs);
40387 var settings = this;
40389 ['xs','sm','md','lg'].map(function(size){
40390 if (settings[size]) {
40391 cfg.cls += ' col-' + size + '-' + settings[size];
40398 initEvents : function()
40400 this.indicator = this.indicatorEl();
40402 this.initCurrencyEvent();
40404 this.initNumberEvent();
40407 initCurrencyEvent : function()
40410 throw "can not find store for combo";
40413 this.store = Roo.factory(this.store, Roo.data);
40414 this.store.parent = this;
40418 this.triggerEl = this.el.select('.input-group-addon', true).first();
40420 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40425 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40426 _this.list.setWidth(lw);
40429 this.list.on('mouseover', this.onViewOver, this);
40430 this.list.on('mousemove', this.onViewMove, this);
40431 this.list.on('scroll', this.onViewScroll, this);
40434 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40437 this.view = new Roo.View(this.list, this.tpl, {
40438 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40441 this.view.on('click', this.onViewClick, this);
40443 this.store.on('beforeload', this.onBeforeLoad, this);
40444 this.store.on('load', this.onLoad, this);
40445 this.store.on('loadexception', this.onLoadException, this);
40447 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40448 "up" : function(e){
40449 this.inKeyMode = true;
40453 "down" : function(e){
40454 if(!this.isExpanded()){
40455 this.onTriggerClick();
40457 this.inKeyMode = true;
40462 "enter" : function(e){
40465 if(this.fireEvent("specialkey", this, e)){
40466 this.onViewClick(false);
40472 "esc" : function(e){
40476 "tab" : function(e){
40479 if(this.fireEvent("specialkey", this, e)){
40480 this.onViewClick(false);
40488 doRelay : function(foo, bar, hname){
40489 if(hname == 'down' || this.scope.isExpanded()){
40490 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40498 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40502 initNumberEvent : function(e)
40504 this.inputEl().on("keydown" , this.fireKey, this);
40505 this.inputEl().on("focus", this.onFocus, this);
40506 this.inputEl().on("blur", this.onBlur, this);
40508 this.inputEl().relayEvent('keyup', this);
40510 if(this.indicator){
40511 this.indicator.addClass('invisible');
40514 this.originalValue = this.getValue();
40516 if(this.validationEvent == 'keyup'){
40517 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40518 this.inputEl().on('keyup', this.filterValidation, this);
40520 else if(this.validationEvent !== false){
40521 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40524 if(this.selectOnFocus){
40525 this.on("focus", this.preFocus, this);
40528 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40529 this.inputEl().on("keypress", this.filterKeys, this);
40531 this.inputEl().relayEvent('keypress', this);
40534 var allowed = "0123456789";
40536 if(this.allowDecimals){
40537 allowed += this.decimalSeparator;
40540 if(this.allowNegative){
40544 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40546 var keyPress = function(e){
40548 var k = e.getKey();
40550 var c = e.getCharCode();
40553 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40554 allowed.indexOf(String.fromCharCode(c)) === -1
40560 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40564 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40569 this.inputEl().on("keypress", keyPress, this);
40573 onTriggerClick : function(e)
40580 this.loadNext = false;
40582 if(this.isExpanded()){
40587 this.hasFocus = true;
40589 if(this.triggerAction == 'all') {
40590 this.doQuery(this.allQuery, true);
40594 this.doQuery(this.getRawValue());
40597 getCurrency : function()
40599 var v = this.currencyEl().getValue();
40604 restrictHeight : function()
40606 this.list.alignTo(this.currencyEl(), this.listAlign);
40607 this.list.alignTo(this.currencyEl(), this.listAlign);
40610 onViewClick : function(view, doFocus, el, e)
40612 var index = this.view.getSelectedIndexes()[0];
40614 var r = this.store.getAt(index);
40617 this.onSelect(r, index);
40621 onSelect : function(record, index){
40623 if(this.fireEvent('beforeselect', this, record, index) !== false){
40625 this.setFromCurrencyData(index > -1 ? record.data : false);
40629 this.fireEvent('select', this, record, index);
40633 setFromCurrencyData : function(o)
40637 this.lastCurrency = o;
40639 if (this.currencyField) {
40640 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40642 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40645 this.lastSelectionText = currency;
40647 //setting default currency
40648 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40649 this.setCurrency(this.defaultCurrency);
40653 this.setCurrency(currency);
40656 setFromData : function(o)
40660 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40662 this.setFromCurrencyData(c);
40667 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40669 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40672 this.setValue(value);
40676 setCurrency : function(v)
40678 this.currencyValue = v;
40681 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40686 setValue : function(v)
40688 v = this.fixPrecision(v);
40690 v = String(v).replace(".", this.decimalSeparator);
40696 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40698 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40699 this.thousandsDelimiter || ','
40702 if(this.allowBlank && !v) {
40703 this.inputEl().dom.value = '';
40710 getRawValue : function()
40712 var v = this.inputEl().getValue();
40717 getValue : function()
40719 return this.fixPrecision(this.parseValue(this.getRawValue()));
40722 parseValue : function(value)
40724 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40725 return isNaN(value) ? '' : value;
40728 fixPrecision : function(value)
40730 var nan = isNaN(value);
40732 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40733 return nan ? '' : value;
40736 return parseFloat(value).toFixed(this.decimalPrecision);
40739 decimalPrecisionFcn : function(v)
40741 return Math.floor(v);
40744 validateValue : function(value)
40746 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40750 var num = this.parseValue(value);
40753 this.markInvalid(String.format(this.nanText, value));
40757 if(num < this.minValue){
40758 this.markInvalid(String.format(this.minText, this.minValue));
40762 if(num > this.maxValue){
40763 this.markInvalid(String.format(this.maxText, this.maxValue));
40770 validate : function()
40772 if(this.disabled || this.allowBlank){
40777 var currency = this.getCurrency();
40779 if(this.validateValue(this.getRawValue()) && currency.length){
40784 this.markInvalid();
40788 getName: function()
40793 beforeBlur : function()
40799 var v = this.parseValue(this.getRawValue());
40806 onBlur : function()
40810 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40811 //this.el.removeClass(this.focusClass);
40814 this.hasFocus = false;
40816 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40820 var v = this.getValue();
40822 if(String(v) !== String(this.startValue)){
40823 this.fireEvent('change', this, v, this.startValue);
40826 this.fireEvent("blur", this);
40829 inputEl : function()
40831 return this.el.select('.roo-money-amount-input', true).first();
40834 currencyEl : function()
40836 return this.el.select('.roo-money-currency-input', true).first();
40839 hiddenEl : function()
40841 return this.el.select('input.hidden-number-input',true).first();