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);
1412 allChildren : function()
1414 var r=new Roo.util.MixedCollection(false, function(o){
1415 return o.id || (o.id = Roo.id());
1417 var iter = function(el) {
1424 Roo.each(el.items,function(e) {
1433 checkEmpty : function()
1435 var items = this.allChildren();
1438 items.each(function(f){
1439 if(f.el.isVisible()) {
1458 * @class Roo.bootstrap.Img
1459 * @extends Roo.bootstrap.Component
1460 * Bootstrap Img class
1461 * @cfg {Boolean} imgResponsive false | true
1462 * @cfg {String} border rounded | circle | thumbnail
1463 * @cfg {String} src image source
1464 * @cfg {String} alt image alternative text
1465 * @cfg {String} href a tag href
1466 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1467 * @cfg {String} xsUrl xs image source
1468 * @cfg {String} smUrl sm image source
1469 * @cfg {String} mdUrl md image source
1470 * @cfg {String} lgUrl lg image source
1473 * Create a new Input
1474 * @param {Object} config The config object
1477 Roo.bootstrap.Img = function(config){
1478 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1484 * The img click event for the img.
1485 * @param {Roo.EventObject} e
1491 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1493 imgResponsive: true,
1503 getAutoCreate : function()
1505 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1506 return this.createSingleImg();
1511 cls: 'roo-image-responsive-group',
1516 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1518 if(!_this[size + 'Url']){
1524 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1525 html: _this.html || cfg.html,
1526 src: _this[size + 'Url']
1529 img.cls += ' roo-image-responsive-' + size;
1531 var s = ['xs', 'sm', 'md', 'lg'];
1533 s.splice(s.indexOf(size), 1);
1535 Roo.each(s, function(ss){
1536 img.cls += ' hidden-' + ss;
1539 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1540 cfg.cls += ' img-' + _this.border;
1544 cfg.alt = _this.alt;
1557 a.target = _this.target;
1561 cfg.cn.push((_this.href) ? a : img);
1568 createSingleImg : function()
1572 cls: (this.imgResponsive) ? 'img-responsive' : '',
1574 src : 'about:blank' // just incase src get's set to undefined?!?
1577 cfg.html = this.html || cfg.html;
1579 cfg.src = this.src || cfg.src;
1581 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1582 cfg.cls += ' img-' + this.border;
1599 a.target = this.target;
1604 return (this.href) ? a : cfg;
1607 initEvents: function()
1610 this.el.on('click', this.onClick, this);
1615 onClick : function(e)
1617 Roo.log('img onclick');
1618 this.fireEvent('click', this, e);
1621 * Sets the url of the image - used to update it
1622 * @param {String} url the url of the image
1625 setSrc : function(url)
1629 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1630 this.el.dom.src = url;
1634 this.el.select('img', true).first().dom.src = url;
1650 * @class Roo.bootstrap.Link
1651 * @extends Roo.bootstrap.Component
1652 * Bootstrap Link Class
1653 * @cfg {String} alt image alternative text
1654 * @cfg {String} href a tag href
1655 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1656 * @cfg {String} html the content of the link.
1657 * @cfg {String} anchor name for the anchor link
1658 * @cfg {String} fa - favicon
1660 * @cfg {Boolean} preventDefault (true | false) default false
1664 * Create a new Input
1665 * @param {Object} config The config object
1668 Roo.bootstrap.Link = function(config){
1669 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1675 * The img click event for the img.
1676 * @param {Roo.EventObject} e
1682 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1686 preventDefault: false,
1692 getAutoCreate : function()
1694 var html = this.html || '';
1696 if (this.fa !== false) {
1697 html = '<i class="fa fa-' + this.fa + '"></i>';
1702 // anchor's do not require html/href...
1703 if (this.anchor === false) {
1705 cfg.href = this.href || '#';
1707 cfg.name = this.anchor;
1708 if (this.html !== false || this.fa !== false) {
1711 if (this.href !== false) {
1712 cfg.href = this.href;
1716 if(this.alt !== false){
1721 if(this.target !== false) {
1722 cfg.target = this.target;
1728 initEvents: function() {
1730 if(!this.href || this.preventDefault){
1731 this.el.on('click', this.onClick, this);
1735 onClick : function(e)
1737 if(this.preventDefault){
1740 //Roo.log('img onclick');
1741 this.fireEvent('click', this, e);
1754 * @class Roo.bootstrap.Header
1755 * @extends Roo.bootstrap.Component
1756 * Bootstrap Header class
1757 * @cfg {String} html content of header
1758 * @cfg {Number} level (1|2|3|4|5|6) default 1
1761 * Create a new Header
1762 * @param {Object} config The config object
1766 Roo.bootstrap.Header = function(config){
1767 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1770 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1778 getAutoCreate : function(){
1783 tag: 'h' + (1 *this.level),
1784 html: this.html || ''
1796 * Ext JS Library 1.1.1
1797 * Copyright(c) 2006-2007, Ext JS, LLC.
1799 * Originally Released Under LGPL - original licence link has changed is not relivant.
1802 * <script type="text/javascript">
1806 * @class Roo.bootstrap.MenuMgr
1807 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1810 Roo.bootstrap.MenuMgr = function(){
1811 var menus, active, groups = {}, attached = false, lastShow = new Date();
1813 // private - called when first menu is created
1816 active = new Roo.util.MixedCollection();
1817 Roo.get(document).addKeyListener(27, function(){
1818 if(active.length > 0){
1826 if(active && active.length > 0){
1827 var c = active.clone();
1837 if(active.length < 1){
1838 Roo.get(document).un("mouseup", onMouseDown);
1846 var last = active.last();
1847 lastShow = new Date();
1850 Roo.get(document).on("mouseup", onMouseDown);
1855 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1856 m.parentMenu.activeChild = m;
1857 }else if(last && last.isVisible()){
1858 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1863 function onBeforeHide(m){
1865 m.activeChild.hide();
1867 if(m.autoHideTimer){
1868 clearTimeout(m.autoHideTimer);
1869 delete m.autoHideTimer;
1874 function onBeforeShow(m){
1875 var pm = m.parentMenu;
1876 if(!pm && !m.allowOtherMenus){
1878 }else if(pm && pm.activeChild && active != m){
1879 pm.activeChild.hide();
1883 // private this should really trigger on mouseup..
1884 function onMouseDown(e){
1885 Roo.log("on Mouse Up");
1887 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1888 Roo.log("MenuManager hideAll");
1897 function onBeforeCheck(mi, state){
1899 var g = groups[mi.group];
1900 for(var i = 0, l = g.length; i < l; i++){
1902 g[i].setChecked(false);
1911 * Hides all menus that are currently visible
1913 hideAll : function(){
1918 register : function(menu){
1922 menus[menu.id] = menu;
1923 menu.on("beforehide", onBeforeHide);
1924 menu.on("hide", onHide);
1925 menu.on("beforeshow", onBeforeShow);
1926 menu.on("show", onShow);
1928 if(g && menu.events["checkchange"]){
1932 groups[g].push(menu);
1933 menu.on("checkchange", onCheck);
1938 * Returns a {@link Roo.menu.Menu} object
1939 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1940 * be used to generate and return a new Menu instance.
1942 get : function(menu){
1943 if(typeof menu == "string"){ // menu id
1945 }else if(menu.events){ // menu instance
1948 /*else if(typeof menu.length == 'number'){ // array of menu items?
1949 return new Roo.bootstrap.Menu({items:menu});
1950 }else{ // otherwise, must be a config
1951 return new Roo.bootstrap.Menu(menu);
1958 unregister : function(menu){
1959 delete menus[menu.id];
1960 menu.un("beforehide", onBeforeHide);
1961 menu.un("hide", onHide);
1962 menu.un("beforeshow", onBeforeShow);
1963 menu.un("show", onShow);
1965 if(g && menu.events["checkchange"]){
1966 groups[g].remove(menu);
1967 menu.un("checkchange", onCheck);
1972 registerCheckable : function(menuItem){
1973 var g = menuItem.group;
1978 groups[g].push(menuItem);
1979 menuItem.on("beforecheckchange", onBeforeCheck);
1984 unregisterCheckable : function(menuItem){
1985 var g = menuItem.group;
1987 groups[g].remove(menuItem);
1988 menuItem.un("beforecheckchange", onBeforeCheck);
2000 * @class Roo.bootstrap.Menu
2001 * @extends Roo.bootstrap.Component
2002 * Bootstrap Menu class - container for MenuItems
2003 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2004 * @cfg {bool} hidden if the menu should be hidden when rendered.
2005 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2006 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2010 * @param {Object} config The config object
2014 Roo.bootstrap.Menu = function(config){
2015 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2016 if (this.registerMenu && this.type != 'treeview') {
2017 Roo.bootstrap.MenuMgr.register(this);
2022 * Fires before this menu is displayed
2023 * @param {Roo.menu.Menu} this
2028 * Fires before this menu is hidden
2029 * @param {Roo.menu.Menu} this
2034 * Fires after this menu is displayed
2035 * @param {Roo.menu.Menu} this
2040 * Fires after this menu is hidden
2041 * @param {Roo.menu.Menu} this
2046 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2047 * @param {Roo.menu.Menu} this
2048 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2049 * @param {Roo.EventObject} e
2054 * Fires when the mouse is hovering over this menu
2055 * @param {Roo.menu.Menu} this
2056 * @param {Roo.EventObject} e
2057 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2062 * Fires when the mouse exits this menu
2063 * @param {Roo.menu.Menu} this
2064 * @param {Roo.EventObject} e
2065 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2070 * Fires when a menu item contained in this menu is clicked
2071 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2072 * @param {Roo.EventObject} e
2076 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2079 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2083 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2086 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2088 registerMenu : true,
2090 menuItems :false, // stores the menu items..
2100 getChildContainer : function() {
2104 getAutoCreate : function(){
2106 //if (['right'].indexOf(this.align)!==-1) {
2107 // cfg.cn[1].cls += ' pull-right'
2113 cls : 'dropdown-menu' ,
2114 style : 'z-index:1000'
2118 if (this.type === 'submenu') {
2119 cfg.cls = 'submenu active';
2121 if (this.type === 'treeview') {
2122 cfg.cls = 'treeview-menu';
2127 initEvents : function() {
2129 // Roo.log("ADD event");
2130 // Roo.log(this.triggerEl.dom);
2132 this.triggerEl.on('click', this.onTriggerClick, this);
2134 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2136 this.triggerEl.addClass('dropdown-toggle');
2139 this.el.on('touchstart' , this.onTouch, this);
2141 this.el.on('click' , this.onClick, this);
2143 this.el.on("mouseover", this.onMouseOver, this);
2144 this.el.on("mouseout", this.onMouseOut, this);
2148 findTargetItem : function(e)
2150 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2154 //Roo.log(t); Roo.log(t.id);
2156 //Roo.log(this.menuitems);
2157 return this.menuitems.get(t.id);
2159 //return this.items.get(t.menuItemId);
2165 onTouch : function(e)
2167 Roo.log("menu.onTouch");
2168 //e.stopEvent(); this make the user popdown broken
2172 onClick : function(e)
2174 Roo.log("menu.onClick");
2176 var t = this.findTargetItem(e);
2177 if(!t || t.isContainer){
2182 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2183 if(t == this.activeItem && t.shouldDeactivate(e)){
2184 this.activeItem.deactivate();
2185 delete this.activeItem;
2189 this.setActiveItem(t, true);
2197 Roo.log('pass click event');
2201 this.fireEvent("click", this, t, e);
2205 if(!t.href.length || t.href == '#'){
2206 (function() { _this.hide(); }).defer(100);
2211 onMouseOver : function(e){
2212 var t = this.findTargetItem(e);
2215 // if(t.canActivate && !t.disabled){
2216 // this.setActiveItem(t, true);
2220 this.fireEvent("mouseover", this, e, t);
2222 isVisible : function(){
2223 return !this.hidden;
2225 onMouseOut : function(e){
2226 var t = this.findTargetItem(e);
2229 // if(t == this.activeItem && t.shouldDeactivate(e)){
2230 // this.activeItem.deactivate();
2231 // delete this.activeItem;
2234 this.fireEvent("mouseout", this, e, t);
2239 * Displays this menu relative to another element
2240 * @param {String/HTMLElement/Roo.Element} element The element to align to
2241 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2242 * the element (defaults to this.defaultAlign)
2243 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2245 show : function(el, pos, parentMenu){
2246 this.parentMenu = parentMenu;
2250 this.fireEvent("beforeshow", this);
2251 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2254 * Displays this menu at a specific xy position
2255 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2256 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2258 showAt : function(xy, parentMenu, /* private: */_e){
2259 this.parentMenu = parentMenu;
2264 this.fireEvent("beforeshow", this);
2265 //xy = this.el.adjustForConstraints(xy);
2269 this.hideMenuItems();
2270 this.hidden = false;
2271 this.triggerEl.addClass('open');
2273 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2274 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2277 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2282 this.fireEvent("show", this);
2288 this.doFocus.defer(50, this);
2292 doFocus : function(){
2294 this.focusEl.focus();
2299 * Hides this menu and optionally all parent menus
2300 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2302 hide : function(deep)
2305 this.hideMenuItems();
2306 if(this.el && this.isVisible()){
2307 this.fireEvent("beforehide", this);
2308 if(this.activeItem){
2309 this.activeItem.deactivate();
2310 this.activeItem = null;
2312 this.triggerEl.removeClass('open');;
2314 this.fireEvent("hide", this);
2316 if(deep === true && this.parentMenu){
2317 this.parentMenu.hide(true);
2321 onTriggerClick : function(e)
2323 Roo.log('trigger click');
2325 var target = e.getTarget();
2327 Roo.log(target.nodeName.toLowerCase());
2329 if(target.nodeName.toLowerCase() === 'i'){
2335 onTriggerPress : function(e)
2337 Roo.log('trigger press');
2338 //Roo.log(e.getTarget());
2339 // Roo.log(this.triggerEl.dom);
2341 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2342 var pel = Roo.get(e.getTarget());
2343 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2344 Roo.log('is treeview or dropdown?');
2348 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2352 if (this.isVisible()) {
2357 this.show(this.triggerEl, false, false);
2360 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2367 hideMenuItems : function()
2369 Roo.log("hide Menu Items");
2373 //$(backdrop).remove()
2374 this.el.select('.open',true).each(function(aa) {
2376 aa.removeClass('open');
2377 //var parent = getParent($(this))
2378 //var relatedTarget = { relatedTarget: this }
2380 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2381 //if (e.isDefaultPrevented()) return
2382 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2385 addxtypeChild : function (tree, cntr) {
2386 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2388 this.menuitems.add(comp);
2400 this.getEl().dom.innerHTML = '';
2401 this.menuitems.clear();
2415 * @class Roo.bootstrap.MenuItem
2416 * @extends Roo.bootstrap.Component
2417 * Bootstrap MenuItem class
2418 * @cfg {String} html the menu label
2419 * @cfg {String} href the link
2420 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2421 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2422 * @cfg {Boolean} active used on sidebars to highlight active itesm
2423 * @cfg {String} fa favicon to show on left of menu item.
2424 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2428 * Create a new MenuItem
2429 * @param {Object} config The config object
2433 Roo.bootstrap.MenuItem = function(config){
2434 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2439 * The raw click event for the entire grid.
2440 * @param {Roo.bootstrap.MenuItem} this
2441 * @param {Roo.EventObject} e
2447 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2451 preventDefault: false,
2452 isContainer : false,
2456 getAutoCreate : function(){
2458 if(this.isContainer){
2461 cls: 'dropdown-menu-item'
2475 if (this.fa !== false) {
2478 cls : 'fa fa-' + this.fa
2487 cls: 'dropdown-menu-item',
2490 if (this.parent().type == 'treeview') {
2491 cfg.cls = 'treeview-menu';
2494 cfg.cls += ' active';
2499 anc.href = this.href || cfg.cn[0].href ;
2500 ctag.html = this.html || cfg.cn[0].html ;
2504 initEvents: function()
2506 if (this.parent().type == 'treeview') {
2507 this.el.select('a').on('click', this.onClick, this);
2511 this.menu.parentType = this.xtype;
2512 this.menu.triggerEl = this.el;
2513 this.menu = this.addxtype(Roo.apply({}, this.menu));
2517 onClick : function(e)
2519 Roo.log('item on click ');
2521 if(this.preventDefault){
2524 //this.parent().hideMenuItems();
2526 this.fireEvent('click', this, e);
2545 * @class Roo.bootstrap.MenuSeparator
2546 * @extends Roo.bootstrap.Component
2547 * Bootstrap MenuSeparator class
2550 * Create a new MenuItem
2551 * @param {Object} config The config object
2555 Roo.bootstrap.MenuSeparator = function(config){
2556 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2559 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2561 getAutoCreate : function(){
2580 * @class Roo.bootstrap.Modal
2581 * @extends Roo.bootstrap.Component
2582 * Bootstrap Modal class
2583 * @cfg {String} title Title of dialog
2584 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2585 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2586 * @cfg {Boolean} specificTitle default false
2587 * @cfg {Array} buttons Array of buttons or standard button set..
2588 * @cfg {String} buttonPosition (left|right|center) default right
2589 * @cfg {Boolean} animate default true
2590 * @cfg {Boolean} allow_close default true
2591 * @cfg {Boolean} fitwindow default false
2592 * @cfg {String} size (sm|lg) default empty
2596 * Create a new Modal Dialog
2597 * @param {Object} config The config object
2600 Roo.bootstrap.Modal = function(config){
2601 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2606 * The raw btnclick event for the button
2607 * @param {Roo.EventObject} e
2612 * Fire when dialog resize
2613 * @param {Roo.bootstrap.Modal} this
2614 * @param {Roo.EventObject} e
2618 this.buttons = this.buttons || [];
2621 this.tmpl = Roo.factory(this.tmpl);
2626 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2628 title : 'test dialog',
2638 specificTitle: false,
2640 buttonPosition: 'right',
2659 onRender : function(ct, position)
2661 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2664 var cfg = Roo.apply({}, this.getAutoCreate());
2667 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2669 //if (!cfg.name.length) {
2673 cfg.cls += ' ' + this.cls;
2676 cfg.style = this.style;
2678 this.el = Roo.get(document.body).createChild(cfg, position);
2680 //var type = this.el.dom.type;
2683 if(this.tabIndex !== undefined){
2684 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2687 this.dialogEl = this.el.select('.modal-dialog',true).first();
2688 this.bodyEl = this.el.select('.modal-body',true).first();
2689 this.closeEl = this.el.select('.modal-header .close', true).first();
2690 this.headerEl = this.el.select('.modal-header',true).first();
2691 this.titleEl = this.el.select('.modal-title',true).first();
2692 this.footerEl = this.el.select('.modal-footer',true).first();
2694 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2695 this.maskEl.enableDisplayMode("block");
2697 //this.el.addClass("x-dlg-modal");
2699 if (this.buttons.length) {
2700 Roo.each(this.buttons, function(bb) {
2701 var b = Roo.apply({}, bb);
2702 b.xns = b.xns || Roo.bootstrap;
2703 b.xtype = b.xtype || 'Button';
2704 if (typeof(b.listeners) == 'undefined') {
2705 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2708 var btn = Roo.factory(b);
2710 btn.render(this.el.select('.modal-footer div').first());
2714 // render the children.
2717 if(typeof(this.items) != 'undefined'){
2718 var items = this.items;
2721 for(var i =0;i < items.length;i++) {
2722 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2726 this.items = nitems;
2728 // where are these used - they used to be body/close/footer
2732 //this.el.addClass([this.fieldClass, this.cls]);
2736 getAutoCreate : function(){
2741 html : this.html || ''
2746 cls : 'modal-title',
2750 if(this.specificTitle){
2756 if (this.allow_close) {
2768 if(this.size.length){
2769 size = 'modal-' + this.size;
2774 style : 'display: none',
2777 cls: "modal-dialog " + size,
2780 cls : "modal-content",
2783 cls : 'modal-header',
2788 cls : 'modal-footer',
2792 cls: 'btn-' + this.buttonPosition
2809 modal.cls += ' fade';
2815 getChildContainer : function() {
2820 getButtonContainer : function() {
2821 return this.el.select('.modal-footer div',true).first();
2824 initEvents : function()
2826 if (this.allow_close) {
2827 this.closeEl.on('click', this.hide, this);
2829 Roo.EventManager.onWindowResize(this.resize, this, true);
2836 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2837 if (this.fitwindow) {
2838 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2839 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2844 setSize : function(w,h)
2854 if (!this.rendered) {
2858 this.el.setStyle('display', 'block');
2860 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2863 this.el.addClass('in');
2866 this.el.addClass('in');
2870 // not sure how we can show data in here..
2872 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2875 Roo.get(document.body).addClass("x-body-masked");
2877 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2878 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2883 this.fireEvent('show', this);
2885 // set zindex here - otherwise it appears to be ignored...
2886 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2889 this.items.forEach( function(e) {
2890 e.layout ? e.layout() : false;
2898 if(this.fireEvent("beforehide", this) !== false){
2900 Roo.get(document.body).removeClass("x-body-masked");
2901 this.el.removeClass('in');
2902 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2904 if(this.animate){ // why
2906 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2908 this.el.setStyle('display', 'none');
2910 this.fireEvent('hide', this);
2914 addButton : function(str, cb)
2918 var b = Roo.apply({}, { html : str } );
2919 b.xns = b.xns || Roo.bootstrap;
2920 b.xtype = b.xtype || 'Button';
2921 if (typeof(b.listeners) == 'undefined') {
2922 b.listeners = { click : cb.createDelegate(this) };
2925 var btn = Roo.factory(b);
2927 btn.render(this.el.select('.modal-footer div').first());
2933 setDefaultButton : function(btn)
2935 //this.el.select('.modal-footer').()
2939 resizeTo: function(w,h)
2943 this.dialogEl.setWidth(w);
2944 if (this.diff === false) {
2945 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2948 this.bodyEl.setHeight(h-this.diff);
2950 this.fireEvent('resize', this);
2953 setContentSize : function(w, h)
2957 onButtonClick: function(btn,e)
2960 this.fireEvent('btnclick', btn.name, e);
2963 * Set the title of the Dialog
2964 * @param {String} str new Title
2966 setTitle: function(str) {
2967 this.titleEl.dom.innerHTML = str;
2970 * Set the body of the Dialog
2971 * @param {String} str new Title
2973 setBody: function(str) {
2974 this.bodyEl.dom.innerHTML = str;
2977 * Set the body of the Dialog using the template
2978 * @param {Obj} data - apply this data to the template and replace the body contents.
2980 applyBody: function(obj)
2983 Roo.log("Error - using apply Body without a template");
2986 this.tmpl.overwrite(this.bodyEl, obj);
2992 Roo.apply(Roo.bootstrap.Modal, {
2994 * Button config that displays a single OK button
3003 * Button config that displays Yes and No buttons
3019 * Button config that displays OK and Cancel buttons
3034 * Button config that displays Yes, No and Cancel buttons
3058 * messagebox - can be used as a replace
3062 * @class Roo.MessageBox
3063 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3067 Roo.Msg.alert('Status', 'Changes saved successfully.');
3069 // Prompt for user data:
3070 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3072 // process text value...
3076 // Show a dialog using config options:
3078 title:'Save Changes?',
3079 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3080 buttons: Roo.Msg.YESNOCANCEL,
3087 Roo.bootstrap.MessageBox = function(){
3088 var dlg, opt, mask, waitTimer;
3089 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3090 var buttons, activeTextEl, bwidth;
3094 var handleButton = function(button){
3096 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3100 var handleHide = function(){
3102 dlg.el.removeClass(opt.cls);
3105 // Roo.TaskMgr.stop(waitTimer);
3106 // waitTimer = null;
3111 var updateButtons = function(b){
3114 buttons["ok"].hide();
3115 buttons["cancel"].hide();
3116 buttons["yes"].hide();
3117 buttons["no"].hide();
3118 //dlg.footer.dom.style.display = 'none';
3121 dlg.footerEl.dom.style.display = '';
3122 for(var k in buttons){
3123 if(typeof buttons[k] != "function"){
3126 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3127 width += buttons[k].el.getWidth()+15;
3137 var handleEsc = function(d, k, e){
3138 if(opt && opt.closable !== false){
3148 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3149 * @return {Roo.BasicDialog} The BasicDialog element
3151 getDialog : function(){
3153 dlg = new Roo.bootstrap.Modal( {
3156 //constraintoviewport:false,
3158 //collapsible : false,
3163 //buttonAlign:"center",
3164 closeClick : function(){
3165 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3168 handleButton("cancel");
3173 dlg.on("hide", handleHide);
3175 //dlg.addKeyListener(27, handleEsc);
3177 this.buttons = buttons;
3178 var bt = this.buttonText;
3179 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3180 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3181 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3182 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3184 bodyEl = dlg.bodyEl.createChild({
3186 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3187 '<textarea class="roo-mb-textarea"></textarea>' +
3188 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3190 msgEl = bodyEl.dom.firstChild;
3191 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3192 textboxEl.enableDisplayMode();
3193 textboxEl.addKeyListener([10,13], function(){
3194 if(dlg.isVisible() && opt && opt.buttons){
3197 }else if(opt.buttons.yes){
3198 handleButton("yes");
3202 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3203 textareaEl.enableDisplayMode();
3204 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3205 progressEl.enableDisplayMode();
3207 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3208 var pf = progressEl.dom.firstChild;
3210 pp = Roo.get(pf.firstChild);
3211 pp.setHeight(pf.offsetHeight);
3219 * Updates the message box body text
3220 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3221 * the XHTML-compliant non-breaking space character '&#160;')
3222 * @return {Roo.MessageBox} This message box
3224 updateText : function(text)
3226 if(!dlg.isVisible() && !opt.width){
3227 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3228 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3230 msgEl.innerHTML = text || ' ';
3232 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3233 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3235 Math.min(opt.width || cw , this.maxWidth),
3236 Math.max(opt.minWidth || this.minWidth, bwidth)
3239 activeTextEl.setWidth(w);
3241 if(dlg.isVisible()){
3242 dlg.fixedcenter = false;
3244 // to big, make it scroll. = But as usual stupid IE does not support
3247 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3248 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3249 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3251 bodyEl.dom.style.height = '';
3252 bodyEl.dom.style.overflowY = '';
3255 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3257 bodyEl.dom.style.overflowX = '';
3260 dlg.setContentSize(w, bodyEl.getHeight());
3261 if(dlg.isVisible()){
3262 dlg.fixedcenter = true;
3268 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3269 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3270 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3271 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3272 * @return {Roo.MessageBox} This message box
3274 updateProgress : function(value, text){
3276 this.updateText(text);
3279 if (pp) { // weird bug on my firefox - for some reason this is not defined
3280 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3281 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3287 * Returns true if the message box is currently displayed
3288 * @return {Boolean} True if the message box is visible, else false
3290 isVisible : function(){
3291 return dlg && dlg.isVisible();
3295 * Hides the message box if it is displayed
3298 if(this.isVisible()){
3304 * Displays a new message box, or reinitializes an existing message box, based on the config options
3305 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3306 * The following config object properties are supported:
3308 Property Type Description
3309 ---------- --------------- ------------------------------------------------------------------------------------
3310 animEl String/Element An id or Element from which the message box should animate as it opens and
3311 closes (defaults to undefined)
3312 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3313 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3314 closable Boolean False to hide the top-right close button (defaults to true). Note that
3315 progress and wait dialogs will ignore this property and always hide the
3316 close button as they can only be closed programmatically.
3317 cls String A custom CSS class to apply to the message box element
3318 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3319 displayed (defaults to 75)
3320 fn Function A callback function to execute after closing the dialog. The arguments to the
3321 function will be btn (the name of the button that was clicked, if applicable,
3322 e.g. "ok"), and text (the value of the active text field, if applicable).
3323 Progress and wait dialogs will ignore this option since they do not respond to
3324 user actions and can only be closed programmatically, so any required function
3325 should be called by the same code after it closes the dialog.
3326 icon String A CSS class that provides a background image to be used as an icon for
3327 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3328 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3329 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3330 modal Boolean False to allow user interaction with the page while the message box is
3331 displayed (defaults to true)
3332 msg String A string that will replace the existing message box body text (defaults
3333 to the XHTML-compliant non-breaking space character ' ')
3334 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3335 progress Boolean True to display a progress bar (defaults to false)
3336 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3337 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3338 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3339 title String The title text
3340 value String The string value to set into the active textbox element if displayed
3341 wait Boolean True to display a progress bar (defaults to false)
3342 width Number The width of the dialog in pixels
3349 msg: 'Please enter your address:',
3351 buttons: Roo.MessageBox.OKCANCEL,
3354 animEl: 'addAddressBtn'
3357 * @param {Object} config Configuration options
3358 * @return {Roo.MessageBox} This message box
3360 show : function(options)
3363 // this causes nightmares if you show one dialog after another
3364 // especially on callbacks..
3366 if(this.isVisible()){
3369 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3370 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3371 Roo.log("New Dialog Message:" + options.msg )
3372 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3373 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3376 var d = this.getDialog();
3378 d.setTitle(opt.title || " ");
3379 d.closeEl.setDisplayed(opt.closable !== false);
3380 activeTextEl = textboxEl;
3381 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3386 textareaEl.setHeight(typeof opt.multiline == "number" ?
3387 opt.multiline : this.defaultTextHeight);
3388 activeTextEl = textareaEl;
3397 progressEl.setDisplayed(opt.progress === true);
3398 this.updateProgress(0);
3399 activeTextEl.dom.value = opt.value || "";
3401 dlg.setDefaultButton(activeTextEl);
3403 var bs = opt.buttons;
3407 }else if(bs && bs.yes){
3408 db = buttons["yes"];
3410 dlg.setDefaultButton(db);
3412 bwidth = updateButtons(opt.buttons);
3413 this.updateText(opt.msg);
3415 d.el.addClass(opt.cls);
3417 d.proxyDrag = opt.proxyDrag === true;
3418 d.modal = opt.modal !== false;
3419 d.mask = opt.modal !== false ? mask : false;
3421 // force it to the end of the z-index stack so it gets a cursor in FF
3422 document.body.appendChild(dlg.el.dom);
3423 d.animateTarget = null;
3424 d.show(options.animEl);
3430 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3431 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3432 * and closing the message box when the process is complete.
3433 * @param {String} title The title bar text
3434 * @param {String} msg The message box body text
3435 * @return {Roo.MessageBox} This message box
3437 progress : function(title, msg){
3444 minWidth: this.minProgressWidth,
3451 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3452 * If a callback function is passed it will be called after the user clicks the button, and the
3453 * id of the button that was clicked will be passed as the only parameter to the callback
3454 * (could also be the top-right close button).
3455 * @param {String} title The title bar text
3456 * @param {String} msg The message box body text
3457 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3458 * @param {Object} scope (optional) The scope of the callback function
3459 * @return {Roo.MessageBox} This message box
3461 alert : function(title, msg, fn, scope)
3476 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3477 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3478 * You are responsible for closing the message box when the process is complete.
3479 * @param {String} msg The message box body text
3480 * @param {String} title (optional) The title bar text
3481 * @return {Roo.MessageBox} This message box
3483 wait : function(msg, title){
3494 waitTimer = Roo.TaskMgr.start({
3496 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3504 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3505 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3506 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3507 * @param {String} title The title bar text
3508 * @param {String} msg The message box body text
3509 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3510 * @param {Object} scope (optional) The scope of the callback function
3511 * @return {Roo.MessageBox} This message box
3513 confirm : function(title, msg, fn, scope){
3517 buttons: this.YESNO,
3526 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3527 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3528 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3529 * (could also be the top-right close button) and the text that was entered will be passed as the two
3530 * parameters to the callback.
3531 * @param {String} title The title bar text
3532 * @param {String} msg The message box body text
3533 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3534 * @param {Object} scope (optional) The scope of the callback function
3535 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3536 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3537 * @return {Roo.MessageBox} This message box
3539 prompt : function(title, msg, fn, scope, multiline){
3543 buttons: this.OKCANCEL,
3548 multiline: multiline,
3555 * Button config that displays a single OK button
3560 * Button config that displays Yes and No buttons
3563 YESNO : {yes:true, no:true},
3565 * Button config that displays OK and Cancel buttons
3568 OKCANCEL : {ok:true, cancel:true},
3570 * Button config that displays Yes, No and Cancel buttons
3573 YESNOCANCEL : {yes:true, no:true, cancel:true},
3576 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3579 defaultTextHeight : 75,
3581 * The maximum width in pixels of the message box (defaults to 600)
3586 * The minimum width in pixels of the message box (defaults to 100)
3591 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3592 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3595 minProgressWidth : 250,
3597 * An object containing the default button text strings that can be overriden for localized language support.
3598 * Supported properties are: ok, cancel, yes and no.
3599 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3612 * Shorthand for {@link Roo.MessageBox}
3614 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3615 Roo.Msg = Roo.Msg || Roo.MessageBox;
3624 * @class Roo.bootstrap.Navbar
3625 * @extends Roo.bootstrap.Component
3626 * Bootstrap Navbar class
3629 * Create a new Navbar
3630 * @param {Object} config The config object
3634 Roo.bootstrap.Navbar = function(config){
3635 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3639 * @event beforetoggle
3640 * Fire before toggle the menu
3641 * @param {Roo.EventObject} e
3643 "beforetoggle" : true
3647 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3656 getAutoCreate : function(){
3659 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3663 initEvents :function ()
3665 //Roo.log(this.el.select('.navbar-toggle',true));
3666 this.el.select('.navbar-toggle',true).on('click', function() {
3667 if(this.fireEvent('beforetoggle', this) !== false){
3668 this.el.select('.navbar-collapse',true).toggleClass('in');
3678 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3680 var size = this.el.getSize();
3681 this.maskEl.setSize(size.width, size.height);
3682 this.maskEl.enableDisplayMode("block");
3691 getChildContainer : function()
3693 if (this.el.select('.collapse').getCount()) {
3694 return this.el.select('.collapse',true).first();
3727 * @class Roo.bootstrap.NavSimplebar
3728 * @extends Roo.bootstrap.Navbar
3729 * Bootstrap Sidebar class
3731 * @cfg {Boolean} inverse is inverted color
3733 * @cfg {String} type (nav | pills | tabs)
3734 * @cfg {Boolean} arrangement stacked | justified
3735 * @cfg {String} align (left | right) alignment
3737 * @cfg {Boolean} main (true|false) main nav bar? default false
3738 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3740 * @cfg {String} tag (header|footer|nav|div) default is nav
3746 * Create a new Sidebar
3747 * @param {Object} config The config object
3751 Roo.bootstrap.NavSimplebar = function(config){
3752 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3755 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3771 getAutoCreate : function(){
3775 tag : this.tag || 'div',
3788 this.type = this.type || 'nav';
3789 if (['tabs','pills'].indexOf(this.type)!==-1) {
3790 cfg.cn[0].cls += ' nav-' + this.type
3794 if (this.type!=='nav') {
3795 Roo.log('nav type must be nav/tabs/pills')
3797 cfg.cn[0].cls += ' navbar-nav'
3803 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3804 cfg.cn[0].cls += ' nav-' + this.arrangement;
3808 if (this.align === 'right') {
3809 cfg.cn[0].cls += ' navbar-right';
3813 cfg.cls += ' navbar-inverse';
3840 * @class Roo.bootstrap.NavHeaderbar
3841 * @extends Roo.bootstrap.NavSimplebar
3842 * Bootstrap Sidebar class
3844 * @cfg {String} brand what is brand
3845 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3846 * @cfg {String} brand_href href of the brand
3847 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3848 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3849 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3850 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3853 * Create a new Sidebar
3854 * @param {Object} config The config object
3858 Roo.bootstrap.NavHeaderbar = function(config){
3859 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3863 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3870 desktopCenter : false,
3873 getAutoCreate : function(){
3876 tag: this.nav || 'nav',
3883 if (this.desktopCenter) {
3884 cn.push({cls : 'container', cn : []});
3891 cls: 'navbar-header',
3896 cls: 'navbar-toggle',
3897 'data-toggle': 'collapse',
3902 html: 'Toggle navigation'
3924 cls: 'collapse navbar-collapse',
3928 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3930 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3931 cfg.cls += ' navbar-' + this.position;
3933 // tag can override this..
3935 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3938 if (this.brand !== '') {
3941 href: this.brand_href ? this.brand_href : '#',
3942 cls: 'navbar-brand',
3950 cfg.cls += ' main-nav';
3958 getHeaderChildContainer : function()
3960 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3961 return this.el.select('.navbar-header',true).first();
3964 return this.getChildContainer();
3968 initEvents : function()
3970 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3972 if (this.autohide) {
3977 Roo.get(document).on('scroll',function(e) {
3978 var ns = Roo.get(document).getScroll().top;
3979 var os = prevScroll;
3983 ft.removeClass('slideDown');
3984 ft.addClass('slideUp');
3987 ft.removeClass('slideUp');
3988 ft.addClass('slideDown');
4009 * @class Roo.bootstrap.NavSidebar
4010 * @extends Roo.bootstrap.Navbar
4011 * Bootstrap Sidebar class
4014 * Create a new Sidebar
4015 * @param {Object} config The config object
4019 Roo.bootstrap.NavSidebar = function(config){
4020 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4023 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4025 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4027 getAutoCreate : function(){
4032 cls: 'sidebar sidebar-nav'
4054 * @class Roo.bootstrap.NavGroup
4055 * @extends Roo.bootstrap.Component
4056 * Bootstrap NavGroup class
4057 * @cfg {String} align (left|right)
4058 * @cfg {Boolean} inverse
4059 * @cfg {String} type (nav|pills|tab) default nav
4060 * @cfg {String} navId - reference Id for navbar.
4064 * Create a new nav group
4065 * @param {Object} config The config object
4068 Roo.bootstrap.NavGroup = function(config){
4069 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4072 Roo.bootstrap.NavGroup.register(this);
4076 * Fires when the active item changes
4077 * @param {Roo.bootstrap.NavGroup} this
4078 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4079 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4086 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4097 getAutoCreate : function()
4099 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4106 if (['tabs','pills'].indexOf(this.type)!==-1) {
4107 cfg.cls += ' nav-' + this.type
4109 if (this.type!=='nav') {
4110 Roo.log('nav type must be nav/tabs/pills')
4112 cfg.cls += ' navbar-nav'
4115 if (this.parent() && this.parent().sidebar) {
4118 cls: 'dashboard-menu sidebar-menu'
4124 if (this.form === true) {
4130 if (this.align === 'right') {
4131 cfg.cls += ' navbar-right';
4133 cfg.cls += ' navbar-left';
4137 if (this.align === 'right') {
4138 cfg.cls += ' navbar-right';
4142 cfg.cls += ' navbar-inverse';
4150 * sets the active Navigation item
4151 * @param {Roo.bootstrap.NavItem} the new current navitem
4153 setActiveItem : function(item)
4156 Roo.each(this.navItems, function(v){
4161 v.setActive(false, true);
4168 item.setActive(true, true);
4169 this.fireEvent('changed', this, item, prev);
4174 * gets the active Navigation item
4175 * @return {Roo.bootstrap.NavItem} the current navitem
4177 getActive : function()
4181 Roo.each(this.navItems, function(v){
4192 indexOfNav : function()
4196 Roo.each(this.navItems, function(v,i){
4207 * adds a Navigation item
4208 * @param {Roo.bootstrap.NavItem} the navitem to add
4210 addItem : function(cfg)
4212 var cn = new Roo.bootstrap.NavItem(cfg);
4214 cn.parentId = this.id;
4215 cn.onRender(this.el, null);
4219 * register a Navigation item
4220 * @param {Roo.bootstrap.NavItem} the navitem to add
4222 register : function(item)
4224 this.navItems.push( item);
4225 item.navId = this.navId;
4230 * clear all the Navigation item
4233 clearAll : function()
4236 this.el.dom.innerHTML = '';
4239 getNavItem: function(tabId)
4242 Roo.each(this.navItems, function(e) {
4243 if (e.tabId == tabId) {
4253 setActiveNext : function()
4255 var i = this.indexOfNav(this.getActive());
4256 if (i > this.navItems.length) {
4259 this.setActiveItem(this.navItems[i+1]);
4261 setActivePrev : function()
4263 var i = this.indexOfNav(this.getActive());
4267 this.setActiveItem(this.navItems[i-1]);
4269 clearWasActive : function(except) {
4270 Roo.each(this.navItems, function(e) {
4271 if (e.tabId != except.tabId && e.was_active) {
4272 e.was_active = false;
4279 getWasActive : function ()
4282 Roo.each(this.navItems, function(e) {
4297 Roo.apply(Roo.bootstrap.NavGroup, {
4301 * register a Navigation Group
4302 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4304 register : function(navgrp)
4306 this.groups[navgrp.navId] = navgrp;
4310 * fetch a Navigation Group based on the navigation ID
4311 * @param {string} the navgroup to add
4312 * @returns {Roo.bootstrap.NavGroup} the navgroup
4314 get: function(navId) {
4315 if (typeof(this.groups[navId]) == 'undefined') {
4317 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4319 return this.groups[navId] ;
4334 * @class Roo.bootstrap.NavItem
4335 * @extends Roo.bootstrap.Component
4336 * Bootstrap Navbar.NavItem class
4337 * @cfg {String} href link to
4338 * @cfg {String} html content of button
4339 * @cfg {String} badge text inside badge
4340 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4341 * @cfg {String} glyphicon name of glyphicon
4342 * @cfg {String} icon name of font awesome icon
4343 * @cfg {Boolean} active Is item active
4344 * @cfg {Boolean} disabled Is item disabled
4346 * @cfg {Boolean} preventDefault (true | false) default false
4347 * @cfg {String} tabId the tab that this item activates.
4348 * @cfg {String} tagtype (a|span) render as a href or span?
4349 * @cfg {Boolean} animateRef (true|false) link to element default false
4352 * Create a new Navbar Item
4353 * @param {Object} config The config object
4355 Roo.bootstrap.NavItem = function(config){
4356 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4361 * The raw click event for the entire grid.
4362 * @param {Roo.EventObject} e
4367 * Fires when the active item active state changes
4368 * @param {Roo.bootstrap.NavItem} this
4369 * @param {boolean} state the new state
4375 * Fires when scroll to element
4376 * @param {Roo.bootstrap.NavItem} this
4377 * @param {Object} options
4378 * @param {Roo.EventObject} e
4386 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4394 preventDefault : false,
4401 getAutoCreate : function(){
4410 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4412 if (this.disabled) {
4413 cfg.cls += ' disabled';
4416 if (this.href || this.html || this.glyphicon || this.icon) {
4420 href : this.href || "#",
4421 html: this.html || ''
4426 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4429 if(this.glyphicon) {
4430 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4435 cfg.cn[0].html += " <span class='caret'></span>";
4439 if (this.badge !== '') {
4441 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4449 initEvents: function()
4451 if (typeof (this.menu) != 'undefined') {
4452 this.menu.parentType = this.xtype;
4453 this.menu.triggerEl = this.el;
4454 this.menu = this.addxtype(Roo.apply({}, this.menu));
4457 this.el.select('a',true).on('click', this.onClick, this);
4459 if(this.tagtype == 'span'){
4460 this.el.select('span',true).on('click', this.onClick, this);
4463 // at this point parent should be available..
4464 this.parent().register(this);
4467 onClick : function(e)
4469 if (e.getTarget('.dropdown-menu-item')) {
4470 // did you click on a menu itemm.... - then don't trigger onclick..
4475 this.preventDefault ||
4478 Roo.log("NavItem - prevent Default?");
4482 if (this.disabled) {
4486 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4487 if (tg && tg.transition) {
4488 Roo.log("waiting for the transitionend");
4494 //Roo.log("fire event clicked");
4495 if(this.fireEvent('click', this, e) === false){
4499 if(this.tagtype == 'span'){
4503 //Roo.log(this.href);
4504 var ael = this.el.select('a',true).first();
4507 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4508 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4509 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4510 return; // ignore... - it's a 'hash' to another page.
4512 Roo.log("NavItem - prevent Default?");
4514 this.scrollToElement(e);
4518 var p = this.parent();
4520 if (['tabs','pills'].indexOf(p.type)!==-1) {
4521 if (typeof(p.setActiveItem) !== 'undefined') {
4522 p.setActiveItem(this);
4526 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4527 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4528 // remove the collapsed menu expand...
4529 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4533 isActive: function () {
4536 setActive : function(state, fire, is_was_active)
4538 if (this.active && !state && this.navId) {
4539 this.was_active = true;
4540 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4542 nv.clearWasActive(this);
4546 this.active = state;
4549 this.el.removeClass('active');
4550 } else if (!this.el.hasClass('active')) {
4551 this.el.addClass('active');
4554 this.fireEvent('changed', this, state);
4557 // show a panel if it's registered and related..
4559 if (!this.navId || !this.tabId || !state || is_was_active) {
4563 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4567 var pan = tg.getPanelByName(this.tabId);
4571 // if we can not flip to new panel - go back to old nav highlight..
4572 if (false == tg.showPanel(pan)) {
4573 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4575 var onav = nv.getWasActive();
4577 onav.setActive(true, false, true);
4586 // this should not be here...
4587 setDisabled : function(state)
4589 this.disabled = state;
4591 this.el.removeClass('disabled');
4592 } else if (!this.el.hasClass('disabled')) {
4593 this.el.addClass('disabled');
4599 * Fetch the element to display the tooltip on.
4600 * @return {Roo.Element} defaults to this.el
4602 tooltipEl : function()
4604 return this.el.select('' + this.tagtype + '', true).first();
4607 scrollToElement : function(e)
4609 var c = document.body;
4612 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4614 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4615 c = document.documentElement;
4618 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4624 var o = target.calcOffsetsTo(c);
4631 this.fireEvent('scrollto', this, options, e);
4633 Roo.get(c).scrollTo('top', options.value, true);
4646 * <span> icon </span>
4647 * <span> text </span>
4648 * <span>badge </span>
4652 * @class Roo.bootstrap.NavSidebarItem
4653 * @extends Roo.bootstrap.NavItem
4654 * Bootstrap Navbar.NavSidebarItem class
4655 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4656 * {Boolean} open is the menu open
4657 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4658 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4659 * {String} buttonSize (sm|md|lg)the extra classes for the button
4660 * {Boolean} showArrow show arrow next to the text (default true)
4662 * Create a new Navbar Button
4663 * @param {Object} config The config object
4665 Roo.bootstrap.NavSidebarItem = function(config){
4666 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4671 * The raw click event for the entire grid.
4672 * @param {Roo.EventObject} e
4677 * Fires when the active item active state changes
4678 * @param {Roo.bootstrap.NavSidebarItem} this
4679 * @param {boolean} state the new state
4687 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4689 badgeWeight : 'default',
4695 buttonWeight : 'default',
4701 getAutoCreate : function(){
4706 href : this.href || '#',
4712 if(this.buttonView){
4715 href : this.href || '#',
4716 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4729 cfg.cls += ' active';
4732 if (this.disabled) {
4733 cfg.cls += ' disabled';
4736 cfg.cls += ' open x-open';
4739 if (this.glyphicon || this.icon) {
4740 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4741 a.cn.push({ tag : 'i', cls : c }) ;
4744 if(!this.buttonView){
4747 html : this.html || ''
4754 if (this.badge !== '') {
4755 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4761 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4764 a.cls += ' dropdown-toggle treeview' ;
4770 initEvents : function()
4772 if (typeof (this.menu) != 'undefined') {
4773 this.menu.parentType = this.xtype;
4774 this.menu.triggerEl = this.el;
4775 this.menu = this.addxtype(Roo.apply({}, this.menu));
4778 this.el.on('click', this.onClick, this);
4780 if(this.badge !== ''){
4781 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4786 onClick : function(e)
4793 if(this.preventDefault){
4797 this.fireEvent('click', this);
4800 disable : function()
4802 this.setDisabled(true);
4807 this.setDisabled(false);
4810 setDisabled : function(state)
4812 if(this.disabled == state){
4816 this.disabled = state;
4819 this.el.addClass('disabled');
4823 this.el.removeClass('disabled');
4828 setActive : function(state)
4830 if(this.active == state){
4834 this.active = state;
4837 this.el.addClass('active');
4841 this.el.removeClass('active');
4846 isActive: function ()
4851 setBadge : function(str)
4857 this.badgeEl.dom.innerHTML = str;
4874 * @class Roo.bootstrap.Row
4875 * @extends Roo.bootstrap.Component
4876 * Bootstrap Row class (contains columns...)
4880 * @param {Object} config The config object
4883 Roo.bootstrap.Row = function(config){
4884 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4887 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4889 getAutoCreate : function(){
4908 * @class Roo.bootstrap.Element
4909 * @extends Roo.bootstrap.Component
4910 * Bootstrap Element class
4911 * @cfg {String} html contents of the element
4912 * @cfg {String} tag tag of the element
4913 * @cfg {String} cls class of the element
4914 * @cfg {Boolean} preventDefault (true|false) default false
4915 * @cfg {Boolean} clickable (true|false) default false
4918 * Create a new Element
4919 * @param {Object} config The config object
4922 Roo.bootstrap.Element = function(config){
4923 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4929 * When a element is chick
4930 * @param {Roo.bootstrap.Element} this
4931 * @param {Roo.EventObject} e
4937 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4942 preventDefault: false,
4945 getAutoCreate : function(){
4949 // cls: this.cls, double assign in parent class Component.js :: onRender
4956 initEvents: function()
4958 Roo.bootstrap.Element.superclass.initEvents.call(this);
4961 this.el.on('click', this.onClick, this);
4966 onClick : function(e)
4968 if(this.preventDefault){
4972 this.fireEvent('click', this, e);
4975 getValue : function()
4977 return this.el.dom.innerHTML;
4980 setValue : function(value)
4982 this.el.dom.innerHTML = value;
4997 * @class Roo.bootstrap.Pagination
4998 * @extends Roo.bootstrap.Component
4999 * Bootstrap Pagination class
5000 * @cfg {String} size xs | sm | md | lg
5001 * @cfg {Boolean} inverse false | true
5004 * Create a new Pagination
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Pagination = function(config){
5009 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5018 getAutoCreate : function(){
5024 cfg.cls += ' inverse';
5030 cfg.cls += " " + this.cls;
5048 * @class Roo.bootstrap.PaginationItem
5049 * @extends Roo.bootstrap.Component
5050 * Bootstrap PaginationItem class
5051 * @cfg {String} html text
5052 * @cfg {String} href the link
5053 * @cfg {Boolean} preventDefault (true | false) default true
5054 * @cfg {Boolean} active (true | false) default false
5055 * @cfg {Boolean} disabled default false
5059 * Create a new PaginationItem
5060 * @param {Object} config The config object
5064 Roo.bootstrap.PaginationItem = function(config){
5065 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5070 * The raw click event for the entire grid.
5071 * @param {Roo.EventObject} e
5077 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5081 preventDefault: true,
5086 getAutoCreate : function(){
5092 href : this.href ? this.href : '#',
5093 html : this.html ? this.html : ''
5103 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5107 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5113 initEvents: function() {
5115 this.el.on('click', this.onClick, this);
5118 onClick : function(e)
5120 Roo.log('PaginationItem on click ');
5121 if(this.preventDefault){
5129 this.fireEvent('click', this, e);
5145 * @class Roo.bootstrap.Slider
5146 * @extends Roo.bootstrap.Component
5147 * Bootstrap Slider class
5150 * Create a new Slider
5151 * @param {Object} config The config object
5154 Roo.bootstrap.Slider = function(config){
5155 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5158 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5160 getAutoCreate : function(){
5164 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5168 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5180 * Ext JS Library 1.1.1
5181 * Copyright(c) 2006-2007, Ext JS, LLC.
5183 * Originally Released Under LGPL - original licence link has changed is not relivant.
5186 * <script type="text/javascript">
5191 * @class Roo.grid.ColumnModel
5192 * @extends Roo.util.Observable
5193 * This is the default implementation of a ColumnModel used by the Grid. It defines
5194 * the columns in the grid.
5197 var colModel = new Roo.grid.ColumnModel([
5198 {header: "Ticker", width: 60, sortable: true, locked: true},
5199 {header: "Company Name", width: 150, sortable: true},
5200 {header: "Market Cap.", width: 100, sortable: true},
5201 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5202 {header: "Employees", width: 100, sortable: true, resizable: false}
5207 * The config options listed for this class are options which may appear in each
5208 * individual column definition.
5209 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5211 * @param {Object} config An Array of column config objects. See this class's
5212 * config objects for details.
5214 Roo.grid.ColumnModel = function(config){
5216 * The config passed into the constructor
5218 this.config = config;
5221 // if no id, create one
5222 // if the column does not have a dataIndex mapping,
5223 // map it to the order it is in the config
5224 for(var i = 0, len = config.length; i < len; i++){
5226 if(typeof c.dataIndex == "undefined"){
5229 if(typeof c.renderer == "string"){
5230 c.renderer = Roo.util.Format[c.renderer];
5232 if(typeof c.id == "undefined"){
5235 if(c.editor && c.editor.xtype){
5236 c.editor = Roo.factory(c.editor, Roo.grid);
5238 if(c.editor && c.editor.isFormField){
5239 c.editor = new Roo.grid.GridEditor(c.editor);
5241 this.lookup[c.id] = c;
5245 * The width of columns which have no width specified (defaults to 100)
5248 this.defaultWidth = 100;
5251 * Default sortable of columns which have no sortable specified (defaults to false)
5254 this.defaultSortable = false;
5258 * @event widthchange
5259 * Fires when the width of a column changes.
5260 * @param {ColumnModel} this
5261 * @param {Number} columnIndex The column index
5262 * @param {Number} newWidth The new width
5264 "widthchange": true,
5266 * @event headerchange
5267 * Fires when the text of a header changes.
5268 * @param {ColumnModel} this
5269 * @param {Number} columnIndex The column index
5270 * @param {Number} newText The new header text
5272 "headerchange": true,
5274 * @event hiddenchange
5275 * Fires when a column is hidden or "unhidden".
5276 * @param {ColumnModel} this
5277 * @param {Number} columnIndex The column index
5278 * @param {Boolean} hidden true if hidden, false otherwise
5280 "hiddenchange": true,
5282 * @event columnmoved
5283 * Fires when a column is moved.
5284 * @param {ColumnModel} this
5285 * @param {Number} oldIndex
5286 * @param {Number} newIndex
5288 "columnmoved" : true,
5290 * @event columlockchange
5291 * Fires when a column's locked state is changed
5292 * @param {ColumnModel} this
5293 * @param {Number} colIndex
5294 * @param {Boolean} locked true if locked
5296 "columnlockchange" : true
5298 Roo.grid.ColumnModel.superclass.constructor.call(this);
5300 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5302 * @cfg {String} header The header text to display in the Grid view.
5305 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5306 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5307 * specified, the column's index is used as an index into the Record's data Array.
5310 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5311 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5314 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5315 * Defaults to the value of the {@link #defaultSortable} property.
5316 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5319 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5322 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5325 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5328 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5331 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5332 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5333 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5334 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5337 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5340 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5343 * @cfg {String} cursor (Optional)
5346 * @cfg {String} tooltip (Optional)
5349 * @cfg {Number} xs (Optional)
5352 * @cfg {Number} sm (Optional)
5355 * @cfg {Number} md (Optional)
5358 * @cfg {Number} lg (Optional)
5361 * Returns the id of the column at the specified index.
5362 * @param {Number} index The column index
5363 * @return {String} the id
5365 getColumnId : function(index){
5366 return this.config[index].id;
5370 * Returns the column for a specified id.
5371 * @param {String} id The column id
5372 * @return {Object} the column
5374 getColumnById : function(id){
5375 return this.lookup[id];
5380 * Returns the column for a specified dataIndex.
5381 * @param {String} dataIndex The column dataIndex
5382 * @return {Object|Boolean} the column or false if not found
5384 getColumnByDataIndex: function(dataIndex){
5385 var index = this.findColumnIndex(dataIndex);
5386 return index > -1 ? this.config[index] : false;
5390 * Returns the index for a specified column id.
5391 * @param {String} id The column id
5392 * @return {Number} the index, or -1 if not found
5394 getIndexById : function(id){
5395 for(var i = 0, len = this.config.length; i < len; i++){
5396 if(this.config[i].id == id){
5404 * Returns the index for a specified column dataIndex.
5405 * @param {String} dataIndex The column dataIndex
5406 * @return {Number} the index, or -1 if not found
5409 findColumnIndex : function(dataIndex){
5410 for(var i = 0, len = this.config.length; i < len; i++){
5411 if(this.config[i].dataIndex == dataIndex){
5419 moveColumn : function(oldIndex, newIndex){
5420 var c = this.config[oldIndex];
5421 this.config.splice(oldIndex, 1);
5422 this.config.splice(newIndex, 0, c);
5423 this.dataMap = null;
5424 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5427 isLocked : function(colIndex){
5428 return this.config[colIndex].locked === true;
5431 setLocked : function(colIndex, value, suppressEvent){
5432 if(this.isLocked(colIndex) == value){
5435 this.config[colIndex].locked = value;
5437 this.fireEvent("columnlockchange", this, colIndex, value);
5441 getTotalLockedWidth : function(){
5443 for(var i = 0; i < this.config.length; i++){
5444 if(this.isLocked(i) && !this.isHidden(i)){
5445 this.totalWidth += this.getColumnWidth(i);
5451 getLockedCount : function(){
5452 for(var i = 0, len = this.config.length; i < len; i++){
5453 if(!this.isLocked(i)){
5458 return this.config.length;
5462 * Returns the number of columns.
5465 getColumnCount : function(visibleOnly){
5466 if(visibleOnly === true){
5468 for(var i = 0, len = this.config.length; i < len; i++){
5469 if(!this.isHidden(i)){
5475 return this.config.length;
5479 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5480 * @param {Function} fn
5481 * @param {Object} scope (optional)
5482 * @return {Array} result
5484 getColumnsBy : function(fn, scope){
5486 for(var i = 0, len = this.config.length; i < len; i++){
5487 var c = this.config[i];
5488 if(fn.call(scope||this, c, i) === true){
5496 * Returns true if the specified column is sortable.
5497 * @param {Number} col The column index
5500 isSortable : function(col){
5501 if(typeof this.config[col].sortable == "undefined"){
5502 return this.defaultSortable;
5504 return this.config[col].sortable;
5508 * Returns the rendering (formatting) function defined for the column.
5509 * @param {Number} col The column index.
5510 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5512 getRenderer : function(col){
5513 if(!this.config[col].renderer){
5514 return Roo.grid.ColumnModel.defaultRenderer;
5516 return this.config[col].renderer;
5520 * Sets the rendering (formatting) function for a column.
5521 * @param {Number} col The column index
5522 * @param {Function} fn The function to use to process the cell's raw data
5523 * to return HTML markup for the grid view. The render function is called with
5524 * the following parameters:<ul>
5525 * <li>Data value.</li>
5526 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5527 * <li>css A CSS style string to apply to the table cell.</li>
5528 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5529 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5530 * <li>Row index</li>
5531 * <li>Column index</li>
5532 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5534 setRenderer : function(col, fn){
5535 this.config[col].renderer = fn;
5539 * Returns the width for the specified column.
5540 * @param {Number} col The column index
5543 getColumnWidth : function(col){
5544 return this.config[col].width * 1 || this.defaultWidth;
5548 * Sets the width for a column.
5549 * @param {Number} col The column index
5550 * @param {Number} width The new width
5552 setColumnWidth : function(col, width, suppressEvent){
5553 this.config[col].width = width;
5554 this.totalWidth = null;
5556 this.fireEvent("widthchange", this, col, width);
5561 * Returns the total width of all columns.
5562 * @param {Boolean} includeHidden True to include hidden column widths
5565 getTotalWidth : function(includeHidden){
5566 if(!this.totalWidth){
5567 this.totalWidth = 0;
5568 for(var i = 0, len = this.config.length; i < len; i++){
5569 if(includeHidden || !this.isHidden(i)){
5570 this.totalWidth += this.getColumnWidth(i);
5574 return this.totalWidth;
5578 * Returns the header for the specified column.
5579 * @param {Number} col The column index
5582 getColumnHeader : function(col){
5583 return this.config[col].header;
5587 * Sets the header for a column.
5588 * @param {Number} col The column index
5589 * @param {String} header The new header
5591 setColumnHeader : function(col, header){
5592 this.config[col].header = header;
5593 this.fireEvent("headerchange", this, col, header);
5597 * Returns the tooltip for the specified column.
5598 * @param {Number} col The column index
5601 getColumnTooltip : function(col){
5602 return this.config[col].tooltip;
5605 * Sets the tooltip for a column.
5606 * @param {Number} col The column index
5607 * @param {String} tooltip The new tooltip
5609 setColumnTooltip : function(col, tooltip){
5610 this.config[col].tooltip = tooltip;
5614 * Returns the dataIndex for the specified column.
5615 * @param {Number} col The column index
5618 getDataIndex : function(col){
5619 return this.config[col].dataIndex;
5623 * Sets the dataIndex for a column.
5624 * @param {Number} col The column index
5625 * @param {Number} dataIndex The new dataIndex
5627 setDataIndex : function(col, dataIndex){
5628 this.config[col].dataIndex = dataIndex;
5634 * Returns true if the cell is editable.
5635 * @param {Number} colIndex The column index
5636 * @param {Number} rowIndex The row index - this is nto actually used..?
5639 isCellEditable : function(colIndex, rowIndex){
5640 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5644 * Returns the editor defined for the cell/column.
5645 * return false or null to disable editing.
5646 * @param {Number} colIndex The column index
5647 * @param {Number} rowIndex The row index
5650 getCellEditor : function(colIndex, rowIndex){
5651 return this.config[colIndex].editor;
5655 * Sets if a column is editable.
5656 * @param {Number} col The column index
5657 * @param {Boolean} editable True if the column is editable
5659 setEditable : function(col, editable){
5660 this.config[col].editable = editable;
5665 * Returns true if the column is hidden.
5666 * @param {Number} colIndex The column index
5669 isHidden : function(colIndex){
5670 return this.config[colIndex].hidden;
5675 * Returns true if the column width cannot be changed
5677 isFixed : function(colIndex){
5678 return this.config[colIndex].fixed;
5682 * Returns true if the column can be resized
5685 isResizable : function(colIndex){
5686 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5689 * Sets if a column is hidden.
5690 * @param {Number} colIndex The column index
5691 * @param {Boolean} hidden True if the column is hidden
5693 setHidden : function(colIndex, hidden){
5694 this.config[colIndex].hidden = hidden;
5695 this.totalWidth = null;
5696 this.fireEvent("hiddenchange", this, colIndex, hidden);
5700 * Sets the editor for a column.
5701 * @param {Number} col The column index
5702 * @param {Object} editor The editor object
5704 setEditor : function(col, editor){
5705 this.config[col].editor = editor;
5709 Roo.grid.ColumnModel.defaultRenderer = function(value)
5711 if(typeof value == "object") {
5714 if(typeof value == "string" && value.length < 1){
5718 return String.format("{0}", value);
5721 // Alias for backwards compatibility
5722 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5725 * Ext JS Library 1.1.1
5726 * Copyright(c) 2006-2007, Ext JS, LLC.
5728 * Originally Released Under LGPL - original licence link has changed is not relivant.
5731 * <script type="text/javascript">
5735 * @class Roo.LoadMask
5736 * A simple utility class for generically masking elements while loading data. If the element being masked has
5737 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5738 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5739 * element's UpdateManager load indicator and will be destroyed after the initial load.
5741 * Create a new LoadMask
5742 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5743 * @param {Object} config The config object
5745 Roo.LoadMask = function(el, config){
5746 this.el = Roo.get(el);
5747 Roo.apply(this, config);
5749 this.store.on('beforeload', this.onBeforeLoad, this);
5750 this.store.on('load', this.onLoad, this);
5751 this.store.on('loadexception', this.onLoadException, this);
5752 this.removeMask = false;
5754 var um = this.el.getUpdateManager();
5755 um.showLoadIndicator = false; // disable the default indicator
5756 um.on('beforeupdate', this.onBeforeLoad, this);
5757 um.on('update', this.onLoad, this);
5758 um.on('failure', this.onLoad, this);
5759 this.removeMask = true;
5763 Roo.LoadMask.prototype = {
5765 * @cfg {Boolean} removeMask
5766 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5767 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5771 * The text to display in a centered loading message box (defaults to 'Loading...')
5775 * @cfg {String} msgCls
5776 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5778 msgCls : 'x-mask-loading',
5781 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5787 * Disables the mask to prevent it from being displayed
5789 disable : function(){
5790 this.disabled = true;
5794 * Enables the mask so that it can be displayed
5796 enable : function(){
5797 this.disabled = false;
5800 onLoadException : function()
5804 if (typeof(arguments[3]) != 'undefined') {
5805 Roo.MessageBox.alert("Error loading",arguments[3]);
5809 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5810 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5817 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5822 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5826 onBeforeLoad : function(){
5828 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5833 destroy : function(){
5835 this.store.un('beforeload', this.onBeforeLoad, this);
5836 this.store.un('load', this.onLoad, this);
5837 this.store.un('loadexception', this.onLoadException, this);
5839 var um = this.el.getUpdateManager();
5840 um.un('beforeupdate', this.onBeforeLoad, this);
5841 um.un('update', this.onLoad, this);
5842 um.un('failure', this.onLoad, this);
5853 * @class Roo.bootstrap.Table
5854 * @extends Roo.bootstrap.Component
5855 * Bootstrap Table class
5856 * @cfg {String} cls table class
5857 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5858 * @cfg {String} bgcolor Specifies the background color for a table
5859 * @cfg {Number} border Specifies whether the table cells should have borders or not
5860 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5861 * @cfg {Number} cellspacing Specifies the space between cells
5862 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5863 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5864 * @cfg {String} sortable Specifies that the table should be sortable
5865 * @cfg {String} summary Specifies a summary of the content of a table
5866 * @cfg {Number} width Specifies the width of a table
5867 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5869 * @cfg {boolean} striped Should the rows be alternative striped
5870 * @cfg {boolean} bordered Add borders to the table
5871 * @cfg {boolean} hover Add hover highlighting
5872 * @cfg {boolean} condensed Format condensed
5873 * @cfg {boolean} responsive Format condensed
5874 * @cfg {Boolean} loadMask (true|false) default false
5875 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5876 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5877 * @cfg {Boolean} rowSelection (true|false) default false
5878 * @cfg {Boolean} cellSelection (true|false) default false
5879 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5880 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5881 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5885 * Create a new Table
5886 * @param {Object} config The config object
5889 Roo.bootstrap.Table = function(config){
5890 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5895 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5896 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5897 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5898 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5900 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5902 this.sm.grid = this;
5903 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5904 this.sm = this.selModel;
5905 this.sm.xmodule = this.xmodule || false;
5908 if (this.cm && typeof(this.cm.config) == 'undefined') {
5909 this.colModel = new Roo.grid.ColumnModel(this.cm);
5910 this.cm = this.colModel;
5911 this.cm.xmodule = this.xmodule || false;
5914 this.store= Roo.factory(this.store, Roo.data);
5915 this.ds = this.store;
5916 this.ds.xmodule = this.xmodule || false;
5919 if (this.footer && this.store) {
5920 this.footer.dataSource = this.ds;
5921 this.footer = Roo.factory(this.footer);
5928 * Fires when a cell is clicked
5929 * @param {Roo.bootstrap.Table} this
5930 * @param {Roo.Element} el
5931 * @param {Number} rowIndex
5932 * @param {Number} columnIndex
5933 * @param {Roo.EventObject} e
5937 * @event celldblclick
5938 * Fires when a cell is double clicked
5939 * @param {Roo.bootstrap.Table} this
5940 * @param {Roo.Element} el
5941 * @param {Number} rowIndex
5942 * @param {Number} columnIndex
5943 * @param {Roo.EventObject} e
5945 "celldblclick" : true,
5948 * Fires when a row is clicked
5949 * @param {Roo.bootstrap.Table} this
5950 * @param {Roo.Element} el
5951 * @param {Number} rowIndex
5952 * @param {Roo.EventObject} e
5956 * @event rowdblclick
5957 * Fires when a row is double clicked
5958 * @param {Roo.bootstrap.Table} this
5959 * @param {Roo.Element} el
5960 * @param {Number} rowIndex
5961 * @param {Roo.EventObject} e
5963 "rowdblclick" : true,
5966 * Fires when a mouseover occur
5967 * @param {Roo.bootstrap.Table} this
5968 * @param {Roo.Element} el
5969 * @param {Number} rowIndex
5970 * @param {Number} columnIndex
5971 * @param {Roo.EventObject} e
5976 * Fires when a mouseout occur
5977 * @param {Roo.bootstrap.Table} this
5978 * @param {Roo.Element} el
5979 * @param {Number} rowIndex
5980 * @param {Number} columnIndex
5981 * @param {Roo.EventObject} e
5986 * Fires when a row is rendered, so you can change add a style to it.
5987 * @param {Roo.bootstrap.Table} this
5988 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5992 * @event rowsrendered
5993 * Fires when all the rows have been rendered
5994 * @param {Roo.bootstrap.Table} this
5996 'rowsrendered' : true,
5998 * @event contextmenu
5999 * The raw contextmenu event for the entire grid.
6000 * @param {Roo.EventObject} e
6002 "contextmenu" : true,
6004 * @event rowcontextmenu
6005 * Fires when a row is right clicked
6006 * @param {Roo.bootstrap.Table} this
6007 * @param {Number} rowIndex
6008 * @param {Roo.EventObject} e
6010 "rowcontextmenu" : true,
6012 * @event cellcontextmenu
6013 * Fires when a cell is right clicked
6014 * @param {Roo.bootstrap.Table} this
6015 * @param {Number} rowIndex
6016 * @param {Number} cellIndex
6017 * @param {Roo.EventObject} e
6019 "cellcontextmenu" : true,
6021 * @event headercontextmenu
6022 * Fires when a header is right clicked
6023 * @param {Roo.bootstrap.Table} this
6024 * @param {Number} columnIndex
6025 * @param {Roo.EventObject} e
6027 "headercontextmenu" : true
6031 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6057 rowSelection : false,
6058 cellSelection : false,
6061 // Roo.Element - the tbody
6063 // Roo.Element - thead element
6066 container: false, // used by gridpanel...
6070 getAutoCreate : function()
6072 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6079 if (this.scrollBody) {
6080 cfg.cls += ' table-body-fixed';
6083 cfg.cls += ' table-striped';
6087 cfg.cls += ' table-hover';
6089 if (this.bordered) {
6090 cfg.cls += ' table-bordered';
6092 if (this.condensed) {
6093 cfg.cls += ' table-condensed';
6095 if (this.responsive) {
6096 cfg.cls += ' table-responsive';
6100 cfg.cls+= ' ' +this.cls;
6103 // this lot should be simplifed...
6106 cfg.align=this.align;
6109 cfg.bgcolor=this.bgcolor;
6112 cfg.border=this.border;
6114 if (this.cellpadding) {
6115 cfg.cellpadding=this.cellpadding;
6117 if (this.cellspacing) {
6118 cfg.cellspacing=this.cellspacing;
6121 cfg.frame=this.frame;
6124 cfg.rules=this.rules;
6126 if (this.sortable) {
6127 cfg.sortable=this.sortable;
6130 cfg.summary=this.summary;
6133 cfg.width=this.width;
6136 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6139 if(this.store || this.cm){
6140 if(this.headerShow){
6141 cfg.cn.push(this.renderHeader());
6144 cfg.cn.push(this.renderBody());
6146 if(this.footerShow){
6147 cfg.cn.push(this.renderFooter());
6149 // where does this come from?
6150 //cfg.cls+= ' TableGrid';
6153 return { cn : [ cfg ] };
6156 initEvents : function()
6158 if(!this.store || !this.cm){
6161 if (this.selModel) {
6162 this.selModel.initEvents();
6166 //Roo.log('initEvents with ds!!!!');
6168 this.mainBody = this.el.select('tbody', true).first();
6169 this.mainHead = this.el.select('thead', true).first();
6176 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6177 e.on('click', _this.sort, _this);
6180 this.mainBody.on("click", this.onClick, this);
6181 this.mainBody.on("dblclick", this.onDblClick, this);
6183 // why is this done????? = it breaks dialogs??
6184 //this.parent().el.setStyle('position', 'relative');
6188 this.footer.parentId = this.id;
6189 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6192 this.el.select('tfoot tr td').first().addClass('hide');
6196 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6198 this.store.on('load', this.onLoad, this);
6199 this.store.on('beforeload', this.onBeforeLoad, this);
6200 this.store.on('update', this.onUpdate, this);
6201 this.store.on('add', this.onAdd, this);
6202 this.store.on("clear", this.clear, this);
6204 this.el.on("contextmenu", this.onContextMenu, this);
6206 this.mainBody.on('scroll', this.onBodyScroll, this);
6208 this.cm.on("headerchange", this.onHeaderChange, this);
6212 onContextMenu : function(e, t)
6214 this.processEvent("contextmenu", e);
6217 processEvent : function(name, e)
6219 if (name != 'touchstart' ) {
6220 this.fireEvent(name, e);
6223 var t = e.getTarget();
6225 var cell = Roo.get(t);
6231 if(cell.findParent('tfoot', false, true)){
6235 if(cell.findParent('thead', false, true)){
6237 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6238 cell = Roo.get(t).findParent('th', false, true);
6240 Roo.log("failed to find th in thead?");
6241 Roo.log(e.getTarget());
6246 var cellIndex = cell.dom.cellIndex;
6248 var ename = name == 'touchstart' ? 'click' : name;
6249 this.fireEvent("header" + ename, this, cellIndex, e);
6254 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6255 cell = Roo.get(t).findParent('td', false, true);
6257 Roo.log("failed to find th in tbody?");
6258 Roo.log(e.getTarget());
6263 var row = cell.findParent('tr', false, true);
6264 var cellIndex = cell.dom.cellIndex;
6265 var rowIndex = row.dom.rowIndex - 1;
6269 this.fireEvent("row" + name, this, rowIndex, e);
6273 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6279 onMouseover : function(e, el)
6281 var cell = Roo.get(el);
6287 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6288 cell = cell.findParent('td', false, true);
6291 var row = cell.findParent('tr', false, true);
6292 var cellIndex = cell.dom.cellIndex;
6293 var rowIndex = row.dom.rowIndex - 1; // start from 0
6295 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6299 onMouseout : function(e, el)
6301 var cell = Roo.get(el);
6307 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6308 cell = cell.findParent('td', false, true);
6311 var row = cell.findParent('tr', false, true);
6312 var cellIndex = cell.dom.cellIndex;
6313 var rowIndex = row.dom.rowIndex - 1; // start from 0
6315 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6319 onClick : function(e, el)
6321 var cell = Roo.get(el);
6323 if(!cell || (!this.cellSelection && !this.rowSelection)){
6327 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6328 cell = cell.findParent('td', false, true);
6331 if(!cell || typeof(cell) == 'undefined'){
6335 var row = cell.findParent('tr', false, true);
6337 if(!row || typeof(row) == 'undefined'){
6341 var cellIndex = cell.dom.cellIndex;
6342 var rowIndex = this.getRowIndex(row);
6344 // why??? - should these not be based on SelectionModel?
6345 if(this.cellSelection){
6346 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6349 if(this.rowSelection){
6350 this.fireEvent('rowclick', this, row, rowIndex, e);
6356 onDblClick : function(e,el)
6358 var cell = Roo.get(el);
6360 if(!cell || (!this.cellSelection && !this.rowSelection)){
6364 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6365 cell = cell.findParent('td', false, true);
6368 if(!cell || typeof(cell) == 'undefined'){
6372 var row = cell.findParent('tr', false, true);
6374 if(!row || typeof(row) == 'undefined'){
6378 var cellIndex = cell.dom.cellIndex;
6379 var rowIndex = this.getRowIndex(row);
6381 if(this.cellSelection){
6382 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6385 if(this.rowSelection){
6386 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6390 sort : function(e,el)
6392 var col = Roo.get(el);
6394 if(!col.hasClass('sortable')){
6398 var sort = col.attr('sort');
6401 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6405 this.store.sortInfo = {field : sort, direction : dir};
6408 Roo.log("calling footer first");
6409 this.footer.onClick('first');
6412 this.store.load({ params : { start : 0 } });
6416 renderHeader : function()
6424 this.totalWidth = 0;
6426 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6428 var config = cm.config[i];
6433 html: cm.getColumnHeader(i)
6438 if(typeof(config.sortable) != 'undefined' && config.sortable){
6440 c.html = '<i class="glyphicon"></i>' + c.html;
6443 if(typeof(config.lgHeader) != 'undefined'){
6444 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6447 if(typeof(config.mdHeader) != 'undefined'){
6448 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6451 if(typeof(config.smHeader) != 'undefined'){
6452 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6455 if(typeof(config.xsHeader) != 'undefined'){
6456 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6463 if(typeof(config.tooltip) != 'undefined'){
6464 c.tooltip = config.tooltip;
6467 if(typeof(config.colspan) != 'undefined'){
6468 c.colspan = config.colspan;
6471 if(typeof(config.hidden) != 'undefined' && config.hidden){
6472 c.style += ' display:none;';
6475 if(typeof(config.dataIndex) != 'undefined'){
6476 c.sort = config.dataIndex;
6481 if(typeof(config.align) != 'undefined' && config.align.length){
6482 c.style += ' text-align:' + config.align + ';';
6485 if(typeof(config.width) != 'undefined'){
6486 c.style += ' width:' + config.width + 'px;';
6487 this.totalWidth += config.width;
6489 this.totalWidth += 100; // assume minimum of 100 per column?
6492 if(typeof(config.cls) != 'undefined'){
6493 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6496 ['xs','sm','md','lg'].map(function(size){
6498 if(typeof(config[size]) == 'undefined'){
6502 if (!config[size]) { // 0 = hidden
6503 c.cls += ' hidden-' + size;
6507 c.cls += ' col-' + size + '-' + config[size];
6517 renderBody : function()
6527 colspan : this.cm.getColumnCount()
6537 renderFooter : function()
6547 colspan : this.cm.getColumnCount()
6561 // Roo.log('ds onload');
6566 var ds = this.store;
6568 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6569 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6570 if (_this.store.sortInfo) {
6572 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6573 e.select('i', true).addClass(['glyphicon-arrow-up']);
6576 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6577 e.select('i', true).addClass(['glyphicon-arrow-down']);
6582 var tbody = this.mainBody;
6584 if(ds.getCount() > 0){
6585 ds.data.each(function(d,rowIndex){
6586 var row = this.renderRow(cm, ds, rowIndex);
6588 tbody.createChild(row);
6592 if(row.cellObjects.length){
6593 Roo.each(row.cellObjects, function(r){
6594 _this.renderCellObject(r);
6601 Roo.each(this.el.select('tbody td', true).elements, function(e){
6602 e.on('mouseover', _this.onMouseover, _this);
6605 Roo.each(this.el.select('tbody td', true).elements, function(e){
6606 e.on('mouseout', _this.onMouseout, _this);
6608 this.fireEvent('rowsrendered', this);
6609 //if(this.loadMask){
6610 // this.maskEl.hide();
6617 onUpdate : function(ds,record)
6619 this.refreshRow(record);
6623 onRemove : function(ds, record, index, isUpdate){
6624 if(isUpdate !== true){
6625 this.fireEvent("beforerowremoved", this, index, record);
6627 var bt = this.mainBody.dom;
6629 var rows = this.el.select('tbody > tr', true).elements;
6631 if(typeof(rows[index]) != 'undefined'){
6632 bt.removeChild(rows[index].dom);
6635 // if(bt.rows[index]){
6636 // bt.removeChild(bt.rows[index]);
6639 if(isUpdate !== true){
6640 //this.stripeRows(index);
6641 //this.syncRowHeights(index, index);
6643 this.fireEvent("rowremoved", this, index, record);
6647 onAdd : function(ds, records, rowIndex)
6649 //Roo.log('on Add called');
6650 // - note this does not handle multiple adding very well..
6651 var bt = this.mainBody.dom;
6652 for (var i =0 ; i < records.length;i++) {
6653 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6654 //Roo.log(records[i]);
6655 //Roo.log(this.store.getAt(rowIndex+i));
6656 this.insertRow(this.store, rowIndex + i, false);
6663 refreshRow : function(record){
6664 var ds = this.store, index;
6665 if(typeof record == 'number'){
6667 record = ds.getAt(index);
6669 index = ds.indexOf(record);
6671 this.insertRow(ds, index, true);
6673 this.onRemove(ds, record, index+1, true);
6675 //this.syncRowHeights(index, index);
6677 this.fireEvent("rowupdated", this, index, record);
6680 insertRow : function(dm, rowIndex, isUpdate){
6683 this.fireEvent("beforerowsinserted", this, rowIndex);
6685 //var s = this.getScrollState();
6686 var row = this.renderRow(this.cm, this.store, rowIndex);
6687 // insert before rowIndex..
6688 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6692 if(row.cellObjects.length){
6693 Roo.each(row.cellObjects, function(r){
6694 _this.renderCellObject(r);
6699 this.fireEvent("rowsinserted", this, rowIndex);
6700 //this.syncRowHeights(firstRow, lastRow);
6701 //this.stripeRows(firstRow);
6708 getRowDom : function(rowIndex)
6710 var rows = this.el.select('tbody > tr', true).elements;
6712 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6715 // returns the object tree for a tr..
6718 renderRow : function(cm, ds, rowIndex)
6721 var d = ds.getAt(rowIndex);
6728 var cellObjects = [];
6730 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6731 var config = cm.config[i];
6733 var renderer = cm.getRenderer(i);
6737 if(typeof(renderer) !== 'undefined'){
6738 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6740 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6741 // and are rendered into the cells after the row is rendered - using the id for the element.
6743 if(typeof(value) === 'object'){
6753 rowIndex : rowIndex,
6758 this.fireEvent('rowclass', this, rowcfg);
6762 cls : rowcfg.rowClass,
6764 html: (typeof(value) === 'object') ? '' : value
6771 if(typeof(config.colspan) != 'undefined'){
6772 td.colspan = config.colspan;
6775 if(typeof(config.hidden) != 'undefined' && config.hidden){
6776 td.style += ' display:none;';
6779 if(typeof(config.align) != 'undefined' && config.align.length){
6780 td.style += ' text-align:' + config.align + ';';
6783 if(typeof(config.width) != 'undefined'){
6784 td.style += ' width:' + config.width + 'px;';
6787 if(typeof(config.cursor) != 'undefined'){
6788 td.style += ' cursor:' + config.cursor + ';';
6791 if(typeof(config.cls) != 'undefined'){
6792 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6795 ['xs','sm','md','lg'].map(function(size){
6797 if(typeof(config[size]) == 'undefined'){
6801 if (!config[size]) { // 0 = hidden
6802 td.cls += ' hidden-' + size;
6806 td.cls += ' col-' + size + '-' + config[size];
6814 row.cellObjects = cellObjects;
6822 onBeforeLoad : function()
6824 //Roo.log('ds onBeforeLoad');
6828 //if(this.loadMask){
6829 // this.maskEl.show();
6837 this.el.select('tbody', true).first().dom.innerHTML = '';
6840 * Show or hide a row.
6841 * @param {Number} rowIndex to show or hide
6842 * @param {Boolean} state hide
6844 setRowVisibility : function(rowIndex, state)
6846 var bt = this.mainBody.dom;
6848 var rows = this.el.select('tbody > tr', true).elements;
6850 if(typeof(rows[rowIndex]) == 'undefined'){
6853 rows[rowIndex].dom.style.display = state ? '' : 'none';
6857 getSelectionModel : function(){
6859 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6861 return this.selModel;
6864 * Render the Roo.bootstrap object from renderder
6866 renderCellObject : function(r)
6870 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6872 var t = r.cfg.render(r.container);
6875 Roo.each(r.cfg.cn, function(c){
6877 container: t.getChildContainer(),
6880 _this.renderCellObject(child);
6885 getRowIndex : function(row)
6889 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6900 * Returns the grid's underlying element = used by panel.Grid
6901 * @return {Element} The element
6903 getGridEl : function(){
6907 * Forces a resize - used by panel.Grid
6908 * @return {Element} The element
6910 autoSize : function()
6912 //var ctr = Roo.get(this.container.dom.parentElement);
6913 var ctr = Roo.get(this.el.dom);
6915 var thd = this.getGridEl().select('thead',true).first();
6916 var tbd = this.getGridEl().select('tbody', true).first();
6917 var tfd = this.getGridEl().select('tfoot', true).first();
6919 var cw = ctr.getWidth();
6923 tbd.setSize(ctr.getWidth(),
6924 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6926 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6929 cw = Math.max(cw, this.totalWidth);
6930 this.getGridEl().select('tr',true).setWidth(cw);
6931 // resize 'expandable coloumn?
6933 return; // we doe not have a view in this design..
6936 onBodyScroll: function()
6938 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6940 this.mainHead.setStyle({
6941 'position' : 'relative',
6942 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6948 var scrollHeight = this.mainBody.dom.scrollHeight;
6950 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6952 var height = this.mainBody.getHeight();
6954 if(scrollHeight - height == scrollTop) {
6956 var total = this.ds.getTotalCount();
6958 if(this.footer.cursor + this.footer.pageSize < total){
6960 this.footer.ds.load({
6962 start : this.footer.cursor + this.footer.pageSize,
6963 limit : this.footer.pageSize
6973 onHeaderChange : function()
6976 var header = this.renderHeader();
6977 var table = this.el.select('table', true).first();
6979 this.mainHead.remove();
6980 this.mainHead = table.createChild(header, this.mainBody, false);
6995 * @class Roo.bootstrap.TableCell
6996 * @extends Roo.bootstrap.Component
6997 * Bootstrap TableCell class
6998 * @cfg {String} html cell contain text
6999 * @cfg {String} cls cell class
7000 * @cfg {String} tag cell tag (td|th) default td
7001 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7002 * @cfg {String} align Aligns the content in a cell
7003 * @cfg {String} axis Categorizes cells
7004 * @cfg {String} bgcolor Specifies the background color of a cell
7005 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7006 * @cfg {Number} colspan Specifies the number of columns a cell should span
7007 * @cfg {String} headers Specifies one or more header cells a cell is related to
7008 * @cfg {Number} height Sets the height of a cell
7009 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7010 * @cfg {Number} rowspan Sets the number of rows a cell should span
7011 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7012 * @cfg {String} valign Vertical aligns the content in a cell
7013 * @cfg {Number} width Specifies the width of a cell
7016 * Create a new TableCell
7017 * @param {Object} config The config object
7020 Roo.bootstrap.TableCell = function(config){
7021 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7024 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7044 getAutoCreate : function(){
7045 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7065 cfg.align=this.align
7071 cfg.bgcolor=this.bgcolor
7074 cfg.charoff=this.charoff
7077 cfg.colspan=this.colspan
7080 cfg.headers=this.headers
7083 cfg.height=this.height
7086 cfg.nowrap=this.nowrap
7089 cfg.rowspan=this.rowspan
7092 cfg.scope=this.scope
7095 cfg.valign=this.valign
7098 cfg.width=this.width
7117 * @class Roo.bootstrap.TableRow
7118 * @extends Roo.bootstrap.Component
7119 * Bootstrap TableRow class
7120 * @cfg {String} cls row class
7121 * @cfg {String} align Aligns the content in a table row
7122 * @cfg {String} bgcolor Specifies a background color for a table row
7123 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7124 * @cfg {String} valign Vertical aligns the content in a table row
7127 * Create a new TableRow
7128 * @param {Object} config The config object
7131 Roo.bootstrap.TableRow = function(config){
7132 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7135 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7143 getAutoCreate : function(){
7144 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7154 cfg.align = this.align;
7157 cfg.bgcolor = this.bgcolor;
7160 cfg.charoff = this.charoff;
7163 cfg.valign = this.valign;
7181 * @class Roo.bootstrap.TableBody
7182 * @extends Roo.bootstrap.Component
7183 * Bootstrap TableBody class
7184 * @cfg {String} cls element class
7185 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7186 * @cfg {String} align Aligns the content inside the element
7187 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7188 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7191 * Create a new TableBody
7192 * @param {Object} config The config object
7195 Roo.bootstrap.TableBody = function(config){
7196 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7199 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7207 getAutoCreate : function(){
7208 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7222 cfg.align = this.align;
7225 cfg.charoff = this.charoff;
7228 cfg.valign = this.valign;
7235 // initEvents : function()
7242 // this.store = Roo.factory(this.store, Roo.data);
7243 // this.store.on('load', this.onLoad, this);
7245 // this.store.load();
7249 // onLoad: function ()
7251 // this.fireEvent('load', this);
7261 * Ext JS Library 1.1.1
7262 * Copyright(c) 2006-2007, Ext JS, LLC.
7264 * Originally Released Under LGPL - original licence link has changed is not relivant.
7267 * <script type="text/javascript">
7270 // as we use this in bootstrap.
7271 Roo.namespace('Roo.form');
7273 * @class Roo.form.Action
7274 * Internal Class used to handle form actions
7276 * @param {Roo.form.BasicForm} el The form element or its id
7277 * @param {Object} config Configuration options
7282 // define the action interface
7283 Roo.form.Action = function(form, options){
7285 this.options = options || {};
7288 * Client Validation Failed
7291 Roo.form.Action.CLIENT_INVALID = 'client';
7293 * Server Validation Failed
7296 Roo.form.Action.SERVER_INVALID = 'server';
7298 * Connect to Server Failed
7301 Roo.form.Action.CONNECT_FAILURE = 'connect';
7303 * Reading Data from Server Failed
7306 Roo.form.Action.LOAD_FAILURE = 'load';
7308 Roo.form.Action.prototype = {
7310 failureType : undefined,
7311 response : undefined,
7315 run : function(options){
7320 success : function(response){
7325 handleResponse : function(response){
7329 // default connection failure
7330 failure : function(response){
7332 this.response = response;
7333 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7334 this.form.afterAction(this, false);
7337 processResponse : function(response){
7338 this.response = response;
7339 if(!response.responseText){
7342 this.result = this.handleResponse(response);
7346 // utility functions used internally
7347 getUrl : function(appendParams){
7348 var url = this.options.url || this.form.url || this.form.el.dom.action;
7350 var p = this.getParams();
7352 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7358 getMethod : function(){
7359 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7362 getParams : function(){
7363 var bp = this.form.baseParams;
7364 var p = this.options.params;
7366 if(typeof p == "object"){
7367 p = Roo.urlEncode(Roo.applyIf(p, bp));
7368 }else if(typeof p == 'string' && bp){
7369 p += '&' + Roo.urlEncode(bp);
7372 p = Roo.urlEncode(bp);
7377 createCallback : function(){
7379 success: this.success,
7380 failure: this.failure,
7382 timeout: (this.form.timeout*1000),
7383 upload: this.form.fileUpload ? this.success : undefined
7388 Roo.form.Action.Submit = function(form, options){
7389 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7392 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7395 haveProgress : false,
7396 uploadComplete : false,
7398 // uploadProgress indicator.
7399 uploadProgress : function()
7401 if (!this.form.progressUrl) {
7405 if (!this.haveProgress) {
7406 Roo.MessageBox.progress("Uploading", "Uploading");
7408 if (this.uploadComplete) {
7409 Roo.MessageBox.hide();
7413 this.haveProgress = true;
7415 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7417 var c = new Roo.data.Connection();
7419 url : this.form.progressUrl,
7424 success : function(req){
7425 //console.log(data);
7429 rdata = Roo.decode(req.responseText)
7431 Roo.log("Invalid data from server..");
7435 if (!rdata || !rdata.success) {
7437 Roo.MessageBox.alert(Roo.encode(rdata));
7440 var data = rdata.data;
7442 if (this.uploadComplete) {
7443 Roo.MessageBox.hide();
7448 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7449 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7452 this.uploadProgress.defer(2000,this);
7455 failure: function(data) {
7456 Roo.log('progress url failed ');
7467 // run get Values on the form, so it syncs any secondary forms.
7468 this.form.getValues();
7470 var o = this.options;
7471 var method = this.getMethod();
7472 var isPost = method == 'POST';
7473 if(o.clientValidation === false || this.form.isValid()){
7475 if (this.form.progressUrl) {
7476 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7477 (new Date() * 1) + '' + Math.random());
7482 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7483 form:this.form.el.dom,
7484 url:this.getUrl(!isPost),
7486 params:isPost ? this.getParams() : null,
7487 isUpload: this.form.fileUpload
7490 this.uploadProgress();
7492 }else if (o.clientValidation !== false){ // client validation failed
7493 this.failureType = Roo.form.Action.CLIENT_INVALID;
7494 this.form.afterAction(this, false);
7498 success : function(response)
7500 this.uploadComplete= true;
7501 if (this.haveProgress) {
7502 Roo.MessageBox.hide();
7506 var result = this.processResponse(response);
7507 if(result === true || result.success){
7508 this.form.afterAction(this, true);
7512 this.form.markInvalid(result.errors);
7513 this.failureType = Roo.form.Action.SERVER_INVALID;
7515 this.form.afterAction(this, false);
7517 failure : function(response)
7519 this.uploadComplete= true;
7520 if (this.haveProgress) {
7521 Roo.MessageBox.hide();
7524 this.response = response;
7525 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7526 this.form.afterAction(this, false);
7529 handleResponse : function(response){
7530 if(this.form.errorReader){
7531 var rs = this.form.errorReader.read(response);
7534 for(var i = 0, len = rs.records.length; i < len; i++) {
7535 var r = rs.records[i];
7539 if(errors.length < 1){
7543 success : rs.success,
7549 ret = Roo.decode(response.responseText);
7553 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7563 Roo.form.Action.Load = function(form, options){
7564 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7565 this.reader = this.form.reader;
7568 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7573 Roo.Ajax.request(Roo.apply(
7574 this.createCallback(), {
7575 method:this.getMethod(),
7576 url:this.getUrl(false),
7577 params:this.getParams()
7581 success : function(response){
7583 var result = this.processResponse(response);
7584 if(result === true || !result.success || !result.data){
7585 this.failureType = Roo.form.Action.LOAD_FAILURE;
7586 this.form.afterAction(this, false);
7589 this.form.clearInvalid();
7590 this.form.setValues(result.data);
7591 this.form.afterAction(this, true);
7594 handleResponse : function(response){
7595 if(this.form.reader){
7596 var rs = this.form.reader.read(response);
7597 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7599 success : rs.success,
7603 return Roo.decode(response.responseText);
7607 Roo.form.Action.ACTION_TYPES = {
7608 'load' : Roo.form.Action.Load,
7609 'submit' : Roo.form.Action.Submit
7618 * @class Roo.bootstrap.Form
7619 * @extends Roo.bootstrap.Component
7620 * Bootstrap Form class
7621 * @cfg {String} method GET | POST (default POST)
7622 * @cfg {String} labelAlign top | left (default top)
7623 * @cfg {String} align left | right - for navbars
7624 * @cfg {Boolean} loadMask load mask when submit (default true)
7629 * @param {Object} config The config object
7633 Roo.bootstrap.Form = function(config){
7635 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7637 Roo.bootstrap.Form.popover.apply();
7641 * @event clientvalidation
7642 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7643 * @param {Form} this
7644 * @param {Boolean} valid true if the form has passed client-side validation
7646 clientvalidation: true,
7648 * @event beforeaction
7649 * Fires before any action is performed. Return false to cancel the action.
7650 * @param {Form} this
7651 * @param {Action} action The action to be performed
7655 * @event actionfailed
7656 * Fires when an action fails.
7657 * @param {Form} this
7658 * @param {Action} action The action that failed
7660 actionfailed : true,
7662 * @event actioncomplete
7663 * Fires when an action is completed.
7664 * @param {Form} this
7665 * @param {Action} action The action that completed
7667 actioncomplete : true
7671 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7674 * @cfg {String} method
7675 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7680 * The URL to use for form actions if one isn't supplied in the action options.
7683 * @cfg {Boolean} fileUpload
7684 * Set to true if this form is a file upload.
7688 * @cfg {Object} baseParams
7689 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7693 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7697 * @cfg {Sting} align (left|right) for navbar forms
7702 activeAction : null,
7705 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7706 * element by passing it or its id or mask the form itself by passing in true.
7709 waitMsgTarget : false,
7714 * @cfg {Boolean} errorMask (true|false) default false
7719 * @cfg {Number} maskOffset Default 100
7724 * @cfg {Boolean} maskBody
7728 getAutoCreate : function(){
7732 method : this.method || 'POST',
7733 id : this.id || Roo.id(),
7736 if (this.parent().xtype.match(/^Nav/)) {
7737 cfg.cls = 'navbar-form navbar-' + this.align;
7741 if (this.labelAlign == 'left' ) {
7742 cfg.cls += ' form-horizontal';
7748 initEvents : function()
7750 this.el.on('submit', this.onSubmit, this);
7751 // this was added as random key presses on the form where triggering form submit.
7752 this.el.on('keypress', function(e) {
7753 if (e.getCharCode() != 13) {
7756 // we might need to allow it for textareas.. and some other items.
7757 // check e.getTarget().
7759 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7763 Roo.log("keypress blocked");
7771 onSubmit : function(e){
7776 * Returns true if client-side validation on the form is successful.
7779 isValid : function(){
7780 var items = this.getItems();
7784 items.each(function(f){
7790 if(!target && f.el.isVisible(true)){
7796 if(this.errorMask && !valid){
7797 Roo.bootstrap.Form.popover.mask(this, target);
7804 * Returns true if any fields in this form have changed since their original load.
7807 isDirty : function(){
7809 var items = this.getItems();
7810 items.each(function(f){
7820 * Performs a predefined action (submit or load) or custom actions you define on this form.
7821 * @param {String} actionName The name of the action type
7822 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7823 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7824 * accept other config options):
7826 Property Type Description
7827 ---------------- --------------- ----------------------------------------------------------------------------------
7828 url String The url for the action (defaults to the form's url)
7829 method String The form method to use (defaults to the form's method, or POST if not defined)
7830 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7831 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7832 validate the form on the client (defaults to false)
7834 * @return {BasicForm} this
7836 doAction : function(action, options){
7837 if(typeof action == 'string'){
7838 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7840 if(this.fireEvent('beforeaction', this, action) !== false){
7841 this.beforeAction(action);
7842 action.run.defer(100, action);
7848 beforeAction : function(action){
7849 var o = action.options;
7854 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7856 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7859 // not really supported yet.. ??
7861 //if(this.waitMsgTarget === true){
7862 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7863 //}else if(this.waitMsgTarget){
7864 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7865 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7867 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7873 afterAction : function(action, success){
7874 this.activeAction = null;
7875 var o = action.options;
7880 Roo.get(document.body).unmask();
7886 //if(this.waitMsgTarget === true){
7887 // this.el.unmask();
7888 //}else if(this.waitMsgTarget){
7889 // this.waitMsgTarget.unmask();
7891 // Roo.MessageBox.updateProgress(1);
7892 // Roo.MessageBox.hide();
7899 Roo.callback(o.success, o.scope, [this, action]);
7900 this.fireEvent('actioncomplete', this, action);
7904 // failure condition..
7905 // we have a scenario where updates need confirming.
7906 // eg. if a locking scenario exists..
7907 // we look for { errors : { needs_confirm : true }} in the response.
7909 (typeof(action.result) != 'undefined') &&
7910 (typeof(action.result.errors) != 'undefined') &&
7911 (typeof(action.result.errors.needs_confirm) != 'undefined')
7914 Roo.log("not supported yet");
7917 Roo.MessageBox.confirm(
7918 "Change requires confirmation",
7919 action.result.errorMsg,
7924 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7934 Roo.callback(o.failure, o.scope, [this, action]);
7935 // show an error message if no failed handler is set..
7936 if (!this.hasListener('actionfailed')) {
7937 Roo.log("need to add dialog support");
7939 Roo.MessageBox.alert("Error",
7940 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7941 action.result.errorMsg :
7942 "Saving Failed, please check your entries or try again"
7947 this.fireEvent('actionfailed', this, action);
7952 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7953 * @param {String} id The value to search for
7956 findField : function(id){
7957 var items = this.getItems();
7958 var field = items.get(id);
7960 items.each(function(f){
7961 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7968 return field || null;
7971 * Mark fields in this form invalid in bulk.
7972 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7973 * @return {BasicForm} this
7975 markInvalid : function(errors){
7976 if(errors instanceof Array){
7977 for(var i = 0, len = errors.length; i < len; i++){
7978 var fieldError = errors[i];
7979 var f = this.findField(fieldError.id);
7981 f.markInvalid(fieldError.msg);
7987 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7988 field.markInvalid(errors[id]);
7992 //Roo.each(this.childForms || [], function (f) {
7993 // f.markInvalid(errors);
8000 * Set values for fields in this form in bulk.
8001 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8002 * @return {BasicForm} this
8004 setValues : function(values){
8005 if(values instanceof Array){ // array of objects
8006 for(var i = 0, len = values.length; i < len; i++){
8008 var f = this.findField(v.id);
8010 f.setValue(v.value);
8011 if(this.trackResetOnLoad){
8012 f.originalValue = f.getValue();
8016 }else{ // object hash
8019 if(typeof values[id] != 'function' && (field = this.findField(id))){
8021 if (field.setFromData &&
8023 field.displayField &&
8024 // combos' with local stores can
8025 // be queried via setValue()
8026 // to set their value..
8027 (field.store && !field.store.isLocal)
8031 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8032 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8033 field.setFromData(sd);
8035 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8037 field.setFromData(values);
8040 field.setValue(values[id]);
8044 if(this.trackResetOnLoad){
8045 field.originalValue = field.getValue();
8051 //Roo.each(this.childForms || [], function (f) {
8052 // f.setValues(values);
8059 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8060 * they are returned as an array.
8061 * @param {Boolean} asString
8064 getValues : function(asString){
8065 //if (this.childForms) {
8066 // copy values from the child forms
8067 // Roo.each(this.childForms, function (f) {
8068 // this.setValues(f.getValues());
8074 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8075 if(asString === true){
8078 return Roo.urlDecode(fs);
8082 * Returns the fields in this form as an object with key/value pairs.
8083 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8086 getFieldValues : function(with_hidden)
8088 var items = this.getItems();
8090 items.each(function(f){
8096 var v = f.getValue();
8098 if (f.inputType =='radio') {
8099 if (typeof(ret[f.getName()]) == 'undefined') {
8100 ret[f.getName()] = ''; // empty..
8103 if (!f.el.dom.checked) {
8111 if(f.xtype == 'MoneyField'){
8112 ret[f.currencyName] = f.getCurrency();
8115 // not sure if this supported any more..
8116 if ((typeof(v) == 'object') && f.getRawValue) {
8117 v = f.getRawValue() ; // dates..
8119 // combo boxes where name != hiddenName...
8120 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8121 ret[f.name] = f.getRawValue();
8123 ret[f.getName()] = v;
8130 * Clears all invalid messages in this form.
8131 * @return {BasicForm} this
8133 clearInvalid : function(){
8134 var items = this.getItems();
8136 items.each(function(f){
8145 * @return {BasicForm} this
8148 var items = this.getItems();
8149 items.each(function(f){
8153 Roo.each(this.childForms || [], function (f) {
8161 getItems : function()
8163 var r=new Roo.util.MixedCollection(false, function(o){
8164 return o.id || (o.id = Roo.id());
8166 var iter = function(el) {
8173 Roo.each(el.items,function(e) {
8182 hideFields : function(items)
8184 Roo.each(items, function(i){
8186 var f = this.findField(i);
8192 if(f.xtype == 'DateField'){
8193 f.setVisible(false);
8202 showFields : function(items)
8204 Roo.each(items, function(i){
8206 var f = this.findField(i);
8212 if(f.xtype == 'DateField'){
8224 Roo.apply(Roo.bootstrap.Form, {
8251 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8252 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8253 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8254 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8257 this.maskEl.top.enableDisplayMode("block");
8258 this.maskEl.left.enableDisplayMode("block");
8259 this.maskEl.bottom.enableDisplayMode("block");
8260 this.maskEl.right.enableDisplayMode("block");
8262 this.toolTip = new Roo.bootstrap.Tooltip({
8263 cls : 'roo-form-error-popover',
8265 'left' : ['r-l', [-2,0], 'right'],
8266 'right' : ['l-r', [2,0], 'left'],
8267 'bottom' : ['tl-bl', [0,2], 'top'],
8268 'top' : [ 'bl-tl', [0,-2], 'bottom']
8272 this.toolTip.render(Roo.get(document.body));
8274 this.toolTip.el.enableDisplayMode("block");
8276 Roo.get(document.body).on('click', function(){
8280 Roo.get(document.body).on('touchstart', function(){
8284 this.isApplied = true
8287 mask : function(form, target)
8291 this.target = target;
8293 if(!this.form.errorMask || !target.el){
8297 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8299 Roo.log(scrollable);
8301 var ot = this.target.el.calcOffsetsTo(scrollable);
8303 var scrollTo = ot[1] - this.form.maskOffset;
8305 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8307 scrollable.scrollTo('top', scrollTo);
8309 var box = this.target.el.getBox();
8311 var zIndex = Roo.bootstrap.Modal.zIndex++;
8314 this.maskEl.top.setStyle('position', 'absolute');
8315 this.maskEl.top.setStyle('z-index', zIndex);
8316 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8317 this.maskEl.top.setLeft(0);
8318 this.maskEl.top.setTop(0);
8319 this.maskEl.top.show();
8321 this.maskEl.left.setStyle('position', 'absolute');
8322 this.maskEl.left.setStyle('z-index', zIndex);
8323 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8324 this.maskEl.left.setLeft(0);
8325 this.maskEl.left.setTop(box.y - this.padding);
8326 this.maskEl.left.show();
8328 this.maskEl.bottom.setStyle('position', 'absolute');
8329 this.maskEl.bottom.setStyle('z-index', zIndex);
8330 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8331 this.maskEl.bottom.setLeft(0);
8332 this.maskEl.bottom.setTop(box.bottom + this.padding);
8333 this.maskEl.bottom.show();
8335 this.maskEl.right.setStyle('position', 'absolute');
8336 this.maskEl.right.setStyle('z-index', zIndex);
8337 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8338 this.maskEl.right.setLeft(box.right + this.padding);
8339 this.maskEl.right.setTop(box.y - this.padding);
8340 this.maskEl.right.show();
8342 this.toolTip.bindEl = this.target.el;
8344 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8346 var tip = this.target.blankText;
8348 if(this.target.getValue() !== '' ) {
8350 if (this.target.invalidText.length) {
8351 tip = this.target.invalidText;
8352 } else if (this.target.regexText.length){
8353 tip = this.target.regexText;
8357 this.toolTip.show(tip);
8359 this.intervalID = window.setInterval(function() {
8360 Roo.bootstrap.Form.popover.unmask();
8363 window.onwheel = function(){ return false;};
8365 (function(){ this.isMasked = true; }).defer(500, this);
8371 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8375 this.maskEl.top.setStyle('position', 'absolute');
8376 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8377 this.maskEl.top.hide();
8379 this.maskEl.left.setStyle('position', 'absolute');
8380 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8381 this.maskEl.left.hide();
8383 this.maskEl.bottom.setStyle('position', 'absolute');
8384 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8385 this.maskEl.bottom.hide();
8387 this.maskEl.right.setStyle('position', 'absolute');
8388 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8389 this.maskEl.right.hide();
8391 this.toolTip.hide();
8393 this.toolTip.el.hide();
8395 window.onwheel = function(){ return true;};
8397 if(this.intervalID){
8398 window.clearInterval(this.intervalID);
8399 this.intervalID = false;
8402 this.isMasked = false;
8412 * Ext JS Library 1.1.1
8413 * Copyright(c) 2006-2007, Ext JS, LLC.
8415 * Originally Released Under LGPL - original licence link has changed is not relivant.
8418 * <script type="text/javascript">
8421 * @class Roo.form.VTypes
8422 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8425 Roo.form.VTypes = function(){
8426 // closure these in so they are only created once.
8427 var alpha = /^[a-zA-Z_]+$/;
8428 var alphanum = /^[a-zA-Z0-9_]+$/;
8429 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8430 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8432 // All these messages and functions are configurable
8435 * The function used to validate email addresses
8436 * @param {String} value The email address
8438 'email' : function(v){
8439 return email.test(v);
8442 * The error text to display when the email validation function returns false
8445 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8447 * The keystroke filter mask to be applied on email input
8450 'emailMask' : /[a-z0-9_\.\-@]/i,
8453 * The function used to validate URLs
8454 * @param {String} value The URL
8456 'url' : function(v){
8460 * The error text to display when the url validation function returns false
8463 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8466 * The function used to validate alpha values
8467 * @param {String} value The value
8469 'alpha' : function(v){
8470 return alpha.test(v);
8473 * The error text to display when the alpha validation function returns false
8476 'alphaText' : 'This field should only contain letters and _',
8478 * The keystroke filter mask to be applied on alpha input
8481 'alphaMask' : /[a-z_]/i,
8484 * The function used to validate alphanumeric values
8485 * @param {String} value The value
8487 'alphanum' : function(v){
8488 return alphanum.test(v);
8491 * The error text to display when the alphanumeric validation function returns false
8494 'alphanumText' : 'This field should only contain letters, numbers and _',
8496 * The keystroke filter mask to be applied on alphanumeric input
8499 'alphanumMask' : /[a-z0-9_]/i
8509 * @class Roo.bootstrap.Input
8510 * @extends Roo.bootstrap.Component
8511 * Bootstrap Input class
8512 * @cfg {Boolean} disabled is it disabled
8513 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8514 * @cfg {String} name name of the input
8515 * @cfg {string} fieldLabel - the label associated
8516 * @cfg {string} placeholder - placeholder to put in text.
8517 * @cfg {string} before - input group add on before
8518 * @cfg {string} after - input group add on after
8519 * @cfg {string} size - (lg|sm) or leave empty..
8520 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8521 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8522 * @cfg {Number} md colspan out of 12 for computer-sized screens
8523 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8524 * @cfg {string} value default value of the input
8525 * @cfg {Number} labelWidth set the width of label
8526 * @cfg {Number} labellg set the width of label (1-12)
8527 * @cfg {Number} labelmd set the width of label (1-12)
8528 * @cfg {Number} labelsm set the width of label (1-12)
8529 * @cfg {Number} labelxs set the width of label (1-12)
8530 * @cfg {String} labelAlign (top|left)
8531 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8532 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8533 * @cfg {String} indicatorpos (left|right) default left
8535 * @cfg {String} align (left|center|right) Default left
8536 * @cfg {Boolean} forceFeedback (true|false) Default false
8539 * Create a new Input
8540 * @param {Object} config The config object
8543 Roo.bootstrap.Input = function(config){
8545 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8550 * Fires when this field receives input focus.
8551 * @param {Roo.form.Field} this
8556 * Fires when this field loses input focus.
8557 * @param {Roo.form.Field} this
8562 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8563 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8564 * @param {Roo.form.Field} this
8565 * @param {Roo.EventObject} e The event object
8570 * Fires just before the field blurs if the field value has changed.
8571 * @param {Roo.form.Field} this
8572 * @param {Mixed} newValue The new value
8573 * @param {Mixed} oldValue The original value
8578 * Fires after the field has been marked as invalid.
8579 * @param {Roo.form.Field} this
8580 * @param {String} msg The validation message
8585 * Fires after the field has been validated with no errors.
8586 * @param {Roo.form.Field} this
8591 * Fires after the key up
8592 * @param {Roo.form.Field} this
8593 * @param {Roo.EventObject} e The event Object
8599 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8601 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8602 automatic validation (defaults to "keyup").
8604 validationEvent : "keyup",
8606 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8608 validateOnBlur : true,
8610 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8612 validationDelay : 250,
8614 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8616 focusClass : "x-form-focus", // not needed???
8620 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8622 invalidClass : "has-warning",
8625 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8627 validClass : "has-success",
8630 * @cfg {Boolean} hasFeedback (true|false) default true
8635 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8637 invalidFeedbackClass : "glyphicon-warning-sign",
8640 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8642 validFeedbackClass : "glyphicon-ok",
8645 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8647 selectOnFocus : false,
8650 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8654 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8659 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8661 disableKeyFilter : false,
8664 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8668 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8672 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8674 blankText : "Please complete this mandatory field",
8677 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8681 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8683 maxLength : Number.MAX_VALUE,
8685 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8687 minLengthText : "The minimum length for this field is {0}",
8689 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8691 maxLengthText : "The maximum length for this field is {0}",
8695 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8696 * If available, this function will be called only after the basic validators all return true, and will be passed the
8697 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8701 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8702 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8703 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8707 * @cfg {String} regexText -- Depricated - use Invalid Text
8712 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8718 autocomplete: false,
8737 formatedValue : false,
8738 forceFeedback : false,
8740 indicatorpos : 'left',
8747 parentLabelAlign : function()
8750 while (parent.parent()) {
8751 parent = parent.parent();
8752 if (typeof(parent.labelAlign) !='undefined') {
8753 return parent.labelAlign;
8760 getAutoCreate : function()
8762 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8768 if(this.inputType != 'hidden'){
8769 cfg.cls = 'form-group' //input-group
8775 type : this.inputType,
8777 cls : 'form-control',
8778 placeholder : this.placeholder || '',
8779 autocomplete : this.autocomplete || 'new-password'
8783 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8786 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8787 input.maxLength = this.maxLength;
8790 if (this.disabled) {
8791 input.disabled=true;
8794 if (this.readOnly) {
8795 input.readonly=true;
8799 input.name = this.name;
8803 input.cls += ' input-' + this.size;
8807 ['xs','sm','md','lg'].map(function(size){
8808 if (settings[size]) {
8809 cfg.cls += ' col-' + size + '-' + settings[size];
8813 var inputblock = input;
8817 cls: 'glyphicon form-control-feedback'
8820 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8823 cls : 'has-feedback',
8831 if (this.before || this.after) {
8834 cls : 'input-group',
8838 if (this.before && typeof(this.before) == 'string') {
8840 inputblock.cn.push({
8842 cls : 'roo-input-before input-group-addon',
8846 if (this.before && typeof(this.before) == 'object') {
8847 this.before = Roo.factory(this.before);
8849 inputblock.cn.push({
8851 cls : 'roo-input-before input-group-' +
8852 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8856 inputblock.cn.push(input);
8858 if (this.after && typeof(this.after) == 'string') {
8859 inputblock.cn.push({
8861 cls : 'roo-input-after input-group-addon',
8865 if (this.after && typeof(this.after) == 'object') {
8866 this.after = Roo.factory(this.after);
8868 inputblock.cn.push({
8870 cls : 'roo-input-after input-group-' +
8871 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8875 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8876 inputblock.cls += ' has-feedback';
8877 inputblock.cn.push(feedback);
8881 if (align ==='left' && this.fieldLabel.length) {
8883 cfg.cls += ' roo-form-group-label-left';
8888 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8889 tooltip : 'This field is required'
8894 cls : 'control-label',
8895 html : this.fieldLabel
8906 var labelCfg = cfg.cn[1];
8907 var contentCfg = cfg.cn[2];
8909 if(this.indicatorpos == 'right'){
8914 cls : 'control-label',
8918 html : this.fieldLabel
8922 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8923 tooltip : 'This field is required'
8936 labelCfg = cfg.cn[0];
8937 contentCfg = cfg.cn[1];
8941 if(this.labelWidth > 12){
8942 labelCfg.style = "width: " + this.labelWidth + 'px';
8945 if(this.labelWidth < 13 && this.labelmd == 0){
8946 this.labelmd = this.labelWidth;
8949 if(this.labellg > 0){
8950 labelCfg.cls += ' col-lg-' + this.labellg;
8951 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8954 if(this.labelmd > 0){
8955 labelCfg.cls += ' col-md-' + this.labelmd;
8956 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8959 if(this.labelsm > 0){
8960 labelCfg.cls += ' col-sm-' + this.labelsm;
8961 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8964 if(this.labelxs > 0){
8965 labelCfg.cls += ' col-xs-' + this.labelxs;
8966 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8970 } else if ( this.fieldLabel.length) {
8975 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8976 tooltip : 'This field is required'
8980 //cls : 'input-group-addon',
8981 html : this.fieldLabel
8989 if(this.indicatorpos == 'right'){
8994 //cls : 'input-group-addon',
8995 html : this.fieldLabel
9000 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9001 tooltip : 'This field is required'
9021 if (this.parentType === 'Navbar' && this.parent().bar) {
9022 cfg.cls += ' navbar-form';
9025 if (this.parentType === 'NavGroup') {
9026 cfg.cls += ' navbar-form';
9034 * return the real input element.
9036 inputEl: function ()
9038 return this.el.select('input.form-control',true).first();
9041 tooltipEl : function()
9043 return this.inputEl();
9046 indicatorEl : function()
9048 var indicator = this.el.select('i.roo-required-indicator',true).first();
9058 setDisabled : function(v)
9060 var i = this.inputEl().dom;
9062 i.removeAttribute('disabled');
9066 i.setAttribute('disabled','true');
9068 initEvents : function()
9071 this.inputEl().on("keydown" , this.fireKey, this);
9072 this.inputEl().on("focus", this.onFocus, this);
9073 this.inputEl().on("blur", this.onBlur, this);
9075 this.inputEl().relayEvent('keyup', this);
9077 this.indicator = this.indicatorEl();
9080 this.indicator.addClass('invisible');
9084 // reference to original value for reset
9085 this.originalValue = this.getValue();
9086 //Roo.form.TextField.superclass.initEvents.call(this);
9087 if(this.validationEvent == 'keyup'){
9088 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9089 this.inputEl().on('keyup', this.filterValidation, this);
9091 else if(this.validationEvent !== false){
9092 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9095 if(this.selectOnFocus){
9096 this.on("focus", this.preFocus, this);
9099 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9100 this.inputEl().on("keypress", this.filterKeys, this);
9102 this.inputEl().relayEvent('keypress', this);
9105 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9106 this.el.on("click", this.autoSize, this);
9109 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9110 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9113 if (typeof(this.before) == 'object') {
9114 this.before.render(this.el.select('.roo-input-before',true).first());
9116 if (typeof(this.after) == 'object') {
9117 this.after.render(this.el.select('.roo-input-after',true).first());
9122 filterValidation : function(e){
9123 if(!e.isNavKeyPress()){
9124 this.validationTask.delay(this.validationDelay);
9128 * Validates the field value
9129 * @return {Boolean} True if the value is valid, else false
9131 validate : function(){
9132 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9133 if(this.disabled || this.validateValue(this.getRawValue())){
9144 * Validates a value according to the field's validation rules and marks the field as invalid
9145 * if the validation fails
9146 * @param {Mixed} value The value to validate
9147 * @return {Boolean} True if the value is valid, else false
9149 validateValue : function(value)
9151 if(this.getVisibilityEl().hasClass('hidden')){
9155 if(value.length < 1) { // if it's blank
9156 if(this.allowBlank){
9162 if(value.length < this.minLength){
9165 if(value.length > this.maxLength){
9169 var vt = Roo.form.VTypes;
9170 if(!vt[this.vtype](value, this)){
9174 if(typeof this.validator == "function"){
9175 var msg = this.validator(value);
9179 if (typeof(msg) == 'string') {
9180 this.invalidText = msg;
9184 if(this.regex && !this.regex.test(value)){
9192 fireKey : function(e){
9193 //Roo.log('field ' + e.getKey());
9194 if(e.isNavKeyPress()){
9195 this.fireEvent("specialkey", this, e);
9198 focus : function (selectText){
9200 this.inputEl().focus();
9201 if(selectText === true){
9202 this.inputEl().dom.select();
9208 onFocus : function(){
9209 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9210 // this.el.addClass(this.focusClass);
9213 this.hasFocus = true;
9214 this.startValue = this.getValue();
9215 this.fireEvent("focus", this);
9219 beforeBlur : Roo.emptyFn,
9223 onBlur : function(){
9225 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9226 //this.el.removeClass(this.focusClass);
9228 this.hasFocus = false;
9229 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9232 var v = this.getValue();
9233 if(String(v) !== String(this.startValue)){
9234 this.fireEvent('change', this, v, this.startValue);
9236 this.fireEvent("blur", this);
9240 * Resets the current field value to the originally loaded value and clears any validation messages
9243 this.setValue(this.originalValue);
9247 * Returns the name of the field
9248 * @return {Mixed} name The name field
9250 getName: function(){
9254 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9255 * @return {Mixed} value The field value
9257 getValue : function(){
9259 var v = this.inputEl().getValue();
9264 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9265 * @return {Mixed} value The field value
9267 getRawValue : function(){
9268 var v = this.inputEl().getValue();
9274 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9275 * @param {Mixed} value The value to set
9277 setRawValue : function(v){
9278 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9281 selectText : function(start, end){
9282 var v = this.getRawValue();
9284 start = start === undefined ? 0 : start;
9285 end = end === undefined ? v.length : end;
9286 var d = this.inputEl().dom;
9287 if(d.setSelectionRange){
9288 d.setSelectionRange(start, end);
9289 }else if(d.createTextRange){
9290 var range = d.createTextRange();
9291 range.moveStart("character", start);
9292 range.moveEnd("character", v.length-end);
9299 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9300 * @param {Mixed} value The value to set
9302 setValue : function(v){
9305 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9311 processValue : function(value){
9312 if(this.stripCharsRe){
9313 var newValue = value.replace(this.stripCharsRe, '');
9314 if(newValue !== value){
9315 this.setRawValue(newValue);
9322 preFocus : function(){
9324 if(this.selectOnFocus){
9325 this.inputEl().dom.select();
9328 filterKeys : function(e){
9330 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9333 var c = e.getCharCode(), cc = String.fromCharCode(c);
9334 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9337 if(!this.maskRe.test(cc)){
9342 * Clear any invalid styles/messages for this field
9344 clearInvalid : function(){
9346 if(!this.el || this.preventMark){ // not rendered
9351 this.el.removeClass(this.invalidClass);
9353 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9355 var feedback = this.el.select('.form-control-feedback', true).first();
9358 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9363 this.fireEvent('valid', this);
9367 * Mark this field as valid
9369 markValid : function()
9371 if(!this.el || this.preventMark){ // not rendered...
9375 this.el.removeClass([this.invalidClass, this.validClass]);
9377 var feedback = this.el.select('.form-control-feedback', true).first();
9380 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9384 this.indicator.removeClass('visible');
9385 this.indicator.addClass('invisible');
9392 if(this.allowBlank && !this.getRawValue().length){
9396 this.el.addClass(this.validClass);
9398 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9400 var feedback = this.el.select('.form-control-feedback', true).first();
9403 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9404 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9409 this.fireEvent('valid', this);
9413 * Mark this field as invalid
9414 * @param {String} msg The validation message
9416 markInvalid : function(msg)
9418 if(!this.el || this.preventMark){ // not rendered
9422 this.el.removeClass([this.invalidClass, this.validClass]);
9424 var feedback = this.el.select('.form-control-feedback', true).first();
9427 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9434 if(this.allowBlank && !this.getRawValue().length){
9439 this.indicator.removeClass('invisible');
9440 this.indicator.addClass('visible');
9443 this.el.addClass(this.invalidClass);
9445 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9447 var feedback = this.el.select('.form-control-feedback', true).first();
9450 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9452 if(this.getValue().length || this.forceFeedback){
9453 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9460 this.fireEvent('invalid', this, msg);
9463 SafariOnKeyDown : function(event)
9465 // this is a workaround for a password hang bug on chrome/ webkit.
9466 if (this.inputEl().dom.type != 'password') {
9470 var isSelectAll = false;
9472 if(this.inputEl().dom.selectionEnd > 0){
9473 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9475 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9476 event.preventDefault();
9481 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9483 event.preventDefault();
9484 // this is very hacky as keydown always get's upper case.
9486 var cc = String.fromCharCode(event.getCharCode());
9487 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9491 adjustWidth : function(tag, w){
9492 tag = tag.toLowerCase();
9493 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9494 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9498 if(tag == 'textarea'){
9501 }else if(Roo.isOpera){
9505 if(tag == 'textarea'){
9513 setFieldLabel : function(v)
9520 var ar = this.el.select('label > span',true);
9522 if (ar.elements.length) {
9523 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9524 this.fieldLabel = v;
9528 var br = this.el.select('label',true);
9530 if(br.elements.length) {
9531 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9532 this.fieldLabel = v;
9536 Roo.log('Cannot Found any of label > span || label in input');
9540 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9541 this.fieldLabel = v;
9556 * @class Roo.bootstrap.TextArea
9557 * @extends Roo.bootstrap.Input
9558 * Bootstrap TextArea class
9559 * @cfg {Number} cols Specifies the visible width of a text area
9560 * @cfg {Number} rows Specifies the visible number of lines in a text area
9561 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9562 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9563 * @cfg {string} html text
9566 * Create a new TextArea
9567 * @param {Object} config The config object
9570 Roo.bootstrap.TextArea = function(config){
9571 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9575 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9585 getAutoCreate : function(){
9587 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9593 if(this.inputType != 'hidden'){
9594 cfg.cls = 'form-group' //input-group
9602 value : this.value || '',
9603 html: this.html || '',
9604 cls : 'form-control',
9605 placeholder : this.placeholder || ''
9609 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9610 input.maxLength = this.maxLength;
9614 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9618 input.cols = this.cols;
9621 if (this.readOnly) {
9622 input.readonly = true;
9626 input.name = this.name;
9630 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9634 ['xs','sm','md','lg'].map(function(size){
9635 if (settings[size]) {
9636 cfg.cls += ' col-' + size + '-' + settings[size];
9640 var inputblock = input;
9642 if(this.hasFeedback && !this.allowBlank){
9646 cls: 'glyphicon form-control-feedback'
9650 cls : 'has-feedback',
9659 if (this.before || this.after) {
9662 cls : 'input-group',
9666 inputblock.cn.push({
9668 cls : 'input-group-addon',
9673 inputblock.cn.push(input);
9675 if(this.hasFeedback && !this.allowBlank){
9676 inputblock.cls += ' has-feedback';
9677 inputblock.cn.push(feedback);
9681 inputblock.cn.push({
9683 cls : 'input-group-addon',
9690 if (align ==='left' && this.fieldLabel.length) {
9695 cls : 'control-label',
9696 html : this.fieldLabel
9707 if(this.labelWidth > 12){
9708 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9711 if(this.labelWidth < 13 && this.labelmd == 0){
9712 this.labelmd = this.labelWidth;
9715 if(this.labellg > 0){
9716 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9717 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9720 if(this.labelmd > 0){
9721 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9722 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9725 if(this.labelsm > 0){
9726 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9727 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9730 if(this.labelxs > 0){
9731 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9732 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9735 } else if ( this.fieldLabel.length) {
9740 //cls : 'input-group-addon',
9741 html : this.fieldLabel
9759 if (this.disabled) {
9760 input.disabled=true;
9767 * return the real textarea element.
9769 inputEl: function ()
9771 return this.el.select('textarea.form-control',true).first();
9775 * Clear any invalid styles/messages for this field
9777 clearInvalid : function()
9780 if(!this.el || this.preventMark){ // not rendered
9784 var label = this.el.select('label', true).first();
9785 var icon = this.el.select('i.fa-star', true).first();
9791 this.el.removeClass(this.invalidClass);
9793 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9795 var feedback = this.el.select('.form-control-feedback', true).first();
9798 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9803 this.fireEvent('valid', this);
9807 * Mark this field as valid
9809 markValid : function()
9811 if(!this.el || this.preventMark){ // not rendered
9815 this.el.removeClass([this.invalidClass, this.validClass]);
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]);
9823 if(this.disabled || this.allowBlank){
9827 var label = this.el.select('label', true).first();
9828 var icon = this.el.select('i.fa-star', true).first();
9834 this.el.addClass(this.validClass);
9836 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9838 var feedback = this.el.select('.form-control-feedback', true).first();
9841 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9842 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9847 this.fireEvent('valid', this);
9851 * Mark this field as invalid
9852 * @param {String} msg The validation message
9854 markInvalid : function(msg)
9856 if(!this.el || this.preventMark){ // not rendered
9860 this.el.removeClass([this.invalidClass, this.validClass]);
9862 var feedback = this.el.select('.form-control-feedback', true).first();
9865 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9868 if(this.disabled || this.allowBlank){
9872 var label = this.el.select('label', true).first();
9873 var icon = this.el.select('i.fa-star', true).first();
9875 if(!this.getValue().length && label && !icon){
9876 this.el.createChild({
9878 cls : 'text-danger fa fa-lg fa-star',
9879 tooltip : 'This field is required',
9880 style : 'margin-right:5px;'
9884 this.el.addClass(this.invalidClass);
9886 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9888 var feedback = this.el.select('.form-control-feedback', true).first();
9891 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9893 if(this.getValue().length || this.forceFeedback){
9894 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9901 this.fireEvent('invalid', this, msg);
9909 * trigger field - base class for combo..
9914 * @class Roo.bootstrap.TriggerField
9915 * @extends Roo.bootstrap.Input
9916 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9917 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9918 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9919 * for which you can provide a custom implementation. For example:
9921 var trigger = new Roo.bootstrap.TriggerField();
9922 trigger.onTriggerClick = myTriggerFn;
9923 trigger.applyTo('my-field');
9926 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9927 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9928 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9929 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9930 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9933 * Create a new TriggerField.
9934 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9935 * to the base TextField)
9937 Roo.bootstrap.TriggerField = function(config){
9938 this.mimicing = false;
9939 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9942 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9944 * @cfg {String} triggerClass A CSS class to apply to the trigger
9947 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9952 * @cfg {Boolean} removable (true|false) special filter default false
9956 /** @cfg {Boolean} grow @hide */
9957 /** @cfg {Number} growMin @hide */
9958 /** @cfg {Number} growMax @hide */
9964 autoSize: Roo.emptyFn,
9971 actionMode : 'wrap',
9976 getAutoCreate : function(){
9978 var align = this.labelAlign || this.parentLabelAlign();
9983 cls: 'form-group' //input-group
9990 type : this.inputType,
9991 cls : 'form-control',
9992 autocomplete: 'new-password',
9993 placeholder : this.placeholder || ''
9997 input.name = this.name;
10000 input.cls += ' input-' + this.size;
10003 if (this.disabled) {
10004 input.disabled=true;
10007 var inputblock = input;
10009 if(this.hasFeedback && !this.allowBlank){
10013 cls: 'glyphicon form-control-feedback'
10016 if(this.removable && !this.editable && !this.tickable){
10018 cls : 'has-feedback',
10024 cls : 'roo-combo-removable-btn close'
10031 cls : 'has-feedback',
10040 if(this.removable && !this.editable && !this.tickable){
10042 cls : 'roo-removable',
10048 cls : 'roo-combo-removable-btn close'
10055 if (this.before || this.after) {
10058 cls : 'input-group',
10062 inputblock.cn.push({
10064 cls : 'input-group-addon',
10069 inputblock.cn.push(input);
10071 if(this.hasFeedback && !this.allowBlank){
10072 inputblock.cls += ' has-feedback';
10073 inputblock.cn.push(feedback);
10077 inputblock.cn.push({
10079 cls : 'input-group-addon',
10092 cls: 'form-hidden-field'
10106 cls: 'form-hidden-field'
10110 cls: 'roo-select2-choices',
10114 cls: 'roo-select2-search-field',
10127 cls: 'roo-select2-container input-group',
10132 // cls: 'typeahead typeahead-long dropdown-menu',
10133 // style: 'display:none'
10138 if(!this.multiple && this.showToggleBtn){
10144 if (this.caret != false) {
10147 cls: 'fa fa-' + this.caret
10154 cls : 'input-group-addon btn dropdown-toggle',
10159 cls: 'combobox-clear',
10173 combobox.cls += ' roo-select2-container-multi';
10176 if (align ==='left' && this.fieldLabel.length) {
10178 cfg.cls += ' roo-form-group-label-left';
10183 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10184 tooltip : 'This field is required'
10189 cls : 'control-label',
10190 html : this.fieldLabel
10202 var labelCfg = cfg.cn[1];
10203 var contentCfg = cfg.cn[2];
10205 if(this.indicatorpos == 'right'){
10210 cls : 'control-label',
10214 html : this.fieldLabel
10218 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10219 tooltip : 'This field is required'
10232 labelCfg = cfg.cn[0];
10233 contentCfg = cfg.cn[1];
10236 if(this.labelWidth > 12){
10237 labelCfg.style = "width: " + this.labelWidth + 'px';
10240 if(this.labelWidth < 13 && this.labelmd == 0){
10241 this.labelmd = this.labelWidth;
10244 if(this.labellg > 0){
10245 labelCfg.cls += ' col-lg-' + this.labellg;
10246 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10249 if(this.labelmd > 0){
10250 labelCfg.cls += ' col-md-' + this.labelmd;
10251 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10254 if(this.labelsm > 0){
10255 labelCfg.cls += ' col-sm-' + this.labelsm;
10256 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10259 if(this.labelxs > 0){
10260 labelCfg.cls += ' col-xs-' + this.labelxs;
10261 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10264 } else if ( this.fieldLabel.length) {
10265 // Roo.log(" label");
10269 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10270 tooltip : 'This field is required'
10274 //cls : 'input-group-addon',
10275 html : this.fieldLabel
10283 if(this.indicatorpos == 'right'){
10291 html : this.fieldLabel
10295 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10296 tooltip : 'This field is required'
10309 // Roo.log(" no label && no align");
10316 ['xs','sm','md','lg'].map(function(size){
10317 if (settings[size]) {
10318 cfg.cls += ' col-' + size + '-' + settings[size];
10329 onResize : function(w, h){
10330 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10331 // if(typeof w == 'number'){
10332 // var x = w - this.trigger.getWidth();
10333 // this.inputEl().setWidth(this.adjustWidth('input', x));
10334 // this.trigger.setStyle('left', x+'px');
10339 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10342 getResizeEl : function(){
10343 return this.inputEl();
10347 getPositionEl : function(){
10348 return this.inputEl();
10352 alignErrorIcon : function(){
10353 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10357 initEvents : function(){
10361 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10362 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10363 if(!this.multiple && this.showToggleBtn){
10364 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10365 if(this.hideTrigger){
10366 this.trigger.setDisplayed(false);
10368 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10372 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10375 if(this.removable && !this.editable && !this.tickable){
10376 var close = this.closeTriggerEl();
10379 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10380 close.on('click', this.removeBtnClick, this, close);
10384 //this.trigger.addClassOnOver('x-form-trigger-over');
10385 //this.trigger.addClassOnClick('x-form-trigger-click');
10388 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10392 closeTriggerEl : function()
10394 var close = this.el.select('.roo-combo-removable-btn', true).first();
10395 return close ? close : false;
10398 removeBtnClick : function(e, h, el)
10400 e.preventDefault();
10402 if(this.fireEvent("remove", this) !== false){
10404 this.fireEvent("afterremove", this)
10408 createList : function()
10410 this.list = Roo.get(document.body).createChild({
10412 cls: 'typeahead typeahead-long dropdown-menu',
10413 style: 'display:none'
10416 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10421 initTrigger : function(){
10426 onDestroy : function(){
10428 this.trigger.removeAllListeners();
10429 // this.trigger.remove();
10432 // this.wrap.remove();
10434 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10438 onFocus : function(){
10439 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10441 if(!this.mimicing){
10442 this.wrap.addClass('x-trigger-wrap-focus');
10443 this.mimicing = true;
10444 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10445 if(this.monitorTab){
10446 this.el.on("keydown", this.checkTab, this);
10453 checkTab : function(e){
10454 if(e.getKey() == e.TAB){
10455 this.triggerBlur();
10460 onBlur : function(){
10465 mimicBlur : function(e, t){
10467 if(!this.wrap.contains(t) && this.validateBlur()){
10468 this.triggerBlur();
10474 triggerBlur : function(){
10475 this.mimicing = false;
10476 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10477 if(this.monitorTab){
10478 this.el.un("keydown", this.checkTab, this);
10480 //this.wrap.removeClass('x-trigger-wrap-focus');
10481 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10485 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10486 validateBlur : function(e, t){
10491 onDisable : function(){
10492 this.inputEl().dom.disabled = true;
10493 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10495 // this.wrap.addClass('x-item-disabled');
10500 onEnable : function(){
10501 this.inputEl().dom.disabled = false;
10502 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10504 // this.el.removeClass('x-item-disabled');
10509 onShow : function(){
10510 var ae = this.getActionEl();
10513 ae.dom.style.display = '';
10514 ae.dom.style.visibility = 'visible';
10520 onHide : function(){
10521 var ae = this.getActionEl();
10522 ae.dom.style.display = 'none';
10526 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10527 * by an implementing function.
10529 * @param {EventObject} e
10531 onTriggerClick : Roo.emptyFn
10535 * Ext JS Library 1.1.1
10536 * Copyright(c) 2006-2007, Ext JS, LLC.
10538 * Originally Released Under LGPL - original licence link has changed is not relivant.
10541 * <script type="text/javascript">
10546 * @class Roo.data.SortTypes
10548 * Defines the default sorting (casting?) comparison functions used when sorting data.
10550 Roo.data.SortTypes = {
10552 * Default sort that does nothing
10553 * @param {Mixed} s The value being converted
10554 * @return {Mixed} The comparison value
10556 none : function(s){
10561 * The regular expression used to strip tags
10565 stripTagsRE : /<\/?[^>]+>/gi,
10568 * Strips all HTML tags to sort on text only
10569 * @param {Mixed} s The value being converted
10570 * @return {String} The comparison value
10572 asText : function(s){
10573 return String(s).replace(this.stripTagsRE, "");
10577 * Strips all HTML tags to sort on text only - Case insensitive
10578 * @param {Mixed} s The value being converted
10579 * @return {String} The comparison value
10581 asUCText : function(s){
10582 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10586 * Case insensitive string
10587 * @param {Mixed} s The value being converted
10588 * @return {String} The comparison value
10590 asUCString : function(s) {
10591 return String(s).toUpperCase();
10596 * @param {Mixed} s The value being converted
10597 * @return {Number} The comparison value
10599 asDate : function(s) {
10603 if(s instanceof Date){
10604 return s.getTime();
10606 return Date.parse(String(s));
10611 * @param {Mixed} s The value being converted
10612 * @return {Float} The comparison value
10614 asFloat : function(s) {
10615 var val = parseFloat(String(s).replace(/,/g, ""));
10624 * @param {Mixed} s The value being converted
10625 * @return {Number} The comparison value
10627 asInt : function(s) {
10628 var val = parseInt(String(s).replace(/,/g, ""));
10636 * Ext JS Library 1.1.1
10637 * Copyright(c) 2006-2007, Ext JS, LLC.
10639 * Originally Released Under LGPL - original licence link has changed is not relivant.
10642 * <script type="text/javascript">
10646 * @class Roo.data.Record
10647 * Instances of this class encapsulate both record <em>definition</em> information, and record
10648 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10649 * to access Records cached in an {@link Roo.data.Store} object.<br>
10651 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10652 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10655 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10657 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10658 * {@link #create}. The parameters are the same.
10659 * @param {Array} data An associative Array of data values keyed by the field name.
10660 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10661 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10662 * not specified an integer id is generated.
10664 Roo.data.Record = function(data, id){
10665 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10670 * Generate a constructor for a specific record layout.
10671 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10672 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10673 * Each field definition object may contain the following properties: <ul>
10674 * <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,
10675 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10676 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10677 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10678 * is being used, then this is a string containing the javascript expression to reference the data relative to
10679 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10680 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10681 * this may be omitted.</p></li>
10682 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10683 * <ul><li>auto (Default, implies no conversion)</li>
10688 * <li>date</li></ul></p></li>
10689 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10690 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10691 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10692 * by the Reader into an object that will be stored in the Record. It is passed the
10693 * following parameters:<ul>
10694 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10696 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10698 * <br>usage:<br><pre><code>
10699 var TopicRecord = Roo.data.Record.create(
10700 {name: 'title', mapping: 'topic_title'},
10701 {name: 'author', mapping: 'username'},
10702 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10703 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10704 {name: 'lastPoster', mapping: 'user2'},
10705 {name: 'excerpt', mapping: 'post_text'}
10708 var myNewRecord = new TopicRecord({
10709 title: 'Do my job please',
10712 lastPost: new Date(),
10713 lastPoster: 'Animal',
10714 excerpt: 'No way dude!'
10716 myStore.add(myNewRecord);
10721 Roo.data.Record.create = function(o){
10722 var f = function(){
10723 f.superclass.constructor.apply(this, arguments);
10725 Roo.extend(f, Roo.data.Record);
10726 var p = f.prototype;
10727 p.fields = new Roo.util.MixedCollection(false, function(field){
10730 for(var i = 0, len = o.length; i < len; i++){
10731 p.fields.add(new Roo.data.Field(o[i]));
10733 f.getField = function(name){
10734 return p.fields.get(name);
10739 Roo.data.Record.AUTO_ID = 1000;
10740 Roo.data.Record.EDIT = 'edit';
10741 Roo.data.Record.REJECT = 'reject';
10742 Roo.data.Record.COMMIT = 'commit';
10744 Roo.data.Record.prototype = {
10746 * Readonly flag - true if this record has been modified.
10755 join : function(store){
10756 this.store = store;
10760 * Set the named field to the specified value.
10761 * @param {String} name The name of the field to set.
10762 * @param {Object} value The value to set the field to.
10764 set : function(name, value){
10765 if(this.data[name] == value){
10769 if(!this.modified){
10770 this.modified = {};
10772 if(typeof this.modified[name] == 'undefined'){
10773 this.modified[name] = this.data[name];
10775 this.data[name] = value;
10776 if(!this.editing && this.store){
10777 this.store.afterEdit(this);
10782 * Get the value of the named field.
10783 * @param {String} name The name of the field to get the value of.
10784 * @return {Object} The value of the field.
10786 get : function(name){
10787 return this.data[name];
10791 beginEdit : function(){
10792 this.editing = true;
10793 this.modified = {};
10797 cancelEdit : function(){
10798 this.editing = false;
10799 delete this.modified;
10803 endEdit : function(){
10804 this.editing = false;
10805 if(this.dirty && this.store){
10806 this.store.afterEdit(this);
10811 * Usually called by the {@link Roo.data.Store} which owns the Record.
10812 * Rejects all changes made to the Record since either creation, or the last commit operation.
10813 * Modified fields are reverted to their original values.
10815 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10816 * of reject operations.
10818 reject : function(){
10819 var m = this.modified;
10821 if(typeof m[n] != "function"){
10822 this.data[n] = m[n];
10825 this.dirty = false;
10826 delete this.modified;
10827 this.editing = false;
10829 this.store.afterReject(this);
10834 * Usually called by the {@link Roo.data.Store} which owns the Record.
10835 * Commits all changes made to the Record since either creation, or the last commit operation.
10837 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10838 * of commit operations.
10840 commit : function(){
10841 this.dirty = false;
10842 delete this.modified;
10843 this.editing = false;
10845 this.store.afterCommit(this);
10850 hasError : function(){
10851 return this.error != null;
10855 clearError : function(){
10860 * Creates a copy of this record.
10861 * @param {String} id (optional) A new record id if you don't want to use this record's id
10864 copy : function(newId) {
10865 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10869 * Ext JS Library 1.1.1
10870 * Copyright(c) 2006-2007, Ext JS, LLC.
10872 * Originally Released Under LGPL - original licence link has changed is not relivant.
10875 * <script type="text/javascript">
10881 * @class Roo.data.Store
10882 * @extends Roo.util.Observable
10883 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10884 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10886 * 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
10887 * has no knowledge of the format of the data returned by the Proxy.<br>
10889 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10890 * instances from the data object. These records are cached and made available through accessor functions.
10892 * Creates a new Store.
10893 * @param {Object} config A config object containing the objects needed for the Store to access data,
10894 * and read the data into Records.
10896 Roo.data.Store = function(config){
10897 this.data = new Roo.util.MixedCollection(false);
10898 this.data.getKey = function(o){
10901 this.baseParams = {};
10903 this.paramNames = {
10908 "multisort" : "_multisort"
10911 if(config && config.data){
10912 this.inlineData = config.data;
10913 delete config.data;
10916 Roo.apply(this, config);
10918 if(this.reader){ // reader passed
10919 this.reader = Roo.factory(this.reader, Roo.data);
10920 this.reader.xmodule = this.xmodule || false;
10921 if(!this.recordType){
10922 this.recordType = this.reader.recordType;
10924 if(this.reader.onMetaChange){
10925 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10929 if(this.recordType){
10930 this.fields = this.recordType.prototype.fields;
10932 this.modified = [];
10936 * @event datachanged
10937 * Fires when the data cache has changed, and a widget which is using this Store
10938 * as a Record cache should refresh its view.
10939 * @param {Store} this
10941 datachanged : true,
10943 * @event metachange
10944 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10945 * @param {Store} this
10946 * @param {Object} meta The JSON metadata
10951 * Fires when Records have been added to the Store
10952 * @param {Store} this
10953 * @param {Roo.data.Record[]} records The array of Records added
10954 * @param {Number} index The index at which the record(s) were added
10959 * Fires when a Record has been removed from the Store
10960 * @param {Store} this
10961 * @param {Roo.data.Record} record The Record that was removed
10962 * @param {Number} index The index at which the record was removed
10967 * Fires when a Record has been updated
10968 * @param {Store} this
10969 * @param {Roo.data.Record} record The Record that was updated
10970 * @param {String} operation The update operation being performed. Value may be one of:
10972 Roo.data.Record.EDIT
10973 Roo.data.Record.REJECT
10974 Roo.data.Record.COMMIT
10980 * Fires when the data cache has been cleared.
10981 * @param {Store} this
10985 * @event beforeload
10986 * Fires before a request is made for a new data object. If the beforeload handler returns false
10987 * the load action will be canceled.
10988 * @param {Store} this
10989 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10993 * @event beforeloadadd
10994 * Fires after a new set of Records has been loaded.
10995 * @param {Store} this
10996 * @param {Roo.data.Record[]} records The Records that were loaded
10997 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10999 beforeloadadd : true,
11002 * Fires after a new set of Records has been loaded, before they are added to the store.
11003 * @param {Store} this
11004 * @param {Roo.data.Record[]} records The Records that were loaded
11005 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11006 * @params {Object} return from reader
11010 * @event loadexception
11011 * Fires if an exception occurs in the Proxy during loading.
11012 * Called with the signature of the Proxy's "loadexception" event.
11013 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11016 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11017 * @param {Object} load options
11018 * @param {Object} jsonData from your request (normally this contains the Exception)
11020 loadexception : true
11024 this.proxy = Roo.factory(this.proxy, Roo.data);
11025 this.proxy.xmodule = this.xmodule || false;
11026 this.relayEvents(this.proxy, ["loadexception"]);
11028 this.sortToggle = {};
11029 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11031 Roo.data.Store.superclass.constructor.call(this);
11033 if(this.inlineData){
11034 this.loadData(this.inlineData);
11035 delete this.inlineData;
11039 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11041 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11042 * without a remote query - used by combo/forms at present.
11046 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11049 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11052 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11053 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11056 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11057 * on any HTTP request
11060 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11063 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11067 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11068 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11070 remoteSort : false,
11073 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11074 * loaded or when a record is removed. (defaults to false).
11076 pruneModifiedRecords : false,
11079 lastOptions : null,
11082 * Add Records to the Store and fires the add event.
11083 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11085 add : function(records){
11086 records = [].concat(records);
11087 for(var i = 0, len = records.length; i < len; i++){
11088 records[i].join(this);
11090 var index = this.data.length;
11091 this.data.addAll(records);
11092 this.fireEvent("add", this, records, index);
11096 * Remove a Record from the Store and fires the remove event.
11097 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11099 remove : function(record){
11100 var index = this.data.indexOf(record);
11101 this.data.removeAt(index);
11102 if(this.pruneModifiedRecords){
11103 this.modified.remove(record);
11105 this.fireEvent("remove", this, record, index);
11109 * Remove all Records from the Store and fires the clear event.
11111 removeAll : function(){
11113 if(this.pruneModifiedRecords){
11114 this.modified = [];
11116 this.fireEvent("clear", this);
11120 * Inserts Records to the Store at the given index and fires the add event.
11121 * @param {Number} index The start index at which to insert the passed Records.
11122 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11124 insert : function(index, records){
11125 records = [].concat(records);
11126 for(var i = 0, len = records.length; i < len; i++){
11127 this.data.insert(index, records[i]);
11128 records[i].join(this);
11130 this.fireEvent("add", this, records, index);
11134 * Get the index within the cache of the passed Record.
11135 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11136 * @return {Number} The index of the passed Record. Returns -1 if not found.
11138 indexOf : function(record){
11139 return this.data.indexOf(record);
11143 * Get the index within the cache of the Record with the passed id.
11144 * @param {String} id The id of the Record to find.
11145 * @return {Number} The index of the Record. Returns -1 if not found.
11147 indexOfId : function(id){
11148 return this.data.indexOfKey(id);
11152 * Get the Record with the specified id.
11153 * @param {String} id The id of the Record to find.
11154 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11156 getById : function(id){
11157 return this.data.key(id);
11161 * Get the Record at the specified index.
11162 * @param {Number} index The index of the Record to find.
11163 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11165 getAt : function(index){
11166 return this.data.itemAt(index);
11170 * Returns a range of Records between specified indices.
11171 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11172 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11173 * @return {Roo.data.Record[]} An array of Records
11175 getRange : function(start, end){
11176 return this.data.getRange(start, end);
11180 storeOptions : function(o){
11181 o = Roo.apply({}, o);
11184 this.lastOptions = o;
11188 * Loads the Record cache from the configured Proxy using the configured Reader.
11190 * If using remote paging, then the first load call must specify the <em>start</em>
11191 * and <em>limit</em> properties in the options.params property to establish the initial
11192 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11194 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11195 * and this call will return before the new data has been loaded. Perform any post-processing
11196 * in a callback function, or in a "load" event handler.</strong>
11198 * @param {Object} options An object containing properties which control loading options:<ul>
11199 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11200 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11201 * passed the following arguments:<ul>
11202 * <li>r : Roo.data.Record[]</li>
11203 * <li>options: Options object from the load call</li>
11204 * <li>success: Boolean success indicator</li></ul></li>
11205 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11206 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11209 load : function(options){
11210 options = options || {};
11211 if(this.fireEvent("beforeload", this, options) !== false){
11212 this.storeOptions(options);
11213 var p = Roo.apply(options.params || {}, this.baseParams);
11214 // if meta was not loaded from remote source.. try requesting it.
11215 if (!this.reader.metaFromRemote) {
11216 p._requestMeta = 1;
11218 if(this.sortInfo && this.remoteSort){
11219 var pn = this.paramNames;
11220 p[pn["sort"]] = this.sortInfo.field;
11221 p[pn["dir"]] = this.sortInfo.direction;
11223 if (this.multiSort) {
11224 var pn = this.paramNames;
11225 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11228 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11233 * Reloads the Record cache from the configured Proxy using the configured Reader and
11234 * the options from the last load operation performed.
11235 * @param {Object} options (optional) An object containing properties which may override the options
11236 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11237 * the most recently used options are reused).
11239 reload : function(options){
11240 this.load(Roo.applyIf(options||{}, this.lastOptions));
11244 // Called as a callback by the Reader during a load operation.
11245 loadRecords : function(o, options, success){
11246 if(!o || success === false){
11247 if(success !== false){
11248 this.fireEvent("load", this, [], options, o);
11250 if(options.callback){
11251 options.callback.call(options.scope || this, [], options, false);
11255 // if data returned failure - throw an exception.
11256 if (o.success === false) {
11257 // show a message if no listener is registered.
11258 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11259 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11261 // loadmask wil be hooked into this..
11262 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11265 var r = o.records, t = o.totalRecords || r.length;
11267 this.fireEvent("beforeloadadd", this, r, options, o);
11269 if(!options || options.add !== true){
11270 if(this.pruneModifiedRecords){
11271 this.modified = [];
11273 for(var i = 0, len = r.length; i < len; i++){
11277 this.data = this.snapshot;
11278 delete this.snapshot;
11281 this.data.addAll(r);
11282 this.totalLength = t;
11284 this.fireEvent("datachanged", this);
11286 this.totalLength = Math.max(t, this.data.length+r.length);
11290 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11292 var e = new Roo.data.Record({});
11294 e.set(this.parent.displayField, this.parent.emptyTitle);
11295 e.set(this.parent.valueField, '');
11300 this.fireEvent("load", this, r, options, o);
11301 if(options.callback){
11302 options.callback.call(options.scope || this, r, options, true);
11308 * Loads data from a passed data block. A Reader which understands the format of the data
11309 * must have been configured in the constructor.
11310 * @param {Object} data The data block from which to read the Records. The format of the data expected
11311 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11312 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11314 loadData : function(o, append){
11315 var r = this.reader.readRecords(o);
11316 this.loadRecords(r, {add: append}, true);
11320 * Gets the number of cached records.
11322 * <em>If using paging, this may not be the total size of the dataset. If the data object
11323 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11324 * the data set size</em>
11326 getCount : function(){
11327 return this.data.length || 0;
11331 * Gets the total number of records in the dataset as returned by the server.
11333 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11334 * the dataset size</em>
11336 getTotalCount : function(){
11337 return this.totalLength || 0;
11341 * Returns the sort state of the Store as an object with two properties:
11343 field {String} The name of the field by which the Records are sorted
11344 direction {String} The sort order, "ASC" or "DESC"
11347 getSortState : function(){
11348 return this.sortInfo;
11352 applySort : function(){
11353 if(this.sortInfo && !this.remoteSort){
11354 var s = this.sortInfo, f = s.field;
11355 var st = this.fields.get(f).sortType;
11356 var fn = function(r1, r2){
11357 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11358 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11360 this.data.sort(s.direction, fn);
11361 if(this.snapshot && this.snapshot != this.data){
11362 this.snapshot.sort(s.direction, fn);
11368 * Sets the default sort column and order to be used by the next load operation.
11369 * @param {String} fieldName The name of the field to sort by.
11370 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11372 setDefaultSort : function(field, dir){
11373 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11377 * Sort the Records.
11378 * If remote sorting is used, the sort is performed on the server, and the cache is
11379 * reloaded. If local sorting is used, the cache is sorted internally.
11380 * @param {String} fieldName The name of the field to sort by.
11381 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11383 sort : function(fieldName, dir){
11384 var f = this.fields.get(fieldName);
11386 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11388 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11389 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11394 this.sortToggle[f.name] = dir;
11395 this.sortInfo = {field: f.name, direction: dir};
11396 if(!this.remoteSort){
11398 this.fireEvent("datachanged", this);
11400 this.load(this.lastOptions);
11405 * Calls the specified function for each of the Records in the cache.
11406 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11407 * Returning <em>false</em> aborts and exits the iteration.
11408 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11410 each : function(fn, scope){
11411 this.data.each(fn, scope);
11415 * Gets all records modified since the last commit. Modified records are persisted across load operations
11416 * (e.g., during paging).
11417 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11419 getModifiedRecords : function(){
11420 return this.modified;
11424 createFilterFn : function(property, value, anyMatch){
11425 if(!value.exec){ // not a regex
11426 value = String(value);
11427 if(value.length == 0){
11430 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11432 return function(r){
11433 return value.test(r.data[property]);
11438 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11439 * @param {String} property A field on your records
11440 * @param {Number} start The record index to start at (defaults to 0)
11441 * @param {Number} end The last record index to include (defaults to length - 1)
11442 * @return {Number} The sum
11444 sum : function(property, start, end){
11445 var rs = this.data.items, v = 0;
11446 start = start || 0;
11447 end = (end || end === 0) ? end : rs.length-1;
11449 for(var i = start; i <= end; i++){
11450 v += (rs[i].data[property] || 0);
11456 * Filter the records by a specified property.
11457 * @param {String} field A field on your records
11458 * @param {String/RegExp} value Either a string that the field
11459 * should start with or a RegExp to test against the field
11460 * @param {Boolean} anyMatch True to match any part not just the beginning
11462 filter : function(property, value, anyMatch){
11463 var fn = this.createFilterFn(property, value, anyMatch);
11464 return fn ? this.filterBy(fn) : this.clearFilter();
11468 * Filter by a function. The specified function will be called with each
11469 * record in this data source. If the function returns true the record is included,
11470 * otherwise it is filtered.
11471 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11472 * @param {Object} scope (optional) The scope of the function (defaults to this)
11474 filterBy : function(fn, scope){
11475 this.snapshot = this.snapshot || this.data;
11476 this.data = this.queryBy(fn, scope||this);
11477 this.fireEvent("datachanged", this);
11481 * Query the records by a specified property.
11482 * @param {String} field A field on your records
11483 * @param {String/RegExp} value Either a string that the field
11484 * should start with or a RegExp to test against the field
11485 * @param {Boolean} anyMatch True to match any part not just the beginning
11486 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11488 query : function(property, value, anyMatch){
11489 var fn = this.createFilterFn(property, value, anyMatch);
11490 return fn ? this.queryBy(fn) : this.data.clone();
11494 * Query by a function. The specified function will be called with each
11495 * record in this data source. If the function returns true the record is included
11497 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11498 * @param {Object} scope (optional) The scope of the function (defaults to this)
11499 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11501 queryBy : function(fn, scope){
11502 var data = this.snapshot || this.data;
11503 return data.filterBy(fn, scope||this);
11507 * Collects unique values for a particular dataIndex from this store.
11508 * @param {String} dataIndex The property to collect
11509 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11510 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11511 * @return {Array} An array of the unique values
11513 collect : function(dataIndex, allowNull, bypassFilter){
11514 var d = (bypassFilter === true && this.snapshot) ?
11515 this.snapshot.items : this.data.items;
11516 var v, sv, r = [], l = {};
11517 for(var i = 0, len = d.length; i < len; i++){
11518 v = d[i].data[dataIndex];
11520 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11529 * Revert to a view of the Record cache with no filtering applied.
11530 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11532 clearFilter : function(suppressEvent){
11533 if(this.snapshot && this.snapshot != this.data){
11534 this.data = this.snapshot;
11535 delete this.snapshot;
11536 if(suppressEvent !== true){
11537 this.fireEvent("datachanged", this);
11543 afterEdit : function(record){
11544 if(this.modified.indexOf(record) == -1){
11545 this.modified.push(record);
11547 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11551 afterReject : function(record){
11552 this.modified.remove(record);
11553 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11557 afterCommit : function(record){
11558 this.modified.remove(record);
11559 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11563 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11564 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11566 commitChanges : function(){
11567 var m = this.modified.slice(0);
11568 this.modified = [];
11569 for(var i = 0, len = m.length; i < len; i++){
11575 * Cancel outstanding changes on all changed records.
11577 rejectChanges : function(){
11578 var m = this.modified.slice(0);
11579 this.modified = [];
11580 for(var i = 0, len = m.length; i < len; i++){
11585 onMetaChange : function(meta, rtype, o){
11586 this.recordType = rtype;
11587 this.fields = rtype.prototype.fields;
11588 delete this.snapshot;
11589 this.sortInfo = meta.sortInfo || this.sortInfo;
11590 this.modified = [];
11591 this.fireEvent('metachange', this, this.reader.meta);
11594 moveIndex : function(data, type)
11596 var index = this.indexOf(data);
11598 var newIndex = index + type;
11602 this.insert(newIndex, data);
11607 * Ext JS Library 1.1.1
11608 * Copyright(c) 2006-2007, Ext JS, LLC.
11610 * Originally Released Under LGPL - original licence link has changed is not relivant.
11613 * <script type="text/javascript">
11617 * @class Roo.data.SimpleStore
11618 * @extends Roo.data.Store
11619 * Small helper class to make creating Stores from Array data easier.
11620 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11621 * @cfg {Array} fields An array of field definition objects, or field name strings.
11622 * @cfg {Array} data The multi-dimensional array of data
11624 * @param {Object} config
11626 Roo.data.SimpleStore = function(config){
11627 Roo.data.SimpleStore.superclass.constructor.call(this, {
11629 reader: new Roo.data.ArrayReader({
11632 Roo.data.Record.create(config.fields)
11634 proxy : new Roo.data.MemoryProxy(config.data)
11638 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11640 * Ext JS Library 1.1.1
11641 * Copyright(c) 2006-2007, Ext JS, LLC.
11643 * Originally Released Under LGPL - original licence link has changed is not relivant.
11646 * <script type="text/javascript">
11651 * @extends Roo.data.Store
11652 * @class Roo.data.JsonStore
11653 * Small helper class to make creating Stores for JSON data easier. <br/>
11655 var store = new Roo.data.JsonStore({
11656 url: 'get-images.php',
11658 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11661 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11662 * JsonReader and HttpProxy (unless inline data is provided).</b>
11663 * @cfg {Array} fields An array of field definition objects, or field name strings.
11665 * @param {Object} config
11667 Roo.data.JsonStore = function(c){
11668 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11669 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11670 reader: new Roo.data.JsonReader(c, c.fields)
11673 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11675 * Ext JS Library 1.1.1
11676 * Copyright(c) 2006-2007, Ext JS, LLC.
11678 * Originally Released Under LGPL - original licence link has changed is not relivant.
11681 * <script type="text/javascript">
11685 Roo.data.Field = function(config){
11686 if(typeof config == "string"){
11687 config = {name: config};
11689 Roo.apply(this, config);
11692 this.type = "auto";
11695 var st = Roo.data.SortTypes;
11696 // named sortTypes are supported, here we look them up
11697 if(typeof this.sortType == "string"){
11698 this.sortType = st[this.sortType];
11701 // set default sortType for strings and dates
11702 if(!this.sortType){
11705 this.sortType = st.asUCString;
11708 this.sortType = st.asDate;
11711 this.sortType = st.none;
11716 var stripRe = /[\$,%]/g;
11718 // prebuilt conversion function for this field, instead of
11719 // switching every time we're reading a value
11721 var cv, dateFormat = this.dateFormat;
11726 cv = function(v){ return v; };
11729 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11733 return v !== undefined && v !== null && v !== '' ?
11734 parseInt(String(v).replace(stripRe, ""), 10) : '';
11739 return v !== undefined && v !== null && v !== '' ?
11740 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11745 cv = function(v){ return v === true || v === "true" || v == 1; };
11752 if(v instanceof Date){
11756 if(dateFormat == "timestamp"){
11757 return new Date(v*1000);
11759 return Date.parseDate(v, dateFormat);
11761 var parsed = Date.parse(v);
11762 return parsed ? new Date(parsed) : null;
11771 Roo.data.Field.prototype = {
11779 * Ext JS Library 1.1.1
11780 * Copyright(c) 2006-2007, Ext JS, LLC.
11782 * Originally Released Under LGPL - original licence link has changed is not relivant.
11785 * <script type="text/javascript">
11788 // Base class for reading structured data from a data source. This class is intended to be
11789 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11792 * @class Roo.data.DataReader
11793 * Base class for reading structured data from a data source. This class is intended to be
11794 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11797 Roo.data.DataReader = function(meta, recordType){
11801 this.recordType = recordType instanceof Array ?
11802 Roo.data.Record.create(recordType) : recordType;
11805 Roo.data.DataReader.prototype = {
11807 * Create an empty record
11808 * @param {Object} data (optional) - overlay some values
11809 * @return {Roo.data.Record} record created.
11811 newRow : function(d) {
11813 this.recordType.prototype.fields.each(function(c) {
11815 case 'int' : da[c.name] = 0; break;
11816 case 'date' : da[c.name] = new Date(); break;
11817 case 'float' : da[c.name] = 0.0; break;
11818 case 'boolean' : da[c.name] = false; break;
11819 default : da[c.name] = ""; break;
11823 return new this.recordType(Roo.apply(da, d));
11828 * Ext JS Library 1.1.1
11829 * Copyright(c) 2006-2007, Ext JS, LLC.
11831 * Originally Released Under LGPL - original licence link has changed is not relivant.
11834 * <script type="text/javascript">
11838 * @class Roo.data.DataProxy
11839 * @extends Roo.data.Observable
11840 * This class is an abstract base class for implementations which provide retrieval of
11841 * unformatted data objects.<br>
11843 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11844 * (of the appropriate type which knows how to parse the data object) to provide a block of
11845 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11847 * Custom implementations must implement the load method as described in
11848 * {@link Roo.data.HttpProxy#load}.
11850 Roo.data.DataProxy = function(){
11853 * @event beforeload
11854 * Fires before a network request is made to retrieve a data object.
11855 * @param {Object} This DataProxy object.
11856 * @param {Object} params The params parameter to the load function.
11861 * Fires before the load method's callback is called.
11862 * @param {Object} This DataProxy object.
11863 * @param {Object} o The data object.
11864 * @param {Object} arg The callback argument object passed to the load function.
11868 * @event loadexception
11869 * Fires if an Exception occurs during data retrieval.
11870 * @param {Object} This DataProxy object.
11871 * @param {Object} o The data object.
11872 * @param {Object} arg The callback argument object passed to the load function.
11873 * @param {Object} e The Exception.
11875 loadexception : true
11877 Roo.data.DataProxy.superclass.constructor.call(this);
11880 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11883 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11887 * Ext JS Library 1.1.1
11888 * Copyright(c) 2006-2007, Ext JS, LLC.
11890 * Originally Released Under LGPL - original licence link has changed is not relivant.
11893 * <script type="text/javascript">
11896 * @class Roo.data.MemoryProxy
11897 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11898 * to the Reader when its load method is called.
11900 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11902 Roo.data.MemoryProxy = function(data){
11906 Roo.data.MemoryProxy.superclass.constructor.call(this);
11910 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11913 * Load data from the requested source (in this case an in-memory
11914 * data object passed to the constructor), read the data object into
11915 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11916 * process that block using the passed callback.
11917 * @param {Object} params This parameter is not used by the MemoryProxy class.
11918 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11919 * object into a block of Roo.data.Records.
11920 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11921 * The function must be passed <ul>
11922 * <li>The Record block object</li>
11923 * <li>The "arg" argument from the load function</li>
11924 * <li>A boolean success indicator</li>
11926 * @param {Object} scope The scope in which to call the callback
11927 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11929 load : function(params, reader, callback, scope, arg){
11930 params = params || {};
11933 result = reader.readRecords(this.data);
11935 this.fireEvent("loadexception", this, arg, null, e);
11936 callback.call(scope, null, arg, false);
11939 callback.call(scope, result, arg, true);
11943 update : function(params, records){
11948 * Ext JS Library 1.1.1
11949 * Copyright(c) 2006-2007, Ext JS, LLC.
11951 * Originally Released Under LGPL - original licence link has changed is not relivant.
11954 * <script type="text/javascript">
11957 * @class Roo.data.HttpProxy
11958 * @extends Roo.data.DataProxy
11959 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11960 * configured to reference a certain URL.<br><br>
11962 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11963 * from which the running page was served.<br><br>
11965 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11967 * Be aware that to enable the browser to parse an XML document, the server must set
11968 * the Content-Type header in the HTTP response to "text/xml".
11970 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11971 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11972 * will be used to make the request.
11974 Roo.data.HttpProxy = function(conn){
11975 Roo.data.HttpProxy.superclass.constructor.call(this);
11976 // is conn a conn config or a real conn?
11978 this.useAjax = !conn || !conn.events;
11982 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11983 // thse are take from connection...
11986 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11989 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11990 * extra parameters to each request made by this object. (defaults to undefined)
11993 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11994 * to each request made by this object. (defaults to undefined)
11997 * @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)
12000 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12003 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12009 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12013 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12014 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12015 * a finer-grained basis than the DataProxy events.
12017 getConnection : function(){
12018 return this.useAjax ? Roo.Ajax : this.conn;
12022 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12023 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12024 * process that block using the passed callback.
12025 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12026 * for the request to the remote server.
12027 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12028 * object into a block of Roo.data.Records.
12029 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12030 * The function must be passed <ul>
12031 * <li>The Record block object</li>
12032 * <li>The "arg" argument from the load function</li>
12033 * <li>A boolean success indicator</li>
12035 * @param {Object} scope The scope in which to call the callback
12036 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12038 load : function(params, reader, callback, scope, arg){
12039 if(this.fireEvent("beforeload", this, params) !== false){
12041 params : params || {},
12043 callback : callback,
12048 callback : this.loadResponse,
12052 Roo.applyIf(o, this.conn);
12053 if(this.activeRequest){
12054 Roo.Ajax.abort(this.activeRequest);
12056 this.activeRequest = Roo.Ajax.request(o);
12058 this.conn.request(o);
12061 callback.call(scope||this, null, arg, false);
12066 loadResponse : function(o, success, response){
12067 delete this.activeRequest;
12069 this.fireEvent("loadexception", this, o, response);
12070 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12075 result = o.reader.read(response);
12077 this.fireEvent("loadexception", this, o, response, e);
12078 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12082 this.fireEvent("load", this, o, o.request.arg);
12083 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12087 update : function(dataSet){
12092 updateResponse : function(dataSet){
12097 * Ext JS Library 1.1.1
12098 * Copyright(c) 2006-2007, Ext JS, LLC.
12100 * Originally Released Under LGPL - original licence link has changed is not relivant.
12103 * <script type="text/javascript">
12107 * @class Roo.data.ScriptTagProxy
12108 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12109 * other than the originating domain of the running page.<br><br>
12111 * <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
12112 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12114 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12115 * source code that is used as the source inside a <script> tag.<br><br>
12117 * In order for the browser to process the returned data, the server must wrap the data object
12118 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12119 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12120 * depending on whether the callback name was passed:
12123 boolean scriptTag = false;
12124 String cb = request.getParameter("callback");
12127 response.setContentType("text/javascript");
12129 response.setContentType("application/x-json");
12131 Writer out = response.getWriter();
12133 out.write(cb + "(");
12135 out.print(dataBlock.toJsonString());
12142 * @param {Object} config A configuration object.
12144 Roo.data.ScriptTagProxy = function(config){
12145 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12146 Roo.apply(this, config);
12147 this.head = document.getElementsByTagName("head")[0];
12150 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12152 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12154 * @cfg {String} url The URL from which to request the data object.
12157 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12161 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12162 * the server the name of the callback function set up by the load call to process the returned data object.
12163 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12164 * javascript output which calls this named function passing the data object as its only parameter.
12166 callbackParam : "callback",
12168 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12169 * name to the request.
12174 * Load data from the configured URL, read the data object into
12175 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12176 * process that block using the passed callback.
12177 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12178 * for the request to the remote server.
12179 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12180 * object into a block of Roo.data.Records.
12181 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12182 * The function must be passed <ul>
12183 * <li>The Record block object</li>
12184 * <li>The "arg" argument from the load function</li>
12185 * <li>A boolean success indicator</li>
12187 * @param {Object} scope The scope in which to call the callback
12188 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12190 load : function(params, reader, callback, scope, arg){
12191 if(this.fireEvent("beforeload", this, params) !== false){
12193 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12195 var url = this.url;
12196 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12198 url += "&_dc=" + (new Date().getTime());
12200 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12203 cb : "stcCallback"+transId,
12204 scriptId : "stcScript"+transId,
12208 callback : callback,
12214 window[trans.cb] = function(o){
12215 conn.handleResponse(o, trans);
12218 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12220 if(this.autoAbort !== false){
12224 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12226 var script = document.createElement("script");
12227 script.setAttribute("src", url);
12228 script.setAttribute("type", "text/javascript");
12229 script.setAttribute("id", trans.scriptId);
12230 this.head.appendChild(script);
12232 this.trans = trans;
12234 callback.call(scope||this, null, arg, false);
12239 isLoading : function(){
12240 return this.trans ? true : false;
12244 * Abort the current server request.
12246 abort : function(){
12247 if(this.isLoading()){
12248 this.destroyTrans(this.trans);
12253 destroyTrans : function(trans, isLoaded){
12254 this.head.removeChild(document.getElementById(trans.scriptId));
12255 clearTimeout(trans.timeoutId);
12257 window[trans.cb] = undefined;
12259 delete window[trans.cb];
12262 // if hasn't been loaded, wait for load to remove it to prevent script error
12263 window[trans.cb] = function(){
12264 window[trans.cb] = undefined;
12266 delete window[trans.cb];
12273 handleResponse : function(o, trans){
12274 this.trans = false;
12275 this.destroyTrans(trans, true);
12278 result = trans.reader.readRecords(o);
12280 this.fireEvent("loadexception", this, o, trans.arg, e);
12281 trans.callback.call(trans.scope||window, null, trans.arg, false);
12284 this.fireEvent("load", this, o, trans.arg);
12285 trans.callback.call(trans.scope||window, result, trans.arg, true);
12289 handleFailure : function(trans){
12290 this.trans = false;
12291 this.destroyTrans(trans, false);
12292 this.fireEvent("loadexception", this, null, trans.arg);
12293 trans.callback.call(trans.scope||window, null, trans.arg, false);
12297 * Ext JS Library 1.1.1
12298 * Copyright(c) 2006-2007, Ext JS, LLC.
12300 * Originally Released Under LGPL - original licence link has changed is not relivant.
12303 * <script type="text/javascript">
12307 * @class Roo.data.JsonReader
12308 * @extends Roo.data.DataReader
12309 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12310 * based on mappings in a provided Roo.data.Record constructor.
12312 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12313 * in the reply previously.
12318 var RecordDef = Roo.data.Record.create([
12319 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12320 {name: 'occupation'} // This field will use "occupation" as the mapping.
12322 var myReader = new Roo.data.JsonReader({
12323 totalProperty: "results", // The property which contains the total dataset size (optional)
12324 root: "rows", // The property which contains an Array of row objects
12325 id: "id" // The property within each row object that provides an ID for the record (optional)
12329 * This would consume a JSON file like this:
12331 { 'results': 2, 'rows': [
12332 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12333 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12336 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12337 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12338 * paged from the remote server.
12339 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12340 * @cfg {String} root name of the property which contains the Array of row objects.
12341 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12342 * @cfg {Array} fields Array of field definition objects
12344 * Create a new JsonReader
12345 * @param {Object} meta Metadata configuration options
12346 * @param {Object} recordType Either an Array of field definition objects,
12347 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12349 Roo.data.JsonReader = function(meta, recordType){
12352 // set some defaults:
12353 Roo.applyIf(meta, {
12354 totalProperty: 'total',
12355 successProperty : 'success',
12360 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12362 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12365 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12366 * Used by Store query builder to append _requestMeta to params.
12369 metaFromRemote : false,
12371 * This method is only used by a DataProxy which has retrieved data from a remote server.
12372 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12373 * @return {Object} data A data block which is used by an Roo.data.Store object as
12374 * a cache of Roo.data.Records.
12376 read : function(response){
12377 var json = response.responseText;
12379 var o = /* eval:var:o */ eval("("+json+")");
12381 throw {message: "JsonReader.read: Json object not found"};
12387 this.metaFromRemote = true;
12388 this.meta = o.metaData;
12389 this.recordType = Roo.data.Record.create(o.metaData.fields);
12390 this.onMetaChange(this.meta, this.recordType, o);
12392 return this.readRecords(o);
12395 // private function a store will implement
12396 onMetaChange : function(meta, recordType, o){
12403 simpleAccess: function(obj, subsc) {
12410 getJsonAccessor: function(){
12412 return function(expr) {
12414 return(re.test(expr))
12415 ? new Function("obj", "return obj." + expr)
12420 return Roo.emptyFn;
12425 * Create a data block containing Roo.data.Records from an XML document.
12426 * @param {Object} o An object which contains an Array of row objects in the property specified
12427 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12428 * which contains the total size of the dataset.
12429 * @return {Object} data A data block which is used by an Roo.data.Store object as
12430 * a cache of Roo.data.Records.
12432 readRecords : function(o){
12434 * After any data loads, the raw JSON data is available for further custom processing.
12438 var s = this.meta, Record = this.recordType,
12439 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12441 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12443 if(s.totalProperty) {
12444 this.getTotal = this.getJsonAccessor(s.totalProperty);
12446 if(s.successProperty) {
12447 this.getSuccess = this.getJsonAccessor(s.successProperty);
12449 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12451 var g = this.getJsonAccessor(s.id);
12452 this.getId = function(rec) {
12454 return (r === undefined || r === "") ? null : r;
12457 this.getId = function(){return null;};
12460 for(var jj = 0; jj < fl; jj++){
12462 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12463 this.ef[jj] = this.getJsonAccessor(map);
12467 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12468 if(s.totalProperty){
12469 var vt = parseInt(this.getTotal(o), 10);
12474 if(s.successProperty){
12475 var vs = this.getSuccess(o);
12476 if(vs === false || vs === 'false'){
12481 for(var i = 0; i < c; i++){
12484 var id = this.getId(n);
12485 for(var j = 0; j < fl; j++){
12487 var v = this.ef[j](n);
12489 Roo.log('missing convert for ' + f.name);
12493 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12495 var record = new Record(values, id);
12497 records[i] = record;
12503 totalRecords : totalRecords
12508 * Ext JS Library 1.1.1
12509 * Copyright(c) 2006-2007, Ext JS, LLC.
12511 * Originally Released Under LGPL - original licence link has changed is not relivant.
12514 * <script type="text/javascript">
12518 * @class Roo.data.ArrayReader
12519 * @extends Roo.data.DataReader
12520 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12521 * Each element of that Array represents a row of data fields. The
12522 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12523 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12527 var RecordDef = Roo.data.Record.create([
12528 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12529 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12531 var myReader = new Roo.data.ArrayReader({
12532 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12536 * This would consume an Array like this:
12538 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12540 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12542 * Create a new JsonReader
12543 * @param {Object} meta Metadata configuration options.
12544 * @param {Object} recordType Either an Array of field definition objects
12545 * as specified to {@link Roo.data.Record#create},
12546 * or an {@link Roo.data.Record} object
12547 * created using {@link Roo.data.Record#create}.
12549 Roo.data.ArrayReader = function(meta, recordType){
12550 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12553 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12555 * Create a data block containing Roo.data.Records from an XML document.
12556 * @param {Object} o An Array of row objects which represents the dataset.
12557 * @return {Object} data A data block which is used by an Roo.data.Store object as
12558 * a cache of Roo.data.Records.
12560 readRecords : function(o){
12561 var sid = this.meta ? this.meta.id : null;
12562 var recordType = this.recordType, fields = recordType.prototype.fields;
12565 for(var i = 0; i < root.length; i++){
12568 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12569 for(var j = 0, jlen = fields.length; j < jlen; j++){
12570 var f = fields.items[j];
12571 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12572 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12574 values[f.name] = v;
12576 var record = new recordType(values, id);
12578 records[records.length] = record;
12582 totalRecords : records.length
12591 * @class Roo.bootstrap.ComboBox
12592 * @extends Roo.bootstrap.TriggerField
12593 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12594 * @cfg {Boolean} append (true|false) default false
12595 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12596 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12597 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12598 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12599 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12600 * @cfg {Boolean} animate default true
12601 * @cfg {Boolean} emptyResultText only for touch device
12602 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12603 * @cfg {String} emptyTitle default ''
12605 * Create a new ComboBox.
12606 * @param {Object} config Configuration options
12608 Roo.bootstrap.ComboBox = function(config){
12609 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12613 * Fires when the dropdown list is expanded
12614 * @param {Roo.bootstrap.ComboBox} combo This combo box
12619 * Fires when the dropdown list is collapsed
12620 * @param {Roo.bootstrap.ComboBox} combo This combo box
12624 * @event beforeselect
12625 * Fires before a list item is selected. Return false to cancel the selection.
12626 * @param {Roo.bootstrap.ComboBox} combo This combo box
12627 * @param {Roo.data.Record} record The data record returned from the underlying store
12628 * @param {Number} index The index of the selected item in the dropdown list
12630 'beforeselect' : true,
12633 * Fires when a list item is selected
12634 * @param {Roo.bootstrap.ComboBox} combo This combo box
12635 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12636 * @param {Number} index The index of the selected item in the dropdown list
12640 * @event beforequery
12641 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12642 * The event object passed has these properties:
12643 * @param {Roo.bootstrap.ComboBox} combo This combo box
12644 * @param {String} query The query
12645 * @param {Boolean} forceAll true to force "all" query
12646 * @param {Boolean} cancel true to cancel the query
12647 * @param {Object} e The query event object
12649 'beforequery': true,
12652 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12653 * @param {Roo.bootstrap.ComboBox} combo This combo box
12658 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12659 * @param {Roo.bootstrap.ComboBox} combo This combo box
12660 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12665 * Fires when the remove value from the combobox array
12666 * @param {Roo.bootstrap.ComboBox} combo This combo box
12670 * @event afterremove
12671 * Fires when the remove value from the combobox array
12672 * @param {Roo.bootstrap.ComboBox} combo This combo box
12674 'afterremove' : true,
12676 * @event specialfilter
12677 * Fires when specialfilter
12678 * @param {Roo.bootstrap.ComboBox} combo This combo box
12680 'specialfilter' : true,
12683 * Fires when tick the element
12684 * @param {Roo.bootstrap.ComboBox} combo This combo box
12688 * @event touchviewdisplay
12689 * Fires when touch view require special display (default is using displayField)
12690 * @param {Roo.bootstrap.ComboBox} combo This combo box
12691 * @param {Object} cfg set html .
12693 'touchviewdisplay' : true
12698 this.tickItems = [];
12700 this.selectedIndex = -1;
12701 if(this.mode == 'local'){
12702 if(config.queryDelay === undefined){
12703 this.queryDelay = 10;
12705 if(config.minChars === undefined){
12711 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12714 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12715 * rendering into an Roo.Editor, defaults to false)
12718 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12719 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12722 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12725 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12726 * the dropdown list (defaults to undefined, with no header element)
12730 * @cfg {String/Roo.Template} tpl The template to use to render the output
12734 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12736 listWidth: undefined,
12738 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12739 * mode = 'remote' or 'text' if mode = 'local')
12741 displayField: undefined,
12744 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12745 * mode = 'remote' or 'value' if mode = 'local').
12746 * Note: use of a valueField requires the user make a selection
12747 * in order for a value to be mapped.
12749 valueField: undefined,
12751 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12756 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12757 * field's data value (defaults to the underlying DOM element's name)
12759 hiddenName: undefined,
12761 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12765 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12767 selectedClass: 'active',
12770 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12774 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12775 * anchor positions (defaults to 'tl-bl')
12777 listAlign: 'tl-bl?',
12779 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12783 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12784 * query specified by the allQuery config option (defaults to 'query')
12786 triggerAction: 'query',
12788 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12789 * (defaults to 4, does not apply if editable = false)
12793 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12794 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12798 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12799 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12803 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12804 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12808 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12809 * when editable = true (defaults to false)
12811 selectOnFocus:false,
12813 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12815 queryParam: 'query',
12817 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12818 * when mode = 'remote' (defaults to 'Loading...')
12820 loadingText: 'Loading...',
12822 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12826 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12830 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12831 * traditional select (defaults to true)
12835 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12839 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12843 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12844 * listWidth has a higher value)
12848 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12849 * allow the user to set arbitrary text into the field (defaults to false)
12851 forceSelection:false,
12853 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12854 * if typeAhead = true (defaults to 250)
12856 typeAheadDelay : 250,
12858 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12859 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12861 valueNotFoundText : undefined,
12863 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12865 blockFocus : false,
12868 * @cfg {Boolean} disableClear Disable showing of clear button.
12870 disableClear : false,
12872 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12874 alwaysQuery : false,
12877 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12882 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12884 invalidClass : "has-warning",
12887 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12889 validClass : "has-success",
12892 * @cfg {Boolean} specialFilter (true|false) special filter default false
12894 specialFilter : false,
12897 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12899 mobileTouchView : true,
12902 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12904 useNativeIOS : false,
12906 ios_options : false,
12918 btnPosition : 'right',
12919 triggerList : true,
12920 showToggleBtn : true,
12922 emptyResultText: 'Empty',
12923 triggerText : 'Select',
12926 // element that contains real text value.. (when hidden is used..)
12928 getAutoCreate : function()
12933 * Render classic select for iso
12936 if(Roo.isIOS && this.useNativeIOS){
12937 cfg = this.getAutoCreateNativeIOS();
12945 if(Roo.isTouch && this.mobileTouchView){
12946 cfg = this.getAutoCreateTouchView();
12953 if(!this.tickable){
12954 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12959 * ComboBox with tickable selections
12962 var align = this.labelAlign || this.parentLabelAlign();
12965 cls : 'form-group roo-combobox-tickable' //input-group
12968 var btn_text_select = '';
12969 var btn_text_done = '';
12970 var btn_text_cancel = '';
12972 if (this.btn_text_show) {
12973 btn_text_select = 'Select';
12974 btn_text_done = 'Done';
12975 btn_text_cancel = 'Cancel';
12980 cls : 'tickable-buttons',
12985 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12986 //html : this.triggerText
12987 html: btn_text_select
12993 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12995 html: btn_text_done
13001 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13003 html: btn_text_cancel
13009 buttons.cn.unshift({
13011 cls: 'roo-select2-search-field-input'
13017 Roo.each(buttons.cn, function(c){
13019 c.cls += ' btn-' + _this.size;
13022 if (_this.disabled) {
13033 cls: 'form-hidden-field'
13037 cls: 'roo-select2-choices',
13041 cls: 'roo-select2-search-field',
13052 cls: 'roo-select2-container input-group roo-select2-container-multi',
13057 // cls: 'typeahead typeahead-long dropdown-menu',
13058 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13063 if(this.hasFeedback && !this.allowBlank){
13067 cls: 'glyphicon form-control-feedback'
13070 combobox.cn.push(feedback);
13074 if (align ==='left' && this.fieldLabel.length) {
13076 cfg.cls += ' roo-form-group-label-left';
13081 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13082 tooltip : 'This field is required'
13087 cls : 'control-label',
13088 html : this.fieldLabel
13100 var labelCfg = cfg.cn[1];
13101 var contentCfg = cfg.cn[2];
13104 if(this.indicatorpos == 'right'){
13110 cls : 'control-label',
13114 html : this.fieldLabel
13118 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13119 tooltip : 'This field is required'
13134 labelCfg = cfg.cn[0];
13135 contentCfg = cfg.cn[1];
13139 if(this.labelWidth > 12){
13140 labelCfg.style = "width: " + this.labelWidth + 'px';
13143 if(this.labelWidth < 13 && this.labelmd == 0){
13144 this.labelmd = this.labelWidth;
13147 if(this.labellg > 0){
13148 labelCfg.cls += ' col-lg-' + this.labellg;
13149 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13152 if(this.labelmd > 0){
13153 labelCfg.cls += ' col-md-' + this.labelmd;
13154 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13157 if(this.labelsm > 0){
13158 labelCfg.cls += ' col-sm-' + this.labelsm;
13159 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13162 if(this.labelxs > 0){
13163 labelCfg.cls += ' col-xs-' + this.labelxs;
13164 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13168 } else if ( this.fieldLabel.length) {
13169 // Roo.log(" label");
13173 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13174 tooltip : 'This field is required'
13178 //cls : 'input-group-addon',
13179 html : this.fieldLabel
13184 if(this.indicatorpos == 'right'){
13188 //cls : 'input-group-addon',
13189 html : this.fieldLabel
13193 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13194 tooltip : 'This field is required'
13203 // Roo.log(" no label && no align");
13210 ['xs','sm','md','lg'].map(function(size){
13211 if (settings[size]) {
13212 cfg.cls += ' col-' + size + '-' + settings[size];
13220 _initEventsCalled : false,
13223 initEvents: function()
13225 if (this._initEventsCalled) { // as we call render... prevent looping...
13228 this._initEventsCalled = true;
13231 throw "can not find store for combo";
13234 this.indicator = this.indicatorEl();
13236 this.store = Roo.factory(this.store, Roo.data);
13237 this.store.parent = this;
13239 // if we are building from html. then this element is so complex, that we can not really
13240 // use the rendered HTML.
13241 // so we have to trash and replace the previous code.
13242 if (Roo.XComponent.build_from_html) {
13243 // remove this element....
13244 var e = this.el.dom, k=0;
13245 while (e ) { e = e.previousSibling; ++k;}
13250 this.rendered = false;
13252 this.render(this.parent().getChildContainer(true), k);
13255 if(Roo.isIOS && this.useNativeIOS){
13256 this.initIOSView();
13264 if(Roo.isTouch && this.mobileTouchView){
13265 this.initTouchView();
13270 this.initTickableEvents();
13274 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13276 if(this.hiddenName){
13278 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13280 this.hiddenField.dom.value =
13281 this.hiddenValue !== undefined ? this.hiddenValue :
13282 this.value !== undefined ? this.value : '';
13284 // prevent input submission
13285 this.el.dom.removeAttribute('name');
13286 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13291 // this.el.dom.setAttribute('autocomplete', 'off');
13294 var cls = 'x-combo-list';
13296 //this.list = new Roo.Layer({
13297 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13303 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13304 _this.list.setWidth(lw);
13307 this.list.on('mouseover', this.onViewOver, this);
13308 this.list.on('mousemove', this.onViewMove, this);
13309 this.list.on('scroll', this.onViewScroll, this);
13312 this.list.swallowEvent('mousewheel');
13313 this.assetHeight = 0;
13316 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13317 this.assetHeight += this.header.getHeight();
13320 this.innerList = this.list.createChild({cls:cls+'-inner'});
13321 this.innerList.on('mouseover', this.onViewOver, this);
13322 this.innerList.on('mousemove', this.onViewMove, this);
13323 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13325 if(this.allowBlank && !this.pageSize && !this.disableClear){
13326 this.footer = this.list.createChild({cls:cls+'-ft'});
13327 this.pageTb = new Roo.Toolbar(this.footer);
13331 this.footer = this.list.createChild({cls:cls+'-ft'});
13332 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13333 {pageSize: this.pageSize});
13337 if (this.pageTb && this.allowBlank && !this.disableClear) {
13339 this.pageTb.add(new Roo.Toolbar.Fill(), {
13340 cls: 'x-btn-icon x-btn-clear',
13342 handler: function()
13345 _this.clearValue();
13346 _this.onSelect(false, -1);
13351 this.assetHeight += this.footer.getHeight();
13356 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13359 this.view = new Roo.View(this.list, this.tpl, {
13360 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13362 //this.view.wrapEl.setDisplayed(false);
13363 this.view.on('click', this.onViewClick, this);
13366 this.store.on('beforeload', this.onBeforeLoad, this);
13367 this.store.on('load', this.onLoad, this);
13368 this.store.on('loadexception', this.onLoadException, this);
13370 if(this.resizable){
13371 this.resizer = new Roo.Resizable(this.list, {
13372 pinned:true, handles:'se'
13374 this.resizer.on('resize', function(r, w, h){
13375 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13376 this.listWidth = w;
13377 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13378 this.restrictHeight();
13380 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13383 if(!this.editable){
13384 this.editable = true;
13385 this.setEditable(false);
13390 if (typeof(this.events.add.listeners) != 'undefined') {
13392 this.addicon = this.wrap.createChild(
13393 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13395 this.addicon.on('click', function(e) {
13396 this.fireEvent('add', this);
13399 if (typeof(this.events.edit.listeners) != 'undefined') {
13401 this.editicon = this.wrap.createChild(
13402 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13403 if (this.addicon) {
13404 this.editicon.setStyle('margin-left', '40px');
13406 this.editicon.on('click', function(e) {
13408 // we fire even if inothing is selected..
13409 this.fireEvent('edit', this, this.lastData );
13415 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13416 "up" : function(e){
13417 this.inKeyMode = true;
13421 "down" : function(e){
13422 if(!this.isExpanded()){
13423 this.onTriggerClick();
13425 this.inKeyMode = true;
13430 "enter" : function(e){
13431 // this.onViewClick();
13435 if(this.fireEvent("specialkey", this, e)){
13436 this.onViewClick(false);
13442 "esc" : function(e){
13446 "tab" : function(e){
13449 if(this.fireEvent("specialkey", this, e)){
13450 this.onViewClick(false);
13458 doRelay : function(foo, bar, hname){
13459 if(hname == 'down' || this.scope.isExpanded()){
13460 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13469 this.queryDelay = Math.max(this.queryDelay || 10,
13470 this.mode == 'local' ? 10 : 250);
13473 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13475 if(this.typeAhead){
13476 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13478 if(this.editable !== false){
13479 this.inputEl().on("keyup", this.onKeyUp, this);
13481 if(this.forceSelection){
13482 this.inputEl().on('blur', this.doForce, this);
13486 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13487 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13491 initTickableEvents: function()
13495 if(this.hiddenName){
13497 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13499 this.hiddenField.dom.value =
13500 this.hiddenValue !== undefined ? this.hiddenValue :
13501 this.value !== undefined ? this.value : '';
13503 // prevent input submission
13504 this.el.dom.removeAttribute('name');
13505 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13510 // this.list = this.el.select('ul.dropdown-menu',true).first();
13512 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13513 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13514 if(this.triggerList){
13515 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13518 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13519 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13521 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13522 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13524 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13525 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13527 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13528 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13529 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13532 this.cancelBtn.hide();
13537 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13538 _this.list.setWidth(lw);
13541 this.list.on('mouseover', this.onViewOver, this);
13542 this.list.on('mousemove', this.onViewMove, this);
13544 this.list.on('scroll', this.onViewScroll, this);
13547 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>';
13550 this.view = new Roo.View(this.list, this.tpl, {
13551 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13554 //this.view.wrapEl.setDisplayed(false);
13555 this.view.on('click', this.onViewClick, this);
13559 this.store.on('beforeload', this.onBeforeLoad, this);
13560 this.store.on('load', this.onLoad, this);
13561 this.store.on('loadexception', this.onLoadException, this);
13564 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13565 "up" : function(e){
13566 this.inKeyMode = true;
13570 "down" : function(e){
13571 this.inKeyMode = true;
13575 "enter" : function(e){
13576 if(this.fireEvent("specialkey", this, e)){
13577 this.onViewClick(false);
13583 "esc" : function(e){
13584 this.onTickableFooterButtonClick(e, false, false);
13587 "tab" : function(e){
13588 this.fireEvent("specialkey", this, e);
13590 this.onTickableFooterButtonClick(e, false, false);
13597 doRelay : function(e, fn, key){
13598 if(this.scope.isExpanded()){
13599 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13608 this.queryDelay = Math.max(this.queryDelay || 10,
13609 this.mode == 'local' ? 10 : 250);
13612 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13614 if(this.typeAhead){
13615 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13618 if(this.editable !== false){
13619 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13622 this.indicator = this.indicatorEl();
13624 if(this.indicator){
13625 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13626 this.indicator.hide();
13631 onDestroy : function(){
13633 this.view.setStore(null);
13634 this.view.el.removeAllListeners();
13635 this.view.el.remove();
13636 this.view.purgeListeners();
13639 this.list.dom.innerHTML = '';
13643 this.store.un('beforeload', this.onBeforeLoad, this);
13644 this.store.un('load', this.onLoad, this);
13645 this.store.un('loadexception', this.onLoadException, this);
13647 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13651 fireKey : function(e){
13652 if(e.isNavKeyPress() && !this.list.isVisible()){
13653 this.fireEvent("specialkey", this, e);
13658 onResize: function(w, h){
13659 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13661 // if(typeof w != 'number'){
13662 // // we do not handle it!?!?
13665 // var tw = this.trigger.getWidth();
13666 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13667 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13669 // this.inputEl().setWidth( this.adjustWidth('input', x));
13671 // //this.trigger.setStyle('left', x+'px');
13673 // if(this.list && this.listWidth === undefined){
13674 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13675 // this.list.setWidth(lw);
13676 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13684 * Allow or prevent the user from directly editing the field text. If false is passed,
13685 * the user will only be able to select from the items defined in the dropdown list. This method
13686 * is the runtime equivalent of setting the 'editable' config option at config time.
13687 * @param {Boolean} value True to allow the user to directly edit the field text
13689 setEditable : function(value){
13690 if(value == this.editable){
13693 this.editable = value;
13695 this.inputEl().dom.setAttribute('readOnly', true);
13696 this.inputEl().on('mousedown', this.onTriggerClick, this);
13697 this.inputEl().addClass('x-combo-noedit');
13699 this.inputEl().dom.setAttribute('readOnly', false);
13700 this.inputEl().un('mousedown', this.onTriggerClick, this);
13701 this.inputEl().removeClass('x-combo-noedit');
13707 onBeforeLoad : function(combo,opts){
13708 if(!this.hasFocus){
13712 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13714 this.restrictHeight();
13715 this.selectedIndex = -1;
13719 onLoad : function(){
13721 this.hasQuery = false;
13723 if(!this.hasFocus){
13727 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13728 this.loading.hide();
13731 if(this.store.getCount() > 0){
13734 this.restrictHeight();
13735 if(this.lastQuery == this.allQuery){
13736 if(this.editable && !this.tickable){
13737 this.inputEl().dom.select();
13741 !this.selectByValue(this.value, true) &&
13744 !this.store.lastOptions ||
13745 typeof(this.store.lastOptions.add) == 'undefined' ||
13746 this.store.lastOptions.add != true
13749 this.select(0, true);
13752 if(this.autoFocus){
13755 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13756 this.taTask.delay(this.typeAheadDelay);
13760 this.onEmptyResults();
13766 onLoadException : function()
13768 this.hasQuery = false;
13770 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13771 this.loading.hide();
13774 if(this.tickable && this.editable){
13779 // only causes errors at present
13780 //Roo.log(this.store.reader.jsonData);
13781 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13783 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13789 onTypeAhead : function(){
13790 if(this.store.getCount() > 0){
13791 var r = this.store.getAt(0);
13792 var newValue = r.data[this.displayField];
13793 var len = newValue.length;
13794 var selStart = this.getRawValue().length;
13796 if(selStart != len){
13797 this.setRawValue(newValue);
13798 this.selectText(selStart, newValue.length);
13804 onSelect : function(record, index){
13806 if(this.fireEvent('beforeselect', this, record, index) !== false){
13808 this.setFromData(index > -1 ? record.data : false);
13811 this.fireEvent('select', this, record, index);
13816 * Returns the currently selected field value or empty string if no value is set.
13817 * @return {String} value The selected value
13819 getValue : function()
13821 if(Roo.isIOS && this.useNativeIOS){
13822 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13826 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13829 if(this.valueField){
13830 return typeof this.value != 'undefined' ? this.value : '';
13832 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13836 getRawValue : function()
13838 if(Roo.isIOS && this.useNativeIOS){
13839 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13842 var v = this.inputEl().getValue();
13848 * Clears any text/value currently set in the field
13850 clearValue : function(){
13852 if(this.hiddenField){
13853 this.hiddenField.dom.value = '';
13856 this.setRawValue('');
13857 this.lastSelectionText = '';
13858 this.lastData = false;
13860 var close = this.closeTriggerEl();
13871 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13872 * will be displayed in the field. If the value does not match the data value of an existing item,
13873 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13874 * Otherwise the field will be blank (although the value will still be set).
13875 * @param {String} value The value to match
13877 setValue : function(v)
13879 if(Roo.isIOS && this.useNativeIOS){
13880 this.setIOSValue(v);
13890 if(this.valueField){
13891 var r = this.findRecord(this.valueField, v);
13893 text = r.data[this.displayField];
13894 }else if(this.valueNotFoundText !== undefined){
13895 text = this.valueNotFoundText;
13898 this.lastSelectionText = text;
13899 if(this.hiddenField){
13900 this.hiddenField.dom.value = v;
13902 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13905 var close = this.closeTriggerEl();
13908 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13914 * @property {Object} the last set data for the element
13919 * Sets the value of the field based on a object which is related to the record format for the store.
13920 * @param {Object} value the value to set as. or false on reset?
13922 setFromData : function(o){
13929 var dv = ''; // display value
13930 var vv = ''; // value value..
13932 if (this.displayField) {
13933 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13935 // this is an error condition!!!
13936 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13939 if(this.valueField){
13940 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13943 var close = this.closeTriggerEl();
13946 if(dv.length || vv * 1 > 0){
13948 this.blockFocus=true;
13954 if(this.hiddenField){
13955 this.hiddenField.dom.value = vv;
13957 this.lastSelectionText = dv;
13958 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13962 // no hidden field.. - we store the value in 'value', but still display
13963 // display field!!!!
13964 this.lastSelectionText = dv;
13965 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13972 reset : function(){
13973 // overridden so that last data is reset..
13980 this.setValue(this.originalValue);
13981 //this.clearInvalid();
13982 this.lastData = false;
13984 this.view.clearSelections();
13990 findRecord : function(prop, value){
13992 if(this.store.getCount() > 0){
13993 this.store.each(function(r){
13994 if(r.data[prop] == value){
14004 getName: function()
14006 // returns hidden if it's set..
14007 if (!this.rendered) {return ''};
14008 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14012 onViewMove : function(e, t){
14013 this.inKeyMode = false;
14017 onViewOver : function(e, t){
14018 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14021 var item = this.view.findItemFromChild(t);
14024 var index = this.view.indexOf(item);
14025 this.select(index, false);
14030 onViewClick : function(view, doFocus, el, e)
14032 var index = this.view.getSelectedIndexes()[0];
14034 var r = this.store.getAt(index);
14038 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14045 Roo.each(this.tickItems, function(v,k){
14047 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14049 _this.tickItems.splice(k, 1);
14051 if(typeof(e) == 'undefined' && view == false){
14052 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14064 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14065 this.tickItems.push(r.data);
14068 if(typeof(e) == 'undefined' && view == false){
14069 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14076 this.onSelect(r, index);
14078 if(doFocus !== false && !this.blockFocus){
14079 this.inputEl().focus();
14084 restrictHeight : function(){
14085 //this.innerList.dom.style.height = '';
14086 //var inner = this.innerList.dom;
14087 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14088 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14089 //this.list.beginUpdate();
14090 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14091 this.list.alignTo(this.inputEl(), this.listAlign);
14092 this.list.alignTo(this.inputEl(), this.listAlign);
14093 //this.list.endUpdate();
14097 onEmptyResults : function(){
14099 if(this.tickable && this.editable){
14100 this.hasFocus = false;
14101 this.restrictHeight();
14109 * Returns true if the dropdown list is expanded, else false.
14111 isExpanded : function(){
14112 return this.list.isVisible();
14116 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14117 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14118 * @param {String} value The data value of the item to select
14119 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14120 * selected item if it is not currently in view (defaults to true)
14121 * @return {Boolean} True if the value matched an item in the list, else false
14123 selectByValue : function(v, scrollIntoView){
14124 if(v !== undefined && v !== null){
14125 var r = this.findRecord(this.valueField || this.displayField, v);
14127 this.select(this.store.indexOf(r), scrollIntoView);
14135 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14136 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14137 * @param {Number} index The zero-based index of the list item to select
14138 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14139 * selected item if it is not currently in view (defaults to true)
14141 select : function(index, scrollIntoView){
14142 this.selectedIndex = index;
14143 this.view.select(index);
14144 if(scrollIntoView !== false){
14145 var el = this.view.getNode(index);
14147 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14150 this.list.scrollChildIntoView(el, false);
14156 selectNext : function(){
14157 var ct = this.store.getCount();
14159 if(this.selectedIndex == -1){
14161 }else if(this.selectedIndex < ct-1){
14162 this.select(this.selectedIndex+1);
14168 selectPrev : function(){
14169 var ct = this.store.getCount();
14171 if(this.selectedIndex == -1){
14173 }else if(this.selectedIndex != 0){
14174 this.select(this.selectedIndex-1);
14180 onKeyUp : function(e){
14181 if(this.editable !== false && !e.isSpecialKey()){
14182 this.lastKey = e.getKey();
14183 this.dqTask.delay(this.queryDelay);
14188 validateBlur : function(){
14189 return !this.list || !this.list.isVisible();
14193 initQuery : function(){
14195 var v = this.getRawValue();
14197 if(this.tickable && this.editable){
14198 v = this.tickableInputEl().getValue();
14205 doForce : function(){
14206 if(this.inputEl().dom.value.length > 0){
14207 this.inputEl().dom.value =
14208 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14214 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14215 * query allowing the query action to be canceled if needed.
14216 * @param {String} query The SQL query to execute
14217 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14218 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14219 * saved in the current store (defaults to false)
14221 doQuery : function(q, forceAll){
14223 if(q === undefined || q === null){
14228 forceAll: forceAll,
14232 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14237 forceAll = qe.forceAll;
14238 if(forceAll === true || (q.length >= this.minChars)){
14240 this.hasQuery = true;
14242 if(this.lastQuery != q || this.alwaysQuery){
14243 this.lastQuery = q;
14244 if(this.mode == 'local'){
14245 this.selectedIndex = -1;
14247 this.store.clearFilter();
14250 if(this.specialFilter){
14251 this.fireEvent('specialfilter', this);
14256 this.store.filter(this.displayField, q);
14259 this.store.fireEvent("datachanged", this.store);
14266 this.store.baseParams[this.queryParam] = q;
14268 var options = {params : this.getParams(q)};
14271 options.add = true;
14272 options.params.start = this.page * this.pageSize;
14275 this.store.load(options);
14278 * this code will make the page width larger, at the beginning, the list not align correctly,
14279 * we should expand the list on onLoad
14280 * so command out it
14285 this.selectedIndex = -1;
14290 this.loadNext = false;
14294 getParams : function(q){
14296 //p[this.queryParam] = q;
14300 p.limit = this.pageSize;
14306 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14308 collapse : function(){
14309 if(!this.isExpanded()){
14315 this.hasFocus = false;
14319 this.cancelBtn.hide();
14320 this.trigger.show();
14323 this.tickableInputEl().dom.value = '';
14324 this.tickableInputEl().blur();
14329 Roo.get(document).un('mousedown', this.collapseIf, this);
14330 Roo.get(document).un('mousewheel', this.collapseIf, this);
14331 if (!this.editable) {
14332 Roo.get(document).un('keydown', this.listKeyPress, this);
14334 this.fireEvent('collapse', this);
14340 collapseIf : function(e){
14341 var in_combo = e.within(this.el);
14342 var in_list = e.within(this.list);
14343 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14345 if (in_combo || in_list || is_list) {
14346 //e.stopPropagation();
14351 this.onTickableFooterButtonClick(e, false, false);
14359 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14361 expand : function(){
14363 if(this.isExpanded() || !this.hasFocus){
14367 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14368 this.list.setWidth(lw);
14374 this.restrictHeight();
14378 this.tickItems = Roo.apply([], this.item);
14381 this.cancelBtn.show();
14382 this.trigger.hide();
14385 this.tickableInputEl().focus();
14390 Roo.get(document).on('mousedown', this.collapseIf, this);
14391 Roo.get(document).on('mousewheel', this.collapseIf, this);
14392 if (!this.editable) {
14393 Roo.get(document).on('keydown', this.listKeyPress, this);
14396 this.fireEvent('expand', this);
14400 // Implements the default empty TriggerField.onTriggerClick function
14401 onTriggerClick : function(e)
14403 Roo.log('trigger click');
14405 if(this.disabled || !this.triggerList){
14410 this.loadNext = false;
14412 if(this.isExpanded()){
14414 if (!this.blockFocus) {
14415 this.inputEl().focus();
14419 this.hasFocus = true;
14420 if(this.triggerAction == 'all') {
14421 this.doQuery(this.allQuery, true);
14423 this.doQuery(this.getRawValue());
14425 if (!this.blockFocus) {
14426 this.inputEl().focus();
14431 onTickableTriggerClick : function(e)
14438 this.loadNext = false;
14439 this.hasFocus = true;
14441 if(this.triggerAction == 'all') {
14442 this.doQuery(this.allQuery, true);
14444 this.doQuery(this.getRawValue());
14448 onSearchFieldClick : function(e)
14450 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14451 this.onTickableFooterButtonClick(e, false, false);
14455 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14460 this.loadNext = false;
14461 this.hasFocus = true;
14463 if(this.triggerAction == 'all') {
14464 this.doQuery(this.allQuery, true);
14466 this.doQuery(this.getRawValue());
14470 listKeyPress : function(e)
14472 //Roo.log('listkeypress');
14473 // scroll to first matching element based on key pres..
14474 if (e.isSpecialKey()) {
14477 var k = String.fromCharCode(e.getKey()).toUpperCase();
14480 var csel = this.view.getSelectedNodes();
14481 var cselitem = false;
14483 var ix = this.view.indexOf(csel[0]);
14484 cselitem = this.store.getAt(ix);
14485 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14491 this.store.each(function(v) {
14493 // start at existing selection.
14494 if (cselitem.id == v.id) {
14500 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14501 match = this.store.indexOf(v);
14507 if (match === false) {
14508 return true; // no more action?
14511 this.view.select(match);
14512 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14513 sn.scrollIntoView(sn.dom.parentNode, false);
14516 onViewScroll : function(e, t){
14518 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){
14522 this.hasQuery = true;
14524 this.loading = this.list.select('.loading', true).first();
14526 if(this.loading === null){
14527 this.list.createChild({
14529 cls: 'loading roo-select2-more-results roo-select2-active',
14530 html: 'Loading more results...'
14533 this.loading = this.list.select('.loading', true).first();
14535 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14537 this.loading.hide();
14540 this.loading.show();
14545 this.loadNext = true;
14547 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14552 addItem : function(o)
14554 var dv = ''; // display value
14556 if (this.displayField) {
14557 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14559 // this is an error condition!!!
14560 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14567 var choice = this.choices.createChild({
14569 cls: 'roo-select2-search-choice',
14578 cls: 'roo-select2-search-choice-close fa fa-times',
14583 }, this.searchField);
14585 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14587 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14595 this.inputEl().dom.value = '';
14600 onRemoveItem : function(e, _self, o)
14602 e.preventDefault();
14604 this.lastItem = Roo.apply([], this.item);
14606 var index = this.item.indexOf(o.data) * 1;
14609 Roo.log('not this item?!');
14613 this.item.splice(index, 1);
14618 this.fireEvent('remove', this, e);
14624 syncValue : function()
14626 if(!this.item.length){
14633 Roo.each(this.item, function(i){
14634 if(_this.valueField){
14635 value.push(i[_this.valueField]);
14642 this.value = value.join(',');
14644 if(this.hiddenField){
14645 this.hiddenField.dom.value = this.value;
14648 this.store.fireEvent("datachanged", this.store);
14653 clearItem : function()
14655 if(!this.multiple){
14661 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14669 if(this.tickable && !Roo.isTouch){
14670 this.view.refresh();
14674 inputEl: function ()
14676 if(Roo.isIOS && this.useNativeIOS){
14677 return this.el.select('select.roo-ios-select', true).first();
14680 if(Roo.isTouch && this.mobileTouchView){
14681 return this.el.select('input.form-control',true).first();
14685 return this.searchField;
14688 return this.el.select('input.form-control',true).first();
14691 onTickableFooterButtonClick : function(e, btn, el)
14693 e.preventDefault();
14695 this.lastItem = Roo.apply([], this.item);
14697 if(btn && btn.name == 'cancel'){
14698 this.tickItems = Roo.apply([], this.item);
14707 Roo.each(this.tickItems, function(o){
14715 validate : function()
14717 if(this.getVisibilityEl().hasClass('hidden')){
14721 var v = this.getRawValue();
14724 v = this.getValue();
14727 if(this.disabled || this.allowBlank || v.length){
14732 this.markInvalid();
14736 tickableInputEl : function()
14738 if(!this.tickable || !this.editable){
14739 return this.inputEl();
14742 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14746 getAutoCreateTouchView : function()
14751 cls: 'form-group' //input-group
14757 type : this.inputType,
14758 cls : 'form-control x-combo-noedit',
14759 autocomplete: 'new-password',
14760 placeholder : this.placeholder || '',
14765 input.name = this.name;
14769 input.cls += ' input-' + this.size;
14772 if (this.disabled) {
14773 input.disabled = true;
14784 inputblock.cls += ' input-group';
14786 inputblock.cn.unshift({
14788 cls : 'input-group-addon',
14793 if(this.removable && !this.multiple){
14794 inputblock.cls += ' roo-removable';
14796 inputblock.cn.push({
14799 cls : 'roo-combo-removable-btn close'
14803 if(this.hasFeedback && !this.allowBlank){
14805 inputblock.cls += ' has-feedback';
14807 inputblock.cn.push({
14809 cls: 'glyphicon form-control-feedback'
14816 inputblock.cls += (this.before) ? '' : ' input-group';
14818 inputblock.cn.push({
14820 cls : 'input-group-addon',
14831 cls: 'form-hidden-field'
14845 cls: 'form-hidden-field'
14849 cls: 'roo-select2-choices',
14853 cls: 'roo-select2-search-field',
14866 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14872 if(!this.multiple && this.showToggleBtn){
14879 if (this.caret != false) {
14882 cls: 'fa fa-' + this.caret
14889 cls : 'input-group-addon btn dropdown-toggle',
14894 cls: 'combobox-clear',
14908 combobox.cls += ' roo-select2-container-multi';
14911 var align = this.labelAlign || this.parentLabelAlign();
14913 if (align ==='left' && this.fieldLabel.length) {
14918 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14919 tooltip : 'This field is required'
14923 cls : 'control-label',
14924 html : this.fieldLabel
14935 var labelCfg = cfg.cn[1];
14936 var contentCfg = cfg.cn[2];
14939 if(this.indicatorpos == 'right'){
14944 cls : 'control-label',
14948 html : this.fieldLabel
14952 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14953 tooltip : 'This field is required'
14966 labelCfg = cfg.cn[0];
14967 contentCfg = cfg.cn[1];
14972 if(this.labelWidth > 12){
14973 labelCfg.style = "width: " + this.labelWidth + 'px';
14976 if(this.labelWidth < 13 && this.labelmd == 0){
14977 this.labelmd = this.labelWidth;
14980 if(this.labellg > 0){
14981 labelCfg.cls += ' col-lg-' + this.labellg;
14982 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14985 if(this.labelmd > 0){
14986 labelCfg.cls += ' col-md-' + this.labelmd;
14987 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14990 if(this.labelsm > 0){
14991 labelCfg.cls += ' col-sm-' + this.labelsm;
14992 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14995 if(this.labelxs > 0){
14996 labelCfg.cls += ' col-xs-' + this.labelxs;
14997 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15001 } else if ( this.fieldLabel.length) {
15005 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15006 tooltip : 'This field is required'
15010 cls : 'control-label',
15011 html : this.fieldLabel
15022 if(this.indicatorpos == 'right'){
15026 cls : 'control-label',
15027 html : this.fieldLabel,
15031 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15032 tooltip : 'This field is required'
15049 var settings = this;
15051 ['xs','sm','md','lg'].map(function(size){
15052 if (settings[size]) {
15053 cfg.cls += ' col-' + size + '-' + settings[size];
15060 initTouchView : function()
15062 this.renderTouchView();
15064 this.touchViewEl.on('scroll', function(){
15065 this.el.dom.scrollTop = 0;
15068 this.originalValue = this.getValue();
15070 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15072 this.inputEl().on("click", this.showTouchView, this);
15073 if (this.triggerEl) {
15074 this.triggerEl.on("click", this.showTouchView, this);
15078 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15079 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15081 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15083 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15084 this.store.on('load', this.onTouchViewLoad, this);
15085 this.store.on('loadexception', this.onTouchViewLoadException, this);
15087 if(this.hiddenName){
15089 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15091 this.hiddenField.dom.value =
15092 this.hiddenValue !== undefined ? this.hiddenValue :
15093 this.value !== undefined ? this.value : '';
15095 this.el.dom.removeAttribute('name');
15096 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15100 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15101 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15104 if(this.removable && !this.multiple){
15105 var close = this.closeTriggerEl();
15107 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15108 close.on('click', this.removeBtnClick, this, close);
15112 * fix the bug in Safari iOS8
15114 this.inputEl().on("focus", function(e){
15115 document.activeElement.blur();
15123 renderTouchView : function()
15125 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15126 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15128 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15129 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15131 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15132 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15133 this.touchViewBodyEl.setStyle('overflow', 'auto');
15135 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15136 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15138 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15139 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15143 showTouchView : function()
15149 this.touchViewHeaderEl.hide();
15151 if(this.modalTitle.length){
15152 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15153 this.touchViewHeaderEl.show();
15156 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15157 this.touchViewEl.show();
15159 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15161 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15162 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15164 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15166 if(this.modalTitle.length){
15167 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15170 this.touchViewBodyEl.setHeight(bodyHeight);
15174 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15176 this.touchViewEl.addClass('in');
15179 this.doTouchViewQuery();
15183 hideTouchView : function()
15185 this.touchViewEl.removeClass('in');
15189 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15191 this.touchViewEl.setStyle('display', 'none');
15196 setTouchViewValue : function()
15203 Roo.each(this.tickItems, function(o){
15208 this.hideTouchView();
15211 doTouchViewQuery : function()
15220 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15224 if(!this.alwaysQuery || this.mode == 'local'){
15225 this.onTouchViewLoad();
15232 onTouchViewBeforeLoad : function(combo,opts)
15238 onTouchViewLoad : function()
15240 if(this.store.getCount() < 1){
15241 this.onTouchViewEmptyResults();
15245 this.clearTouchView();
15247 var rawValue = this.getRawValue();
15249 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15251 this.tickItems = [];
15253 this.store.data.each(function(d, rowIndex){
15254 var row = this.touchViewListGroup.createChild(template);
15256 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15257 row.addClass(d.data.cls);
15260 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15263 html : d.data[this.displayField]
15266 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15267 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15270 row.removeClass('selected');
15271 if(!this.multiple && this.valueField &&
15272 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15275 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15276 row.addClass('selected');
15279 if(this.multiple && this.valueField &&
15280 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15284 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15285 this.tickItems.push(d.data);
15288 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15292 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15294 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15296 if(this.modalTitle.length){
15297 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15300 var listHeight = this.touchViewListGroup.getHeight();
15304 if(firstChecked && listHeight > bodyHeight){
15305 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15310 onTouchViewLoadException : function()
15312 this.hideTouchView();
15315 onTouchViewEmptyResults : function()
15317 this.clearTouchView();
15319 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15321 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15325 clearTouchView : function()
15327 this.touchViewListGroup.dom.innerHTML = '';
15330 onTouchViewClick : function(e, el, o)
15332 e.preventDefault();
15335 var rowIndex = o.rowIndex;
15337 var r = this.store.getAt(rowIndex);
15339 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15341 if(!this.multiple){
15342 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15343 c.dom.removeAttribute('checked');
15346 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15348 this.setFromData(r.data);
15350 var close = this.closeTriggerEl();
15356 this.hideTouchView();
15358 this.fireEvent('select', this, r, rowIndex);
15363 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15364 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15365 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15369 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15370 this.addItem(r.data);
15371 this.tickItems.push(r.data);
15375 getAutoCreateNativeIOS : function()
15378 cls: 'form-group' //input-group,
15383 cls : 'roo-ios-select'
15387 combobox.name = this.name;
15390 if (this.disabled) {
15391 combobox.disabled = true;
15394 var settings = this;
15396 ['xs','sm','md','lg'].map(function(size){
15397 if (settings[size]) {
15398 cfg.cls += ' col-' + size + '-' + settings[size];
15408 initIOSView : function()
15410 this.store.on('load', this.onIOSViewLoad, this);
15415 onIOSViewLoad : function()
15417 if(this.store.getCount() < 1){
15421 this.clearIOSView();
15423 if(this.allowBlank) {
15425 var default_text = '-- SELECT --';
15427 if(this.placeholder.length){
15428 default_text = this.placeholder;
15431 if(this.emptyTitle.length){
15432 default_text += ' - ' + this.emptyTitle + ' -';
15435 var opt = this.inputEl().createChild({
15438 html : default_text
15442 o[this.valueField] = 0;
15443 o[this.displayField] = default_text;
15445 this.ios_options.push({
15452 this.store.data.each(function(d, rowIndex){
15456 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15457 html = d.data[this.displayField];
15462 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15463 value = d.data[this.valueField];
15472 if(this.value == d.data[this.valueField]){
15473 option['selected'] = true;
15476 var opt = this.inputEl().createChild(option);
15478 this.ios_options.push({
15485 this.inputEl().on('change', function(){
15486 this.fireEvent('select', this);
15491 clearIOSView: function()
15493 this.inputEl().dom.innerHTML = '';
15495 this.ios_options = [];
15498 setIOSValue: function(v)
15502 if(!this.ios_options){
15506 Roo.each(this.ios_options, function(opts){
15508 opts.el.dom.removeAttribute('selected');
15510 if(opts.data[this.valueField] != v){
15514 opts.el.dom.setAttribute('selected', true);
15520 * @cfg {Boolean} grow
15524 * @cfg {Number} growMin
15528 * @cfg {Number} growMax
15537 Roo.apply(Roo.bootstrap.ComboBox, {
15541 cls: 'modal-header',
15563 cls: 'list-group-item',
15567 cls: 'roo-combobox-list-group-item-value'
15571 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15585 listItemCheckbox : {
15587 cls: 'list-group-item',
15591 cls: 'roo-combobox-list-group-item-value'
15595 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15611 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15616 cls: 'modal-footer',
15624 cls: 'col-xs-6 text-left',
15627 cls: 'btn btn-danger roo-touch-view-cancel',
15633 cls: 'col-xs-6 text-right',
15636 cls: 'btn btn-success roo-touch-view-ok',
15647 Roo.apply(Roo.bootstrap.ComboBox, {
15649 touchViewTemplate : {
15651 cls: 'modal fade roo-combobox-touch-view',
15655 cls: 'modal-dialog',
15656 style : 'position:fixed', // we have to fix position....
15660 cls: 'modal-content',
15662 Roo.bootstrap.ComboBox.header,
15663 Roo.bootstrap.ComboBox.body,
15664 Roo.bootstrap.ComboBox.footer
15673 * Ext JS Library 1.1.1
15674 * Copyright(c) 2006-2007, Ext JS, LLC.
15676 * Originally Released Under LGPL - original licence link has changed is not relivant.
15679 * <script type="text/javascript">
15684 * @extends Roo.util.Observable
15685 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15686 * This class also supports single and multi selection modes. <br>
15687 * Create a data model bound view:
15689 var store = new Roo.data.Store(...);
15691 var view = new Roo.View({
15693 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15695 singleSelect: true,
15696 selectedClass: "ydataview-selected",
15700 // listen for node click?
15701 view.on("click", function(vw, index, node, e){
15702 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15706 dataModel.load("foobar.xml");
15708 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15710 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15711 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15713 * Note: old style constructor is still suported (container, template, config)
15716 * Create a new View
15717 * @param {Object} config The config object
15720 Roo.View = function(config, depreciated_tpl, depreciated_config){
15722 this.parent = false;
15724 if (typeof(depreciated_tpl) == 'undefined') {
15725 // new way.. - universal constructor.
15726 Roo.apply(this, config);
15727 this.el = Roo.get(this.el);
15730 this.el = Roo.get(config);
15731 this.tpl = depreciated_tpl;
15732 Roo.apply(this, depreciated_config);
15734 this.wrapEl = this.el.wrap().wrap();
15735 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15738 if(typeof(this.tpl) == "string"){
15739 this.tpl = new Roo.Template(this.tpl);
15741 // support xtype ctors..
15742 this.tpl = new Roo.factory(this.tpl, Roo);
15746 this.tpl.compile();
15751 * @event beforeclick
15752 * Fires before a click is processed. Returns false to cancel the default action.
15753 * @param {Roo.View} this
15754 * @param {Number} index The index of the target node
15755 * @param {HTMLElement} node The target node
15756 * @param {Roo.EventObject} e The raw event object
15758 "beforeclick" : true,
15761 * Fires when a template node is clicked.
15762 * @param {Roo.View} this
15763 * @param {Number} index The index of the target node
15764 * @param {HTMLElement} node The target node
15765 * @param {Roo.EventObject} e The raw event object
15770 * Fires when a template node is double clicked.
15771 * @param {Roo.View} this
15772 * @param {Number} index The index of the target node
15773 * @param {HTMLElement} node The target node
15774 * @param {Roo.EventObject} e The raw event object
15778 * @event contextmenu
15779 * Fires when a template node is right clicked.
15780 * @param {Roo.View} this
15781 * @param {Number} index The index of the target node
15782 * @param {HTMLElement} node The target node
15783 * @param {Roo.EventObject} e The raw event object
15785 "contextmenu" : true,
15787 * @event selectionchange
15788 * Fires when the selected nodes change.
15789 * @param {Roo.View} this
15790 * @param {Array} selections Array of the selected nodes
15792 "selectionchange" : true,
15795 * @event beforeselect
15796 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15797 * @param {Roo.View} this
15798 * @param {HTMLElement} node The node to be selected
15799 * @param {Array} selections Array of currently selected nodes
15801 "beforeselect" : true,
15803 * @event preparedata
15804 * Fires on every row to render, to allow you to change the data.
15805 * @param {Roo.View} this
15806 * @param {Object} data to be rendered (change this)
15808 "preparedata" : true
15816 "click": this.onClick,
15817 "dblclick": this.onDblClick,
15818 "contextmenu": this.onContextMenu,
15822 this.selections = [];
15824 this.cmp = new Roo.CompositeElementLite([]);
15826 this.store = Roo.factory(this.store, Roo.data);
15827 this.setStore(this.store, true);
15830 if ( this.footer && this.footer.xtype) {
15832 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15834 this.footer.dataSource = this.store;
15835 this.footer.container = fctr;
15836 this.footer = Roo.factory(this.footer, Roo);
15837 fctr.insertFirst(this.el);
15839 // this is a bit insane - as the paging toolbar seems to detach the el..
15840 // dom.parentNode.parentNode.parentNode
15841 // they get detached?
15845 Roo.View.superclass.constructor.call(this);
15850 Roo.extend(Roo.View, Roo.util.Observable, {
15853 * @cfg {Roo.data.Store} store Data store to load data from.
15858 * @cfg {String|Roo.Element} el The container element.
15863 * @cfg {String|Roo.Template} tpl The template used by this View
15867 * @cfg {String} dataName the named area of the template to use as the data area
15868 * Works with domtemplates roo-name="name"
15872 * @cfg {String} selectedClass The css class to add to selected nodes
15874 selectedClass : "x-view-selected",
15876 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15881 * @cfg {String} text to display on mask (default Loading)
15885 * @cfg {Boolean} multiSelect Allow multiple selection
15887 multiSelect : false,
15889 * @cfg {Boolean} singleSelect Allow single selection
15891 singleSelect: false,
15894 * @cfg {Boolean} toggleSelect - selecting
15896 toggleSelect : false,
15899 * @cfg {Boolean} tickable - selecting
15904 * Returns the element this view is bound to.
15905 * @return {Roo.Element}
15907 getEl : function(){
15908 return this.wrapEl;
15914 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15916 refresh : function(){
15917 //Roo.log('refresh');
15920 // if we are using something like 'domtemplate', then
15921 // the what gets used is:
15922 // t.applySubtemplate(NAME, data, wrapping data..)
15923 // the outer template then get' applied with
15924 // the store 'extra data'
15925 // and the body get's added to the
15926 // roo-name="data" node?
15927 // <span class='roo-tpl-{name}'></span> ?????
15931 this.clearSelections();
15932 this.el.update("");
15934 var records = this.store.getRange();
15935 if(records.length < 1) {
15937 // is this valid?? = should it render a template??
15939 this.el.update(this.emptyText);
15943 if (this.dataName) {
15944 this.el.update(t.apply(this.store.meta)); //????
15945 el = this.el.child('.roo-tpl-' + this.dataName);
15948 for(var i = 0, len = records.length; i < len; i++){
15949 var data = this.prepareData(records[i].data, i, records[i]);
15950 this.fireEvent("preparedata", this, data, i, records[i]);
15952 var d = Roo.apply({}, data);
15955 Roo.apply(d, {'roo-id' : Roo.id()});
15959 Roo.each(this.parent.item, function(item){
15960 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15963 Roo.apply(d, {'roo-data-checked' : 'checked'});
15967 html[html.length] = Roo.util.Format.trim(
15969 t.applySubtemplate(this.dataName, d, this.store.meta) :
15976 el.update(html.join(""));
15977 this.nodes = el.dom.childNodes;
15978 this.updateIndexes(0);
15983 * Function to override to reformat the data that is sent to
15984 * the template for each node.
15985 * DEPRICATED - use the preparedata event handler.
15986 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15987 * a JSON object for an UpdateManager bound view).
15989 prepareData : function(data, index, record)
15991 this.fireEvent("preparedata", this, data, index, record);
15995 onUpdate : function(ds, record){
15996 // Roo.log('on update');
15997 this.clearSelections();
15998 var index = this.store.indexOf(record);
15999 var n = this.nodes[index];
16000 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16001 n.parentNode.removeChild(n);
16002 this.updateIndexes(index, index);
16008 onAdd : function(ds, records, index)
16010 //Roo.log(['on Add', ds, records, index] );
16011 this.clearSelections();
16012 if(this.nodes.length == 0){
16016 var n = this.nodes[index];
16017 for(var i = 0, len = records.length; i < len; i++){
16018 var d = this.prepareData(records[i].data, i, records[i]);
16020 this.tpl.insertBefore(n, d);
16023 this.tpl.append(this.el, d);
16026 this.updateIndexes(index);
16029 onRemove : function(ds, record, index){
16030 // Roo.log('onRemove');
16031 this.clearSelections();
16032 var el = this.dataName ?
16033 this.el.child('.roo-tpl-' + this.dataName) :
16036 el.dom.removeChild(this.nodes[index]);
16037 this.updateIndexes(index);
16041 * Refresh an individual node.
16042 * @param {Number} index
16044 refreshNode : function(index){
16045 this.onUpdate(this.store, this.store.getAt(index));
16048 updateIndexes : function(startIndex, endIndex){
16049 var ns = this.nodes;
16050 startIndex = startIndex || 0;
16051 endIndex = endIndex || ns.length - 1;
16052 for(var i = startIndex; i <= endIndex; i++){
16053 ns[i].nodeIndex = i;
16058 * Changes the data store this view uses and refresh the view.
16059 * @param {Store} store
16061 setStore : function(store, initial){
16062 if(!initial && this.store){
16063 this.store.un("datachanged", this.refresh);
16064 this.store.un("add", this.onAdd);
16065 this.store.un("remove", this.onRemove);
16066 this.store.un("update", this.onUpdate);
16067 this.store.un("clear", this.refresh);
16068 this.store.un("beforeload", this.onBeforeLoad);
16069 this.store.un("load", this.onLoad);
16070 this.store.un("loadexception", this.onLoad);
16074 store.on("datachanged", this.refresh, this);
16075 store.on("add", this.onAdd, this);
16076 store.on("remove", this.onRemove, this);
16077 store.on("update", this.onUpdate, this);
16078 store.on("clear", this.refresh, this);
16079 store.on("beforeload", this.onBeforeLoad, this);
16080 store.on("load", this.onLoad, this);
16081 store.on("loadexception", this.onLoad, this);
16089 * onbeforeLoad - masks the loading area.
16092 onBeforeLoad : function(store,opts)
16094 //Roo.log('onBeforeLoad');
16096 this.el.update("");
16098 this.el.mask(this.mask ? this.mask : "Loading" );
16100 onLoad : function ()
16107 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16108 * @param {HTMLElement} node
16109 * @return {HTMLElement} The template node
16111 findItemFromChild : function(node){
16112 var el = this.dataName ?
16113 this.el.child('.roo-tpl-' + this.dataName,true) :
16116 if(!node || node.parentNode == el){
16119 var p = node.parentNode;
16120 while(p && p != el){
16121 if(p.parentNode == el){
16130 onClick : function(e){
16131 var item = this.findItemFromChild(e.getTarget());
16133 var index = this.indexOf(item);
16134 if(this.onItemClick(item, index, e) !== false){
16135 this.fireEvent("click", this, index, item, e);
16138 this.clearSelections();
16143 onContextMenu : function(e){
16144 var item = this.findItemFromChild(e.getTarget());
16146 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16151 onDblClick : function(e){
16152 var item = this.findItemFromChild(e.getTarget());
16154 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16158 onItemClick : function(item, index, e)
16160 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16163 if (this.toggleSelect) {
16164 var m = this.isSelected(item) ? 'unselect' : 'select';
16167 _t[m](item, true, false);
16170 if(this.multiSelect || this.singleSelect){
16171 if(this.multiSelect && e.shiftKey && this.lastSelection){
16172 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16174 this.select(item, this.multiSelect && e.ctrlKey);
16175 this.lastSelection = item;
16178 if(!this.tickable){
16179 e.preventDefault();
16187 * Get the number of selected nodes.
16190 getSelectionCount : function(){
16191 return this.selections.length;
16195 * Get the currently selected nodes.
16196 * @return {Array} An array of HTMLElements
16198 getSelectedNodes : function(){
16199 return this.selections;
16203 * Get the indexes of the selected nodes.
16206 getSelectedIndexes : function(){
16207 var indexes = [], s = this.selections;
16208 for(var i = 0, len = s.length; i < len; i++){
16209 indexes.push(s[i].nodeIndex);
16215 * Clear all selections
16216 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16218 clearSelections : function(suppressEvent){
16219 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16220 this.cmp.elements = this.selections;
16221 this.cmp.removeClass(this.selectedClass);
16222 this.selections = [];
16223 if(!suppressEvent){
16224 this.fireEvent("selectionchange", this, this.selections);
16230 * Returns true if the passed node is selected
16231 * @param {HTMLElement/Number} node The node or node index
16232 * @return {Boolean}
16234 isSelected : function(node){
16235 var s = this.selections;
16239 node = this.getNode(node);
16240 return s.indexOf(node) !== -1;
16245 * @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
16246 * @param {Boolean} keepExisting (optional) true to keep existing selections
16247 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16249 select : function(nodeInfo, keepExisting, suppressEvent){
16250 if(nodeInfo instanceof Array){
16252 this.clearSelections(true);
16254 for(var i = 0, len = nodeInfo.length; i < len; i++){
16255 this.select(nodeInfo[i], true, true);
16259 var node = this.getNode(nodeInfo);
16260 if(!node || this.isSelected(node)){
16261 return; // already selected.
16264 this.clearSelections(true);
16267 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16268 Roo.fly(node).addClass(this.selectedClass);
16269 this.selections.push(node);
16270 if(!suppressEvent){
16271 this.fireEvent("selectionchange", this, this.selections);
16279 * @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
16280 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16281 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16283 unselect : function(nodeInfo, keepExisting, suppressEvent)
16285 if(nodeInfo instanceof Array){
16286 Roo.each(this.selections, function(s) {
16287 this.unselect(s, nodeInfo);
16291 var node = this.getNode(nodeInfo);
16292 if(!node || !this.isSelected(node)){
16293 //Roo.log("not selected");
16294 return; // not selected.
16298 Roo.each(this.selections, function(s) {
16300 Roo.fly(node).removeClass(this.selectedClass);
16307 this.selections= ns;
16308 this.fireEvent("selectionchange", this, this.selections);
16312 * Gets a template node.
16313 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16314 * @return {HTMLElement} The node or null if it wasn't found
16316 getNode : function(nodeInfo){
16317 if(typeof nodeInfo == "string"){
16318 return document.getElementById(nodeInfo);
16319 }else if(typeof nodeInfo == "number"){
16320 return this.nodes[nodeInfo];
16326 * Gets a range template nodes.
16327 * @param {Number} startIndex
16328 * @param {Number} endIndex
16329 * @return {Array} An array of nodes
16331 getNodes : function(start, end){
16332 var ns = this.nodes;
16333 start = start || 0;
16334 end = typeof end == "undefined" ? ns.length - 1 : end;
16337 for(var i = start; i <= end; i++){
16341 for(var i = start; i >= end; i--){
16349 * Finds the index of the passed node
16350 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16351 * @return {Number} The index of the node or -1
16353 indexOf : function(node){
16354 node = this.getNode(node);
16355 if(typeof node.nodeIndex == "number"){
16356 return node.nodeIndex;
16358 var ns = this.nodes;
16359 for(var i = 0, len = ns.length; i < len; i++){
16370 * based on jquery fullcalendar
16374 Roo.bootstrap = Roo.bootstrap || {};
16376 * @class Roo.bootstrap.Calendar
16377 * @extends Roo.bootstrap.Component
16378 * Bootstrap Calendar class
16379 * @cfg {Boolean} loadMask (true|false) default false
16380 * @cfg {Object} header generate the user specific header of the calendar, default false
16383 * Create a new Container
16384 * @param {Object} config The config object
16389 Roo.bootstrap.Calendar = function(config){
16390 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16394 * Fires when a date is selected
16395 * @param {DatePicker} this
16396 * @param {Date} date The selected date
16400 * @event monthchange
16401 * Fires when the displayed month changes
16402 * @param {DatePicker} this
16403 * @param {Date} date The selected month
16405 'monthchange': true,
16407 * @event evententer
16408 * Fires when mouse over an event
16409 * @param {Calendar} this
16410 * @param {event} Event
16412 'evententer': true,
16414 * @event eventleave
16415 * Fires when the mouse leaves an
16416 * @param {Calendar} this
16419 'eventleave': true,
16421 * @event eventclick
16422 * Fires when the mouse click an
16423 * @param {Calendar} this
16432 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16435 * @cfg {Number} startDay
16436 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16444 getAutoCreate : function(){
16447 var fc_button = function(name, corner, style, content ) {
16448 return Roo.apply({},{
16450 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16452 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16455 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16466 style : 'width:100%',
16473 cls : 'fc-header-left',
16475 fc_button('prev', 'left', 'arrow', '‹' ),
16476 fc_button('next', 'right', 'arrow', '›' ),
16477 { tag: 'span', cls: 'fc-header-space' },
16478 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16486 cls : 'fc-header-center',
16490 cls: 'fc-header-title',
16493 html : 'month / year'
16501 cls : 'fc-header-right',
16503 /* fc_button('month', 'left', '', 'month' ),
16504 fc_button('week', '', '', 'week' ),
16505 fc_button('day', 'right', '', 'day' )
16517 header = this.header;
16520 var cal_heads = function() {
16522 // fixme - handle this.
16524 for (var i =0; i < Date.dayNames.length; i++) {
16525 var d = Date.dayNames[i];
16528 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16529 html : d.substring(0,3)
16533 ret[0].cls += ' fc-first';
16534 ret[6].cls += ' fc-last';
16537 var cal_cell = function(n) {
16540 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16545 cls: 'fc-day-number',
16549 cls: 'fc-day-content',
16553 style: 'position: relative;' // height: 17px;
16565 var cal_rows = function() {
16568 for (var r = 0; r < 6; r++) {
16575 for (var i =0; i < Date.dayNames.length; i++) {
16576 var d = Date.dayNames[i];
16577 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16580 row.cn[0].cls+=' fc-first';
16581 row.cn[0].cn[0].style = 'min-height:90px';
16582 row.cn[6].cls+=' fc-last';
16586 ret[0].cls += ' fc-first';
16587 ret[4].cls += ' fc-prev-last';
16588 ret[5].cls += ' fc-last';
16595 cls: 'fc-border-separate',
16596 style : 'width:100%',
16604 cls : 'fc-first fc-last',
16622 cls : 'fc-content',
16623 style : "position: relative;",
16626 cls : 'fc-view fc-view-month fc-grid',
16627 style : 'position: relative',
16628 unselectable : 'on',
16631 cls : 'fc-event-container',
16632 style : 'position:absolute;z-index:8;top:0;left:0;'
16650 initEvents : function()
16653 throw "can not find store for calendar";
16659 style: "text-align:center",
16663 style: "background-color:white;width:50%;margin:250 auto",
16667 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16678 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16680 var size = this.el.select('.fc-content', true).first().getSize();
16681 this.maskEl.setSize(size.width, size.height);
16682 this.maskEl.enableDisplayMode("block");
16683 if(!this.loadMask){
16684 this.maskEl.hide();
16687 this.store = Roo.factory(this.store, Roo.data);
16688 this.store.on('load', this.onLoad, this);
16689 this.store.on('beforeload', this.onBeforeLoad, this);
16693 this.cells = this.el.select('.fc-day',true);
16694 //Roo.log(this.cells);
16695 this.textNodes = this.el.query('.fc-day-number');
16696 this.cells.addClassOnOver('fc-state-hover');
16698 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16699 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16700 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16701 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16703 this.on('monthchange', this.onMonthChange, this);
16705 this.update(new Date().clearTime());
16708 resize : function() {
16709 var sz = this.el.getSize();
16711 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16712 this.el.select('.fc-day-content div',true).setHeight(34);
16717 showPrevMonth : function(e){
16718 this.update(this.activeDate.add("mo", -1));
16720 showToday : function(e){
16721 this.update(new Date().clearTime());
16724 showNextMonth : function(e){
16725 this.update(this.activeDate.add("mo", 1));
16729 showPrevYear : function(){
16730 this.update(this.activeDate.add("y", -1));
16734 showNextYear : function(){
16735 this.update(this.activeDate.add("y", 1));
16740 update : function(date)
16742 var vd = this.activeDate;
16743 this.activeDate = date;
16744 // if(vd && this.el){
16745 // var t = date.getTime();
16746 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16747 // Roo.log('using add remove');
16749 // this.fireEvent('monthchange', this, date);
16751 // this.cells.removeClass("fc-state-highlight");
16752 // this.cells.each(function(c){
16753 // if(c.dateValue == t){
16754 // c.addClass("fc-state-highlight");
16755 // setTimeout(function(){
16756 // try{c.dom.firstChild.focus();}catch(e){}
16766 var days = date.getDaysInMonth();
16768 var firstOfMonth = date.getFirstDateOfMonth();
16769 var startingPos = firstOfMonth.getDay()-this.startDay;
16771 if(startingPos < this.startDay){
16775 var pm = date.add(Date.MONTH, -1);
16776 var prevStart = pm.getDaysInMonth()-startingPos;
16778 this.cells = this.el.select('.fc-day',true);
16779 this.textNodes = this.el.query('.fc-day-number');
16780 this.cells.addClassOnOver('fc-state-hover');
16782 var cells = this.cells.elements;
16783 var textEls = this.textNodes;
16785 Roo.each(cells, function(cell){
16786 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16789 days += startingPos;
16791 // convert everything to numbers so it's fast
16792 var day = 86400000;
16793 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16796 //Roo.log(prevStart);
16798 var today = new Date().clearTime().getTime();
16799 var sel = date.clearTime().getTime();
16800 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16801 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16802 var ddMatch = this.disabledDatesRE;
16803 var ddText = this.disabledDatesText;
16804 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16805 var ddaysText = this.disabledDaysText;
16806 var format = this.format;
16808 var setCellClass = function(cal, cell){
16812 //Roo.log('set Cell Class');
16814 var t = d.getTime();
16818 cell.dateValue = t;
16820 cell.className += " fc-today";
16821 cell.className += " fc-state-highlight";
16822 cell.title = cal.todayText;
16825 // disable highlight in other month..
16826 //cell.className += " fc-state-highlight";
16831 cell.className = " fc-state-disabled";
16832 cell.title = cal.minText;
16836 cell.className = " fc-state-disabled";
16837 cell.title = cal.maxText;
16841 if(ddays.indexOf(d.getDay()) != -1){
16842 cell.title = ddaysText;
16843 cell.className = " fc-state-disabled";
16846 if(ddMatch && format){
16847 var fvalue = d.dateFormat(format);
16848 if(ddMatch.test(fvalue)){
16849 cell.title = ddText.replace("%0", fvalue);
16850 cell.className = " fc-state-disabled";
16854 if (!cell.initialClassName) {
16855 cell.initialClassName = cell.dom.className;
16858 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16863 for(; i < startingPos; i++) {
16864 textEls[i].innerHTML = (++prevStart);
16865 d.setDate(d.getDate()+1);
16867 cells[i].className = "fc-past fc-other-month";
16868 setCellClass(this, cells[i]);
16873 for(; i < days; i++){
16874 intDay = i - startingPos + 1;
16875 textEls[i].innerHTML = (intDay);
16876 d.setDate(d.getDate()+1);
16878 cells[i].className = ''; // "x-date-active";
16879 setCellClass(this, cells[i]);
16883 for(; i < 42; i++) {
16884 textEls[i].innerHTML = (++extraDays);
16885 d.setDate(d.getDate()+1);
16887 cells[i].className = "fc-future fc-other-month";
16888 setCellClass(this, cells[i]);
16891 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16893 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16895 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16896 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16898 if(totalRows != 6){
16899 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16900 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16903 this.fireEvent('monthchange', this, date);
16907 if(!this.internalRender){
16908 var main = this.el.dom.firstChild;
16909 var w = main.offsetWidth;
16910 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16911 Roo.fly(main).setWidth(w);
16912 this.internalRender = true;
16913 // opera does not respect the auto grow header center column
16914 // then, after it gets a width opera refuses to recalculate
16915 // without a second pass
16916 if(Roo.isOpera && !this.secondPass){
16917 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16918 this.secondPass = true;
16919 this.update.defer(10, this, [date]);
16926 findCell : function(dt) {
16927 dt = dt.clearTime().getTime();
16929 this.cells.each(function(c){
16930 //Roo.log("check " +c.dateValue + '?=' + dt);
16931 if(c.dateValue == dt){
16941 findCells : function(ev) {
16942 var s = ev.start.clone().clearTime().getTime();
16944 var e= ev.end.clone().clearTime().getTime();
16947 this.cells.each(function(c){
16948 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16950 if(c.dateValue > e){
16953 if(c.dateValue < s){
16962 // findBestRow: function(cells)
16966 // for (var i =0 ; i < cells.length;i++) {
16967 // ret = Math.max(cells[i].rows || 0,ret);
16974 addItem : function(ev)
16976 // look for vertical location slot in
16977 var cells = this.findCells(ev);
16979 // ev.row = this.findBestRow(cells);
16981 // work out the location.
16985 for(var i =0; i < cells.length; i++) {
16987 cells[i].row = cells[0].row;
16990 cells[i].row = cells[i].row + 1;
17000 if (crow.start.getY() == cells[i].getY()) {
17002 crow.end = cells[i];
17019 cells[0].events.push(ev);
17021 this.calevents.push(ev);
17024 clearEvents: function() {
17026 if(!this.calevents){
17030 Roo.each(this.cells.elements, function(c){
17036 Roo.each(this.calevents, function(e) {
17037 Roo.each(e.els, function(el) {
17038 el.un('mouseenter' ,this.onEventEnter, this);
17039 el.un('mouseleave' ,this.onEventLeave, this);
17044 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17050 renderEvents: function()
17054 this.cells.each(function(c) {
17063 if(c.row != c.events.length){
17064 r = 4 - (4 - (c.row - c.events.length));
17067 c.events = ev.slice(0, r);
17068 c.more = ev.slice(r);
17070 if(c.more.length && c.more.length == 1){
17071 c.events.push(c.more.pop());
17074 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17078 this.cells.each(function(c) {
17080 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17083 for (var e = 0; e < c.events.length; e++){
17084 var ev = c.events[e];
17085 var rows = ev.rows;
17087 for(var i = 0; i < rows.length; i++) {
17089 // how many rows should it span..
17092 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17093 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17095 unselectable : "on",
17098 cls: 'fc-event-inner',
17102 // cls: 'fc-event-time',
17103 // html : cells.length > 1 ? '' : ev.time
17107 cls: 'fc-event-title',
17108 html : String.format('{0}', ev.title)
17115 cls: 'ui-resizable-handle ui-resizable-e',
17116 html : '  '
17123 cfg.cls += ' fc-event-start';
17125 if ((i+1) == rows.length) {
17126 cfg.cls += ' fc-event-end';
17129 var ctr = _this.el.select('.fc-event-container',true).first();
17130 var cg = ctr.createChild(cfg);
17132 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17133 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17135 var r = (c.more.length) ? 1 : 0;
17136 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17137 cg.setWidth(ebox.right - sbox.x -2);
17139 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17140 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17141 cg.on('click', _this.onEventClick, _this, ev);
17152 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17153 style : 'position: absolute',
17154 unselectable : "on",
17157 cls: 'fc-event-inner',
17161 cls: 'fc-event-title',
17169 cls: 'ui-resizable-handle ui-resizable-e',
17170 html : '  '
17176 var ctr = _this.el.select('.fc-event-container',true).first();
17177 var cg = ctr.createChild(cfg);
17179 var sbox = c.select('.fc-day-content',true).first().getBox();
17180 var ebox = c.select('.fc-day-content',true).first().getBox();
17182 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17183 cg.setWidth(ebox.right - sbox.x -2);
17185 cg.on('click', _this.onMoreEventClick, _this, c.more);
17195 onEventEnter: function (e, el,event,d) {
17196 this.fireEvent('evententer', this, el, event);
17199 onEventLeave: function (e, el,event,d) {
17200 this.fireEvent('eventleave', this, el, event);
17203 onEventClick: function (e, el,event,d) {
17204 this.fireEvent('eventclick', this, el, event);
17207 onMonthChange: function () {
17211 onMoreEventClick: function(e, el, more)
17215 this.calpopover.placement = 'right';
17216 this.calpopover.setTitle('More');
17218 this.calpopover.setContent('');
17220 var ctr = this.calpopover.el.select('.popover-content', true).first();
17222 Roo.each(more, function(m){
17224 cls : 'fc-event-hori fc-event-draggable',
17227 var cg = ctr.createChild(cfg);
17229 cg.on('click', _this.onEventClick, _this, m);
17232 this.calpopover.show(el);
17237 onLoad: function ()
17239 this.calevents = [];
17242 if(this.store.getCount() > 0){
17243 this.store.data.each(function(d){
17246 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17247 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17248 time : d.data.start_time,
17249 title : d.data.title,
17250 description : d.data.description,
17251 venue : d.data.venue
17256 this.renderEvents();
17258 if(this.calevents.length && this.loadMask){
17259 this.maskEl.hide();
17263 onBeforeLoad: function()
17265 this.clearEvents();
17267 this.maskEl.show();
17281 * @class Roo.bootstrap.Popover
17282 * @extends Roo.bootstrap.Component
17283 * Bootstrap Popover class
17284 * @cfg {String} html contents of the popover (or false to use children..)
17285 * @cfg {String} title of popover (or false to hide)
17286 * @cfg {String} placement how it is placed
17287 * @cfg {String} trigger click || hover (or false to trigger manually)
17288 * @cfg {String} over what (parent or false to trigger manually.)
17289 * @cfg {Number} delay - delay before showing
17292 * Create a new Popover
17293 * @param {Object} config The config object
17296 Roo.bootstrap.Popover = function(config){
17297 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17303 * After the popover show
17305 * @param {Roo.bootstrap.Popover} this
17310 * After the popover hide
17312 * @param {Roo.bootstrap.Popover} this
17318 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17320 title: 'Fill in a title',
17323 placement : 'right',
17324 trigger : 'hover', // hover
17330 can_build_overlaid : false,
17332 getChildContainer : function()
17334 return this.el.select('.popover-content',true).first();
17337 getAutoCreate : function(){
17340 cls : 'popover roo-dynamic',
17341 style: 'display:block',
17347 cls : 'popover-inner',
17351 cls: 'popover-title',
17355 cls : 'popover-content',
17366 setTitle: function(str)
17369 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17371 setContent: function(str)
17374 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17376 // as it get's added to the bottom of the page.
17377 onRender : function(ct, position)
17379 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17381 var cfg = Roo.apply({}, this.getAutoCreate());
17385 cfg.cls += ' ' + this.cls;
17388 cfg.style = this.style;
17390 //Roo.log("adding to ");
17391 this.el = Roo.get(document.body).createChild(cfg, position);
17392 // Roo.log(this.el);
17397 initEvents : function()
17399 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17400 this.el.enableDisplayMode('block');
17402 if (this.over === false) {
17405 if (this.triggers === false) {
17408 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17409 var triggers = this.trigger ? this.trigger.split(' ') : [];
17410 Roo.each(triggers, function(trigger) {
17412 if (trigger == 'click') {
17413 on_el.on('click', this.toggle, this);
17414 } else if (trigger != 'manual') {
17415 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17416 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17418 on_el.on(eventIn ,this.enter, this);
17419 on_el.on(eventOut, this.leave, this);
17430 toggle : function () {
17431 this.hoverState == 'in' ? this.leave() : this.enter();
17434 enter : function () {
17436 clearTimeout(this.timeout);
17438 this.hoverState = 'in';
17440 if (!this.delay || !this.delay.show) {
17445 this.timeout = setTimeout(function () {
17446 if (_t.hoverState == 'in') {
17449 }, this.delay.show)
17452 leave : function() {
17453 clearTimeout(this.timeout);
17455 this.hoverState = 'out';
17457 if (!this.delay || !this.delay.hide) {
17462 this.timeout = setTimeout(function () {
17463 if (_t.hoverState == 'out') {
17466 }, this.delay.hide)
17469 show : function (on_el)
17472 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17476 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17477 if (this.html !== false) {
17478 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17480 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17481 if (!this.title.length) {
17482 this.el.select('.popover-title',true).hide();
17485 var placement = typeof this.placement == 'function' ?
17486 this.placement.call(this, this.el, on_el) :
17489 var autoToken = /\s?auto?\s?/i;
17490 var autoPlace = autoToken.test(placement);
17492 placement = placement.replace(autoToken, '') || 'top';
17496 //this.el.setXY([0,0]);
17498 this.el.dom.style.display='block';
17499 this.el.addClass(placement);
17501 //this.el.appendTo(on_el);
17503 var p = this.getPosition();
17504 var box = this.el.getBox();
17509 var align = Roo.bootstrap.Popover.alignment[placement];
17512 this.el.alignTo(on_el, align[0],align[1]);
17513 //var arrow = this.el.select('.arrow',true).first();
17514 //arrow.set(align[2],
17516 this.el.addClass('in');
17519 if (this.el.hasClass('fade')) {
17523 this.hoverState = 'in';
17525 this.fireEvent('show', this);
17530 this.el.setXY([0,0]);
17531 this.el.removeClass('in');
17533 this.hoverState = null;
17535 this.fireEvent('hide', this);
17540 Roo.bootstrap.Popover.alignment = {
17541 'left' : ['r-l', [-10,0], 'right'],
17542 'right' : ['l-r', [10,0], 'left'],
17543 'bottom' : ['t-b', [0,10], 'top'],
17544 'top' : [ 'b-t', [0,-10], 'bottom']
17555 * @class Roo.bootstrap.Progress
17556 * @extends Roo.bootstrap.Component
17557 * Bootstrap Progress class
17558 * @cfg {Boolean} striped striped of the progress bar
17559 * @cfg {Boolean} active animated of the progress bar
17563 * Create a new Progress
17564 * @param {Object} config The config object
17567 Roo.bootstrap.Progress = function(config){
17568 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17571 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17576 getAutoCreate : function(){
17584 cfg.cls += ' progress-striped';
17588 cfg.cls += ' active';
17607 * @class Roo.bootstrap.ProgressBar
17608 * @extends Roo.bootstrap.Component
17609 * Bootstrap ProgressBar class
17610 * @cfg {Number} aria_valuenow aria-value now
17611 * @cfg {Number} aria_valuemin aria-value min
17612 * @cfg {Number} aria_valuemax aria-value max
17613 * @cfg {String} label label for the progress bar
17614 * @cfg {String} panel (success | info | warning | danger )
17615 * @cfg {String} role role of the progress bar
17616 * @cfg {String} sr_only text
17620 * Create a new ProgressBar
17621 * @param {Object} config The config object
17624 Roo.bootstrap.ProgressBar = function(config){
17625 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17628 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17632 aria_valuemax : 100,
17638 getAutoCreate : function()
17643 cls: 'progress-bar',
17644 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17656 cfg.role = this.role;
17659 if(this.aria_valuenow){
17660 cfg['aria-valuenow'] = this.aria_valuenow;
17663 if(this.aria_valuemin){
17664 cfg['aria-valuemin'] = this.aria_valuemin;
17667 if(this.aria_valuemax){
17668 cfg['aria-valuemax'] = this.aria_valuemax;
17671 if(this.label && !this.sr_only){
17672 cfg.html = this.label;
17676 cfg.cls += ' progress-bar-' + this.panel;
17682 update : function(aria_valuenow)
17684 this.aria_valuenow = aria_valuenow;
17686 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17701 * @class Roo.bootstrap.TabGroup
17702 * @extends Roo.bootstrap.Column
17703 * Bootstrap Column class
17704 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17705 * @cfg {Boolean} carousel true to make the group behave like a carousel
17706 * @cfg {Boolean} bullets show bullets for the panels
17707 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17708 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17709 * @cfg {Boolean} showarrow (true|false) show arrow default true
17712 * Create a new TabGroup
17713 * @param {Object} config The config object
17716 Roo.bootstrap.TabGroup = function(config){
17717 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17719 this.navId = Roo.id();
17722 Roo.bootstrap.TabGroup.register(this);
17726 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17729 transition : false,
17734 slideOnTouch : false,
17737 getAutoCreate : function()
17739 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17741 cfg.cls += ' tab-content';
17743 if (this.carousel) {
17744 cfg.cls += ' carousel slide';
17747 cls : 'carousel-inner',
17751 if(this.bullets && !Roo.isTouch){
17754 cls : 'carousel-bullets',
17758 if(this.bullets_cls){
17759 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17766 cfg.cn[0].cn.push(bullets);
17769 if(this.showarrow){
17770 cfg.cn[0].cn.push({
17772 class : 'carousel-arrow',
17776 class : 'carousel-prev',
17780 class : 'fa fa-chevron-left'
17786 class : 'carousel-next',
17790 class : 'fa fa-chevron-right'
17803 initEvents: function()
17805 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17806 // this.el.on("touchstart", this.onTouchStart, this);
17809 if(this.autoslide){
17812 this.slideFn = window.setInterval(function() {
17813 _this.showPanelNext();
17817 if(this.showarrow){
17818 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17819 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17825 // onTouchStart : function(e, el, o)
17827 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17831 // this.showPanelNext();
17835 getChildContainer : function()
17837 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17841 * register a Navigation item
17842 * @param {Roo.bootstrap.NavItem} the navitem to add
17844 register : function(item)
17846 this.tabs.push( item);
17847 item.navId = this.navId; // not really needed..
17852 getActivePanel : function()
17855 Roo.each(this.tabs, function(t) {
17865 getPanelByName : function(n)
17868 Roo.each(this.tabs, function(t) {
17869 if (t.tabId == n) {
17877 indexOfPanel : function(p)
17880 Roo.each(this.tabs, function(t,i) {
17881 if (t.tabId == p.tabId) {
17890 * show a specific panel
17891 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17892 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17894 showPanel : function (pan)
17896 if(this.transition || typeof(pan) == 'undefined'){
17897 Roo.log("waiting for the transitionend");
17901 if (typeof(pan) == 'number') {
17902 pan = this.tabs[pan];
17905 if (typeof(pan) == 'string') {
17906 pan = this.getPanelByName(pan);
17909 var cur = this.getActivePanel();
17912 Roo.log('pan or acitve pan is undefined');
17916 if (pan.tabId == this.getActivePanel().tabId) {
17920 if (false === cur.fireEvent('beforedeactivate')) {
17924 if(this.bullets > 0 && !Roo.isTouch){
17925 this.setActiveBullet(this.indexOfPanel(pan));
17928 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17930 this.transition = true;
17931 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17932 var lr = dir == 'next' ? 'left' : 'right';
17933 pan.el.addClass(dir); // or prev
17934 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17935 cur.el.addClass(lr); // or right
17936 pan.el.addClass(lr);
17939 cur.el.on('transitionend', function() {
17940 Roo.log("trans end?");
17942 pan.el.removeClass([lr,dir]);
17943 pan.setActive(true);
17945 cur.el.removeClass([lr]);
17946 cur.setActive(false);
17948 _this.transition = false;
17950 }, this, { single: true } );
17955 cur.setActive(false);
17956 pan.setActive(true);
17961 showPanelNext : function()
17963 var i = this.indexOfPanel(this.getActivePanel());
17965 if (i >= this.tabs.length - 1 && !this.autoslide) {
17969 if (i >= this.tabs.length - 1 && this.autoslide) {
17973 this.showPanel(this.tabs[i+1]);
17976 showPanelPrev : function()
17978 var i = this.indexOfPanel(this.getActivePanel());
17980 if (i < 1 && !this.autoslide) {
17984 if (i < 1 && this.autoslide) {
17985 i = this.tabs.length;
17988 this.showPanel(this.tabs[i-1]);
17992 addBullet: function()
17994 if(!this.bullets || Roo.isTouch){
17997 var ctr = this.el.select('.carousel-bullets',true).first();
17998 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17999 var bullet = ctr.createChild({
18000 cls : 'bullet bullet-' + i
18001 },ctr.dom.lastChild);
18006 bullet.on('click', (function(e, el, o, ii, t){
18008 e.preventDefault();
18010 this.showPanel(ii);
18012 if(this.autoslide && this.slideFn){
18013 clearInterval(this.slideFn);
18014 this.slideFn = window.setInterval(function() {
18015 _this.showPanelNext();
18019 }).createDelegate(this, [i, bullet], true));
18024 setActiveBullet : function(i)
18030 Roo.each(this.el.select('.bullet', true).elements, function(el){
18031 el.removeClass('selected');
18034 var bullet = this.el.select('.bullet-' + i, true).first();
18040 bullet.addClass('selected');
18051 Roo.apply(Roo.bootstrap.TabGroup, {
18055 * register a Navigation Group
18056 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18058 register : function(navgrp)
18060 this.groups[navgrp.navId] = navgrp;
18064 * fetch a Navigation Group based on the navigation ID
18065 * if one does not exist , it will get created.
18066 * @param {string} the navgroup to add
18067 * @returns {Roo.bootstrap.NavGroup} the navgroup
18069 get: function(navId) {
18070 if (typeof(this.groups[navId]) == 'undefined') {
18071 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18073 return this.groups[navId] ;
18088 * @class Roo.bootstrap.TabPanel
18089 * @extends Roo.bootstrap.Component
18090 * Bootstrap TabPanel class
18091 * @cfg {Boolean} active panel active
18092 * @cfg {String} html panel content
18093 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18094 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18095 * @cfg {String} href click to link..
18099 * Create a new TabPanel
18100 * @param {Object} config The config object
18103 Roo.bootstrap.TabPanel = function(config){
18104 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18108 * Fires when the active status changes
18109 * @param {Roo.bootstrap.TabPanel} this
18110 * @param {Boolean} state the new state
18115 * @event beforedeactivate
18116 * Fires before a tab is de-activated - can be used to do validation on a form.
18117 * @param {Roo.bootstrap.TabPanel} this
18118 * @return {Boolean} false if there is an error
18121 'beforedeactivate': true
18124 this.tabId = this.tabId || Roo.id();
18128 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18136 getAutoCreate : function(){
18139 // item is needed for carousel - not sure if it has any effect otherwise
18140 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18141 html: this.html || ''
18145 cfg.cls += ' active';
18149 cfg.tabId = this.tabId;
18156 initEvents: function()
18158 var p = this.parent();
18160 this.navId = this.navId || p.navId;
18162 if (typeof(this.navId) != 'undefined') {
18163 // not really needed.. but just in case.. parent should be a NavGroup.
18164 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18168 var i = tg.tabs.length - 1;
18170 if(this.active && tg.bullets > 0 && i < tg.bullets){
18171 tg.setActiveBullet(i);
18175 this.el.on('click', this.onClick, this);
18178 this.el.on("touchstart", this.onTouchStart, this);
18179 this.el.on("touchmove", this.onTouchMove, this);
18180 this.el.on("touchend", this.onTouchEnd, this);
18185 onRender : function(ct, position)
18187 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18190 setActive : function(state)
18192 Roo.log("panel - set active " + this.tabId + "=" + state);
18194 this.active = state;
18196 this.el.removeClass('active');
18198 } else if (!this.el.hasClass('active')) {
18199 this.el.addClass('active');
18202 this.fireEvent('changed', this, state);
18205 onClick : function(e)
18207 e.preventDefault();
18209 if(!this.href.length){
18213 window.location.href = this.href;
18222 onTouchStart : function(e)
18224 this.swiping = false;
18226 this.startX = e.browserEvent.touches[0].clientX;
18227 this.startY = e.browserEvent.touches[0].clientY;
18230 onTouchMove : function(e)
18232 this.swiping = true;
18234 this.endX = e.browserEvent.touches[0].clientX;
18235 this.endY = e.browserEvent.touches[0].clientY;
18238 onTouchEnd : function(e)
18245 var tabGroup = this.parent();
18247 if(this.endX > this.startX){ // swiping right
18248 tabGroup.showPanelPrev();
18252 if(this.startX > this.endX){ // swiping left
18253 tabGroup.showPanelNext();
18272 * @class Roo.bootstrap.DateField
18273 * @extends Roo.bootstrap.Input
18274 * Bootstrap DateField class
18275 * @cfg {Number} weekStart default 0
18276 * @cfg {String} viewMode default empty, (months|years)
18277 * @cfg {String} minViewMode default empty, (months|years)
18278 * @cfg {Number} startDate default -Infinity
18279 * @cfg {Number} endDate default Infinity
18280 * @cfg {Boolean} todayHighlight default false
18281 * @cfg {Boolean} todayBtn default false
18282 * @cfg {Boolean} calendarWeeks default false
18283 * @cfg {Object} daysOfWeekDisabled default empty
18284 * @cfg {Boolean} singleMode default false (true | false)
18286 * @cfg {Boolean} keyboardNavigation default true
18287 * @cfg {String} language default en
18290 * Create a new DateField
18291 * @param {Object} config The config object
18294 Roo.bootstrap.DateField = function(config){
18295 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18299 * Fires when this field show.
18300 * @param {Roo.bootstrap.DateField} this
18301 * @param {Mixed} date The date value
18306 * Fires when this field hide.
18307 * @param {Roo.bootstrap.DateField} this
18308 * @param {Mixed} date The date value
18313 * Fires when select a date.
18314 * @param {Roo.bootstrap.DateField} this
18315 * @param {Mixed} date The date value
18319 * @event beforeselect
18320 * Fires when before select a date.
18321 * @param {Roo.bootstrap.DateField} this
18322 * @param {Mixed} date The date value
18324 beforeselect : true
18328 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18331 * @cfg {String} format
18332 * The default date format string which can be overriden for localization support. The format must be
18333 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18337 * @cfg {String} altFormats
18338 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18339 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18341 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18349 todayHighlight : false,
18355 keyboardNavigation: true,
18357 calendarWeeks: false,
18359 startDate: -Infinity,
18363 daysOfWeekDisabled: [],
18367 singleMode : false,
18369 UTCDate: function()
18371 return new Date(Date.UTC.apply(Date, arguments));
18374 UTCToday: function()
18376 var today = new Date();
18377 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18380 getDate: function() {
18381 var d = this.getUTCDate();
18382 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18385 getUTCDate: function() {
18389 setDate: function(d) {
18390 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18393 setUTCDate: function(d) {
18395 this.setValue(this.formatDate(this.date));
18398 onRender: function(ct, position)
18401 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18403 this.language = this.language || 'en';
18404 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18405 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18407 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18408 this.format = this.format || 'm/d/y';
18409 this.isInline = false;
18410 this.isInput = true;
18411 this.component = this.el.select('.add-on', true).first() || false;
18412 this.component = (this.component && this.component.length === 0) ? false : this.component;
18413 this.hasInput = this.component && this.inputEl().length;
18415 if (typeof(this.minViewMode === 'string')) {
18416 switch (this.minViewMode) {
18418 this.minViewMode = 1;
18421 this.minViewMode = 2;
18424 this.minViewMode = 0;
18429 if (typeof(this.viewMode === 'string')) {
18430 switch (this.viewMode) {
18443 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18445 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18447 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18449 this.picker().on('mousedown', this.onMousedown, this);
18450 this.picker().on('click', this.onClick, this);
18452 this.picker().addClass('datepicker-dropdown');
18454 this.startViewMode = this.viewMode;
18456 if(this.singleMode){
18457 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18458 v.setVisibilityMode(Roo.Element.DISPLAY);
18462 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18463 v.setStyle('width', '189px');
18467 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18468 if(!this.calendarWeeks){
18473 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18474 v.attr('colspan', function(i, val){
18475 return parseInt(val) + 1;
18480 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18482 this.setStartDate(this.startDate);
18483 this.setEndDate(this.endDate);
18485 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18492 if(this.isInline) {
18497 picker : function()
18499 return this.pickerEl;
18500 // return this.el.select('.datepicker', true).first();
18503 fillDow: function()
18505 var dowCnt = this.weekStart;
18514 if(this.calendarWeeks){
18522 while (dowCnt < this.weekStart + 7) {
18526 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18530 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18533 fillMonths: function()
18536 var months = this.picker().select('>.datepicker-months td', true).first();
18538 months.dom.innerHTML = '';
18544 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18547 months.createChild(month);
18554 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;
18556 if (this.date < this.startDate) {
18557 this.viewDate = new Date(this.startDate);
18558 } else if (this.date > this.endDate) {
18559 this.viewDate = new Date(this.endDate);
18561 this.viewDate = new Date(this.date);
18569 var d = new Date(this.viewDate),
18570 year = d.getUTCFullYear(),
18571 month = d.getUTCMonth(),
18572 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18573 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18574 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18575 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18576 currentDate = this.date && this.date.valueOf(),
18577 today = this.UTCToday();
18579 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18581 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18583 // this.picker.select('>tfoot th.today').
18584 // .text(dates[this.language].today)
18585 // .toggle(this.todayBtn !== false);
18587 this.updateNavArrows();
18590 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18592 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18594 prevMonth.setUTCDate(day);
18596 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18598 var nextMonth = new Date(prevMonth);
18600 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18602 nextMonth = nextMonth.valueOf();
18604 var fillMonths = false;
18606 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18608 while(prevMonth.valueOf() < nextMonth) {
18611 if (prevMonth.getUTCDay() === this.weekStart) {
18613 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18621 if(this.calendarWeeks){
18622 // ISO 8601: First week contains first thursday.
18623 // ISO also states week starts on Monday, but we can be more abstract here.
18625 // Start of current week: based on weekstart/current date
18626 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18627 // Thursday of this week
18628 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18629 // First Thursday of year, year from thursday
18630 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18631 // Calendar week: ms between thursdays, div ms per day, div 7 days
18632 calWeek = (th - yth) / 864e5 / 7 + 1;
18634 fillMonths.cn.push({
18642 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18644 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18647 if (this.todayHighlight &&
18648 prevMonth.getUTCFullYear() == today.getFullYear() &&
18649 prevMonth.getUTCMonth() == today.getMonth() &&
18650 prevMonth.getUTCDate() == today.getDate()) {
18651 clsName += ' today';
18654 if (currentDate && prevMonth.valueOf() === currentDate) {
18655 clsName += ' active';
18658 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18659 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18660 clsName += ' disabled';
18663 fillMonths.cn.push({
18665 cls: 'day ' + clsName,
18666 html: prevMonth.getDate()
18669 prevMonth.setDate(prevMonth.getDate()+1);
18672 var currentYear = this.date && this.date.getUTCFullYear();
18673 var currentMonth = this.date && this.date.getUTCMonth();
18675 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18677 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18678 v.removeClass('active');
18680 if(currentYear === year && k === currentMonth){
18681 v.addClass('active');
18684 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18685 v.addClass('disabled');
18691 year = parseInt(year/10, 10) * 10;
18693 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18695 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18698 for (var i = -1; i < 11; i++) {
18699 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18701 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18709 showMode: function(dir)
18712 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18715 Roo.each(this.picker().select('>div',true).elements, function(v){
18716 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18719 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18724 if(this.isInline) {
18728 this.picker().removeClass(['bottom', 'top']);
18730 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18732 * place to the top of element!
18736 this.picker().addClass('top');
18737 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18742 this.picker().addClass('bottom');
18744 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18747 parseDate : function(value)
18749 if(!value || value instanceof Date){
18752 var v = Date.parseDate(value, this.format);
18753 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18754 v = Date.parseDate(value, 'Y-m-d');
18756 if(!v && this.altFormats){
18757 if(!this.altFormatsArray){
18758 this.altFormatsArray = this.altFormats.split("|");
18760 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18761 v = Date.parseDate(value, this.altFormatsArray[i]);
18767 formatDate : function(date, fmt)
18769 return (!date || !(date instanceof Date)) ?
18770 date : date.dateFormat(fmt || this.format);
18773 onFocus : function()
18775 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18779 onBlur : function()
18781 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18783 var d = this.inputEl().getValue();
18792 this.picker().show();
18796 this.fireEvent('show', this, this.date);
18801 if(this.isInline) {
18804 this.picker().hide();
18805 this.viewMode = this.startViewMode;
18808 this.fireEvent('hide', this, this.date);
18812 onMousedown: function(e)
18814 e.stopPropagation();
18815 e.preventDefault();
18820 Roo.bootstrap.DateField.superclass.keyup.call(this);
18824 setValue: function(v)
18826 if(this.fireEvent('beforeselect', this, v) !== false){
18827 var d = new Date(this.parseDate(v) ).clearTime();
18829 if(isNaN(d.getTime())){
18830 this.date = this.viewDate = '';
18831 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18835 v = this.formatDate(d);
18837 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18839 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18843 this.fireEvent('select', this, this.date);
18847 getValue: function()
18849 return this.formatDate(this.date);
18852 fireKey: function(e)
18854 if (!this.picker().isVisible()){
18855 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18861 var dateChanged = false,
18863 newDate, newViewDate;
18868 e.preventDefault();
18872 if (!this.keyboardNavigation) {
18875 dir = e.keyCode == 37 ? -1 : 1;
18878 newDate = this.moveYear(this.date, dir);
18879 newViewDate = this.moveYear(this.viewDate, dir);
18880 } else if (e.shiftKey){
18881 newDate = this.moveMonth(this.date, dir);
18882 newViewDate = this.moveMonth(this.viewDate, dir);
18884 newDate = new Date(this.date);
18885 newDate.setUTCDate(this.date.getUTCDate() + dir);
18886 newViewDate = new Date(this.viewDate);
18887 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18889 if (this.dateWithinRange(newDate)){
18890 this.date = newDate;
18891 this.viewDate = newViewDate;
18892 this.setValue(this.formatDate(this.date));
18894 e.preventDefault();
18895 dateChanged = true;
18900 if (!this.keyboardNavigation) {
18903 dir = e.keyCode == 38 ? -1 : 1;
18905 newDate = this.moveYear(this.date, dir);
18906 newViewDate = this.moveYear(this.viewDate, dir);
18907 } else if (e.shiftKey){
18908 newDate = this.moveMonth(this.date, dir);
18909 newViewDate = this.moveMonth(this.viewDate, dir);
18911 newDate = new Date(this.date);
18912 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18913 newViewDate = new Date(this.viewDate);
18914 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18916 if (this.dateWithinRange(newDate)){
18917 this.date = newDate;
18918 this.viewDate = newViewDate;
18919 this.setValue(this.formatDate(this.date));
18921 e.preventDefault();
18922 dateChanged = true;
18926 this.setValue(this.formatDate(this.date));
18928 e.preventDefault();
18931 this.setValue(this.formatDate(this.date));
18945 onClick: function(e)
18947 e.stopPropagation();
18948 e.preventDefault();
18950 var target = e.getTarget();
18952 if(target.nodeName.toLowerCase() === 'i'){
18953 target = Roo.get(target).dom.parentNode;
18956 var nodeName = target.nodeName;
18957 var className = target.className;
18958 var html = target.innerHTML;
18959 //Roo.log(nodeName);
18961 switch(nodeName.toLowerCase()) {
18963 switch(className) {
18969 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18970 switch(this.viewMode){
18972 this.viewDate = this.moveMonth(this.viewDate, dir);
18976 this.viewDate = this.moveYear(this.viewDate, dir);
18982 var date = new Date();
18983 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18985 this.setValue(this.formatDate(this.date));
18992 if (className.indexOf('disabled') < 0) {
18993 this.viewDate.setUTCDate(1);
18994 if (className.indexOf('month') > -1) {
18995 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18997 var year = parseInt(html, 10) || 0;
18998 this.viewDate.setUTCFullYear(year);
19002 if(this.singleMode){
19003 this.setValue(this.formatDate(this.viewDate));
19014 //Roo.log(className);
19015 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19016 var day = parseInt(html, 10) || 1;
19017 var year = this.viewDate.getUTCFullYear(),
19018 month = this.viewDate.getUTCMonth();
19020 if (className.indexOf('old') > -1) {
19027 } else if (className.indexOf('new') > -1) {
19035 //Roo.log([year,month,day]);
19036 this.date = this.UTCDate(year, month, day,0,0,0,0);
19037 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19039 //Roo.log(this.formatDate(this.date));
19040 this.setValue(this.formatDate(this.date));
19047 setStartDate: function(startDate)
19049 this.startDate = startDate || -Infinity;
19050 if (this.startDate !== -Infinity) {
19051 this.startDate = this.parseDate(this.startDate);
19054 this.updateNavArrows();
19057 setEndDate: function(endDate)
19059 this.endDate = endDate || Infinity;
19060 if (this.endDate !== Infinity) {
19061 this.endDate = this.parseDate(this.endDate);
19064 this.updateNavArrows();
19067 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19069 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19070 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19071 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19073 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19074 return parseInt(d, 10);
19077 this.updateNavArrows();
19080 updateNavArrows: function()
19082 if(this.singleMode){
19086 var d = new Date(this.viewDate),
19087 year = d.getUTCFullYear(),
19088 month = d.getUTCMonth();
19090 Roo.each(this.picker().select('.prev', true).elements, function(v){
19092 switch (this.viewMode) {
19095 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19101 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19108 Roo.each(this.picker().select('.next', true).elements, function(v){
19110 switch (this.viewMode) {
19113 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19119 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19127 moveMonth: function(date, dir)
19132 var new_date = new Date(date.valueOf()),
19133 day = new_date.getUTCDate(),
19134 month = new_date.getUTCMonth(),
19135 mag = Math.abs(dir),
19137 dir = dir > 0 ? 1 : -1;
19140 // If going back one month, make sure month is not current month
19141 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19143 return new_date.getUTCMonth() == month;
19145 // If going forward one month, make sure month is as expected
19146 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19148 return new_date.getUTCMonth() != new_month;
19150 new_month = month + dir;
19151 new_date.setUTCMonth(new_month);
19152 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19153 if (new_month < 0 || new_month > 11) {
19154 new_month = (new_month + 12) % 12;
19157 // For magnitudes >1, move one month at a time...
19158 for (var i=0; i<mag; i++) {
19159 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19160 new_date = this.moveMonth(new_date, dir);
19162 // ...then reset the day, keeping it in the new month
19163 new_month = new_date.getUTCMonth();
19164 new_date.setUTCDate(day);
19166 return new_month != new_date.getUTCMonth();
19169 // Common date-resetting loop -- if date is beyond end of month, make it
19172 new_date.setUTCDate(--day);
19173 new_date.setUTCMonth(new_month);
19178 moveYear: function(date, dir)
19180 return this.moveMonth(date, dir*12);
19183 dateWithinRange: function(date)
19185 return date >= this.startDate && date <= this.endDate;
19191 this.picker().remove();
19194 validateValue : function(value)
19196 if(this.getVisibilityEl().hasClass('hidden')){
19200 if(value.length < 1) {
19201 if(this.allowBlank){
19207 if(value.length < this.minLength){
19210 if(value.length > this.maxLength){
19214 var vt = Roo.form.VTypes;
19215 if(!vt[this.vtype](value, this)){
19219 if(typeof this.validator == "function"){
19220 var msg = this.validator(value);
19226 if(this.regex && !this.regex.test(value)){
19230 if(typeof(this.parseDate(value)) == 'undefined'){
19234 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19238 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19246 setVisible : function(visible)
19252 this.getEl().removeClass('hidden');
19258 this.getEl().addClass('hidden');
19263 Roo.apply(Roo.bootstrap.DateField, {
19274 html: '<i class="fa fa-arrow-left"/>'
19284 html: '<i class="fa fa-arrow-right"/>'
19326 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19327 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19328 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19329 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19330 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19343 navFnc: 'FullYear',
19348 navFnc: 'FullYear',
19353 Roo.apply(Roo.bootstrap.DateField, {
19357 cls: 'datepicker dropdown-menu roo-dynamic',
19361 cls: 'datepicker-days',
19365 cls: 'table-condensed',
19367 Roo.bootstrap.DateField.head,
19371 Roo.bootstrap.DateField.footer
19378 cls: 'datepicker-months',
19382 cls: 'table-condensed',
19384 Roo.bootstrap.DateField.head,
19385 Roo.bootstrap.DateField.content,
19386 Roo.bootstrap.DateField.footer
19393 cls: 'datepicker-years',
19397 cls: 'table-condensed',
19399 Roo.bootstrap.DateField.head,
19400 Roo.bootstrap.DateField.content,
19401 Roo.bootstrap.DateField.footer
19420 * @class Roo.bootstrap.TimeField
19421 * @extends Roo.bootstrap.Input
19422 * Bootstrap DateField class
19426 * Create a new TimeField
19427 * @param {Object} config The config object
19430 Roo.bootstrap.TimeField = function(config){
19431 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19435 * Fires when this field show.
19436 * @param {Roo.bootstrap.DateField} thisthis
19437 * @param {Mixed} date The date value
19442 * Fires when this field hide.
19443 * @param {Roo.bootstrap.DateField} this
19444 * @param {Mixed} date The date value
19449 * Fires when select a date.
19450 * @param {Roo.bootstrap.DateField} this
19451 * @param {Mixed} date The date value
19457 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19460 * @cfg {String} format
19461 * The default time format string which can be overriden for localization support. The format must be
19462 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19466 onRender: function(ct, position)
19469 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19471 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19473 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19475 this.pop = this.picker().select('>.datepicker-time',true).first();
19476 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19478 this.picker().on('mousedown', this.onMousedown, this);
19479 this.picker().on('click', this.onClick, this);
19481 this.picker().addClass('datepicker-dropdown');
19486 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19487 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19488 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19489 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19490 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19491 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19495 fireKey: function(e){
19496 if (!this.picker().isVisible()){
19497 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19503 e.preventDefault();
19511 this.onTogglePeriod();
19514 this.onIncrementMinutes();
19517 this.onDecrementMinutes();
19526 onClick: function(e) {
19527 e.stopPropagation();
19528 e.preventDefault();
19531 picker : function()
19533 return this.el.select('.datepicker', true).first();
19536 fillTime: function()
19538 var time = this.pop.select('tbody', true).first();
19540 time.dom.innerHTML = '';
19555 cls: 'hours-up glyphicon glyphicon-chevron-up'
19575 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19596 cls: 'timepicker-hour',
19611 cls: 'timepicker-minute',
19626 cls: 'btn btn-primary period',
19648 cls: 'hours-down glyphicon glyphicon-chevron-down'
19668 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19686 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19693 var hours = this.time.getHours();
19694 var minutes = this.time.getMinutes();
19707 hours = hours - 12;
19711 hours = '0' + hours;
19715 minutes = '0' + minutes;
19718 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19719 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19720 this.pop.select('button', true).first().dom.innerHTML = period;
19726 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19728 var cls = ['bottom'];
19730 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19737 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19742 this.picker().addClass(cls.join('-'));
19746 Roo.each(cls, function(c){
19748 _this.picker().setTop(_this.inputEl().getHeight());
19752 _this.picker().setTop(0 - _this.picker().getHeight());
19757 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19761 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19768 onFocus : function()
19770 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19774 onBlur : function()
19776 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19782 this.picker().show();
19787 this.fireEvent('show', this, this.date);
19792 this.picker().hide();
19795 this.fireEvent('hide', this, this.date);
19798 setTime : function()
19801 this.setValue(this.time.format(this.format));
19803 this.fireEvent('select', this, this.date);
19808 onMousedown: function(e){
19809 e.stopPropagation();
19810 e.preventDefault();
19813 onIncrementHours: function()
19815 Roo.log('onIncrementHours');
19816 this.time = this.time.add(Date.HOUR, 1);
19821 onDecrementHours: function()
19823 Roo.log('onDecrementHours');
19824 this.time = this.time.add(Date.HOUR, -1);
19828 onIncrementMinutes: function()
19830 Roo.log('onIncrementMinutes');
19831 this.time = this.time.add(Date.MINUTE, 1);
19835 onDecrementMinutes: function()
19837 Roo.log('onDecrementMinutes');
19838 this.time = this.time.add(Date.MINUTE, -1);
19842 onTogglePeriod: function()
19844 Roo.log('onTogglePeriod');
19845 this.time = this.time.add(Date.HOUR, 12);
19852 Roo.apply(Roo.bootstrap.TimeField, {
19882 cls: 'btn btn-info ok',
19894 Roo.apply(Roo.bootstrap.TimeField, {
19898 cls: 'datepicker dropdown-menu',
19902 cls: 'datepicker-time',
19906 cls: 'table-condensed',
19908 Roo.bootstrap.TimeField.content,
19909 Roo.bootstrap.TimeField.footer
19928 * @class Roo.bootstrap.MonthField
19929 * @extends Roo.bootstrap.Input
19930 * Bootstrap MonthField class
19932 * @cfg {String} language default en
19935 * Create a new MonthField
19936 * @param {Object} config The config object
19939 Roo.bootstrap.MonthField = function(config){
19940 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19945 * Fires when this field show.
19946 * @param {Roo.bootstrap.MonthField} this
19947 * @param {Mixed} date The date value
19952 * Fires when this field hide.
19953 * @param {Roo.bootstrap.MonthField} this
19954 * @param {Mixed} date The date value
19959 * Fires when select a date.
19960 * @param {Roo.bootstrap.MonthField} this
19961 * @param {String} oldvalue The old value
19962 * @param {String} newvalue The new value
19968 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19970 onRender: function(ct, position)
19973 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19975 this.language = this.language || 'en';
19976 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19977 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19979 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19980 this.isInline = false;
19981 this.isInput = true;
19982 this.component = this.el.select('.add-on', true).first() || false;
19983 this.component = (this.component && this.component.length === 0) ? false : this.component;
19984 this.hasInput = this.component && this.inputEL().length;
19986 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19988 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19990 this.picker().on('mousedown', this.onMousedown, this);
19991 this.picker().on('click', this.onClick, this);
19993 this.picker().addClass('datepicker-dropdown');
19995 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19996 v.setStyle('width', '189px');
20003 if(this.isInline) {
20009 setValue: function(v, suppressEvent)
20011 var o = this.getValue();
20013 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20017 if(suppressEvent !== true){
20018 this.fireEvent('select', this, o, v);
20023 getValue: function()
20028 onClick: function(e)
20030 e.stopPropagation();
20031 e.preventDefault();
20033 var target = e.getTarget();
20035 if(target.nodeName.toLowerCase() === 'i'){
20036 target = Roo.get(target).dom.parentNode;
20039 var nodeName = target.nodeName;
20040 var className = target.className;
20041 var html = target.innerHTML;
20043 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20047 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20049 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20055 picker : function()
20057 return this.pickerEl;
20060 fillMonths: function()
20063 var months = this.picker().select('>.datepicker-months td', true).first();
20065 months.dom.innerHTML = '';
20071 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20074 months.createChild(month);
20083 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20084 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20087 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20088 e.removeClass('active');
20090 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20091 e.addClass('active');
20098 if(this.isInline) {
20102 this.picker().removeClass(['bottom', 'top']);
20104 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20106 * place to the top of element!
20110 this.picker().addClass('top');
20111 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20116 this.picker().addClass('bottom');
20118 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20121 onFocus : function()
20123 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20127 onBlur : function()
20129 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20131 var d = this.inputEl().getValue();
20140 this.picker().show();
20141 this.picker().select('>.datepicker-months', true).first().show();
20145 this.fireEvent('show', this, this.date);
20150 if(this.isInline) {
20153 this.picker().hide();
20154 this.fireEvent('hide', this, this.date);
20158 onMousedown: function(e)
20160 e.stopPropagation();
20161 e.preventDefault();
20166 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20170 fireKey: function(e)
20172 if (!this.picker().isVisible()){
20173 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20184 e.preventDefault();
20188 dir = e.keyCode == 37 ? -1 : 1;
20190 this.vIndex = this.vIndex + dir;
20192 if(this.vIndex < 0){
20196 if(this.vIndex > 11){
20200 if(isNaN(this.vIndex)){
20204 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20210 dir = e.keyCode == 38 ? -1 : 1;
20212 this.vIndex = this.vIndex + dir * 4;
20214 if(this.vIndex < 0){
20218 if(this.vIndex > 11){
20222 if(isNaN(this.vIndex)){
20226 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20231 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20232 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20236 e.preventDefault();
20239 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20240 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20256 this.picker().remove();
20261 Roo.apply(Roo.bootstrap.MonthField, {
20280 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20281 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20286 Roo.apply(Roo.bootstrap.MonthField, {
20290 cls: 'datepicker dropdown-menu roo-dynamic',
20294 cls: 'datepicker-months',
20298 cls: 'table-condensed',
20300 Roo.bootstrap.DateField.content
20320 * @class Roo.bootstrap.CheckBox
20321 * @extends Roo.bootstrap.Input
20322 * Bootstrap CheckBox class
20324 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20325 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20326 * @cfg {String} boxLabel The text that appears beside the checkbox
20327 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20328 * @cfg {Boolean} checked initnal the element
20329 * @cfg {Boolean} inline inline the element (default false)
20330 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20331 * @cfg {String} tooltip label tooltip
20334 * Create a new CheckBox
20335 * @param {Object} config The config object
20338 Roo.bootstrap.CheckBox = function(config){
20339 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20344 * Fires when the element is checked or unchecked.
20345 * @param {Roo.bootstrap.CheckBox} this This input
20346 * @param {Boolean} checked The new checked value
20351 * Fires when the element is click.
20352 * @param {Roo.bootstrap.CheckBox} this This input
20359 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20361 inputType: 'checkbox',
20370 getAutoCreate : function()
20372 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20378 cfg.cls = 'form-group ' + this.inputType; //input-group
20381 cfg.cls += ' ' + this.inputType + '-inline';
20387 type : this.inputType,
20388 value : this.inputValue,
20389 cls : 'roo-' + this.inputType, //'form-box',
20390 placeholder : this.placeholder || ''
20394 if(this.inputType != 'radio'){
20398 cls : 'roo-hidden-value',
20399 value : this.checked ? this.inputValue : this.valueOff
20404 if (this.weight) { // Validity check?
20405 cfg.cls += " " + this.inputType + "-" + this.weight;
20408 if (this.disabled) {
20409 input.disabled=true;
20413 input.checked = this.checked;
20418 input.name = this.name;
20420 if(this.inputType != 'radio'){
20421 hidden.name = this.name;
20422 input.name = '_hidden_' + this.name;
20427 input.cls += ' input-' + this.size;
20432 ['xs','sm','md','lg'].map(function(size){
20433 if (settings[size]) {
20434 cfg.cls += ' col-' + size + '-' + settings[size];
20438 var inputblock = input;
20440 if (this.before || this.after) {
20443 cls : 'input-group',
20448 inputblock.cn.push({
20450 cls : 'input-group-addon',
20455 inputblock.cn.push(input);
20457 if(this.inputType != 'radio'){
20458 inputblock.cn.push(hidden);
20462 inputblock.cn.push({
20464 cls : 'input-group-addon',
20471 if (align ==='left' && this.fieldLabel.length) {
20472 // Roo.log("left and has label");
20477 cls : 'control-label',
20478 html : this.fieldLabel
20488 if(this.labelWidth > 12){
20489 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20492 if(this.labelWidth < 13 && this.labelmd == 0){
20493 this.labelmd = this.labelWidth;
20496 if(this.labellg > 0){
20497 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20498 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20501 if(this.labelmd > 0){
20502 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20503 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20506 if(this.labelsm > 0){
20507 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20508 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20511 if(this.labelxs > 0){
20512 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20513 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20516 } else if ( this.fieldLabel.length) {
20517 // Roo.log(" label");
20521 tag: this.boxLabel ? 'span' : 'label',
20523 cls: 'control-label box-input-label',
20524 //cls : 'input-group-addon',
20525 html : this.fieldLabel
20534 // Roo.log(" no label && no align");
20535 cfg.cn = [ inputblock ] ;
20541 var boxLabelCfg = {
20543 //'for': id, // box label is handled by onclick - so no for...
20545 html: this.boxLabel
20549 boxLabelCfg.tooltip = this.tooltip;
20552 cfg.cn.push(boxLabelCfg);
20555 if(this.inputType != 'radio'){
20556 cfg.cn.push(hidden);
20564 * return the real input element.
20566 inputEl: function ()
20568 return this.el.select('input.roo-' + this.inputType,true).first();
20570 hiddenEl: function ()
20572 return this.el.select('input.roo-hidden-value',true).first();
20575 labelEl: function()
20577 return this.el.select('label.control-label',true).first();
20579 /* depricated... */
20583 return this.labelEl();
20586 boxLabelEl: function()
20588 return this.el.select('label.box-label',true).first();
20591 initEvents : function()
20593 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20595 this.inputEl().on('click', this.onClick, this);
20597 if (this.boxLabel) {
20598 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20601 this.startValue = this.getValue();
20604 Roo.bootstrap.CheckBox.register(this);
20608 onClick : function(e)
20610 if(this.fireEvent('click', this, e) !== false){
20611 this.setChecked(!this.checked);
20616 setChecked : function(state,suppressEvent)
20618 this.startValue = this.getValue();
20620 if(this.inputType == 'radio'){
20622 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20623 e.dom.checked = false;
20626 this.inputEl().dom.checked = true;
20628 this.inputEl().dom.value = this.inputValue;
20630 if(suppressEvent !== true){
20631 this.fireEvent('check', this, true);
20639 this.checked = state;
20641 this.inputEl().dom.checked = state;
20644 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20646 if(suppressEvent !== true){
20647 this.fireEvent('check', this, state);
20653 getValue : function()
20655 if(this.inputType == 'radio'){
20656 return this.getGroupValue();
20659 return this.hiddenEl().dom.value;
20663 getGroupValue : function()
20665 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20669 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20672 setValue : function(v,suppressEvent)
20674 if(this.inputType == 'radio'){
20675 this.setGroupValue(v, suppressEvent);
20679 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20684 setGroupValue : function(v, suppressEvent)
20686 this.startValue = this.getValue();
20688 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20689 e.dom.checked = false;
20691 if(e.dom.value == v){
20692 e.dom.checked = true;
20696 if(suppressEvent !== true){
20697 this.fireEvent('check', this, true);
20705 validate : function()
20707 if(this.getVisibilityEl().hasClass('hidden')){
20713 (this.inputType == 'radio' && this.validateRadio()) ||
20714 (this.inputType == 'checkbox' && this.validateCheckbox())
20720 this.markInvalid();
20724 validateRadio : function()
20726 if(this.getVisibilityEl().hasClass('hidden')){
20730 if(this.allowBlank){
20736 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20737 if(!e.dom.checked){
20749 validateCheckbox : function()
20752 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20753 //return (this.getValue() == this.inputValue) ? true : false;
20756 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20764 for(var i in group){
20765 if(group[i].el.isVisible(true)){
20773 for(var i in group){
20778 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20785 * Mark this field as valid
20787 markValid : function()
20791 this.fireEvent('valid', this);
20793 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20796 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20803 if(this.inputType == 'radio'){
20804 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20805 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20806 e.findParent('.form-group', false, true).addClass(_this.validClass);
20813 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20814 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20818 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20824 for(var i in group){
20825 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20826 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20831 * Mark this field as invalid
20832 * @param {String} msg The validation message
20834 markInvalid : function(msg)
20836 if(this.allowBlank){
20842 this.fireEvent('invalid', this, msg);
20844 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20847 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20851 label.markInvalid();
20854 if(this.inputType == 'radio'){
20855 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20856 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20857 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20864 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20865 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20869 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20875 for(var i in group){
20876 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20877 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20882 clearInvalid : function()
20884 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20886 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20888 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20890 if (label && label.iconEl) {
20891 label.iconEl.removeClass(label.validClass);
20892 label.iconEl.removeClass(label.invalidClass);
20896 disable : function()
20898 if(this.inputType != 'radio'){
20899 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20906 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20907 _this.getActionEl().addClass(this.disabledClass);
20908 e.dom.disabled = true;
20912 this.disabled = true;
20913 this.fireEvent("disable", this);
20917 enable : function()
20919 if(this.inputType != 'radio'){
20920 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20927 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20928 _this.getActionEl().removeClass(this.disabledClass);
20929 e.dom.disabled = false;
20933 this.disabled = false;
20934 this.fireEvent("enable", this);
20938 setBoxLabel : function(v)
20943 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20949 Roo.apply(Roo.bootstrap.CheckBox, {
20954 * register a CheckBox Group
20955 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20957 register : function(checkbox)
20959 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20960 this.groups[checkbox.groupId] = {};
20963 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20967 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20971 * fetch a CheckBox Group based on the group ID
20972 * @param {string} the group ID
20973 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20975 get: function(groupId) {
20976 if (typeof(this.groups[groupId]) == 'undefined') {
20980 return this.groups[groupId] ;
20993 * @class Roo.bootstrap.Radio
20994 * @extends Roo.bootstrap.Component
20995 * Bootstrap Radio class
20996 * @cfg {String} boxLabel - the label associated
20997 * @cfg {String} value - the value of radio
21000 * Create a new Radio
21001 * @param {Object} config The config object
21003 Roo.bootstrap.Radio = function(config){
21004 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21008 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21014 getAutoCreate : function()
21018 cls : 'form-group radio',
21023 html : this.boxLabel
21031 initEvents : function()
21033 this.parent().register(this);
21035 this.el.on('click', this.onClick, this);
21039 onClick : function(e)
21041 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21042 this.setChecked(true);
21046 setChecked : function(state, suppressEvent)
21048 this.parent().setValue(this.value, suppressEvent);
21052 setBoxLabel : function(v)
21057 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21072 * @class Roo.bootstrap.SecurePass
21073 * @extends Roo.bootstrap.Input
21074 * Bootstrap SecurePass class
21078 * Create a new SecurePass
21079 * @param {Object} config The config object
21082 Roo.bootstrap.SecurePass = function (config) {
21083 // these go here, so the translation tool can replace them..
21085 PwdEmpty: "Please type a password, and then retype it to confirm.",
21086 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21087 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21088 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21089 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21090 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21091 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21092 TooWeak: "Your password is Too Weak."
21094 this.meterLabel = "Password strength:";
21095 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21096 this.meterClass = [
21097 "roo-password-meter-tooweak",
21098 "roo-password-meter-weak",
21099 "roo-password-meter-medium",
21100 "roo-password-meter-strong",
21101 "roo-password-meter-grey"
21106 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21109 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21111 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21113 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21114 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21115 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21116 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21117 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21118 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21119 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21129 * @cfg {String/Object} Label for the strength meter (defaults to
21130 * 'Password strength:')
21135 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21136 * ['Weak', 'Medium', 'Strong'])
21139 pwdStrengths: false,
21152 initEvents: function ()
21154 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21156 if (this.el.is('input[type=password]') && Roo.isSafari) {
21157 this.el.on('keydown', this.SafariOnKeyDown, this);
21160 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21163 onRender: function (ct, position)
21165 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21166 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21167 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21169 this.trigger.createChild({
21174 cls: 'roo-password-meter-grey col-xs-12',
21177 //width: this.meterWidth + 'px'
21181 cls: 'roo-password-meter-text'
21187 if (this.hideTrigger) {
21188 this.trigger.setDisplayed(false);
21190 this.setSize(this.width || '', this.height || '');
21193 onDestroy: function ()
21195 if (this.trigger) {
21196 this.trigger.removeAllListeners();
21197 this.trigger.remove();
21200 this.wrap.remove();
21202 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21205 checkStrength: function ()
21207 var pwd = this.inputEl().getValue();
21208 if (pwd == this._lastPwd) {
21213 if (this.ClientSideStrongPassword(pwd)) {
21215 } else if (this.ClientSideMediumPassword(pwd)) {
21217 } else if (this.ClientSideWeakPassword(pwd)) {
21223 Roo.log('strength1: ' + strength);
21225 //var pm = this.trigger.child('div/div/div').dom;
21226 var pm = this.trigger.child('div/div');
21227 pm.removeClass(this.meterClass);
21228 pm.addClass(this.meterClass[strength]);
21231 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21233 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21235 this._lastPwd = pwd;
21239 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21241 this._lastPwd = '';
21243 var pm = this.trigger.child('div/div');
21244 pm.removeClass(this.meterClass);
21245 pm.addClass('roo-password-meter-grey');
21248 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21251 this.inputEl().dom.type='password';
21254 validateValue: function (value)
21257 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21260 if (value.length == 0) {
21261 if (this.allowBlank) {
21262 this.clearInvalid();
21266 this.markInvalid(this.errors.PwdEmpty);
21267 this.errorMsg = this.errors.PwdEmpty;
21275 if ('[\x21-\x7e]*'.match(value)) {
21276 this.markInvalid(this.errors.PwdBadChar);
21277 this.errorMsg = this.errors.PwdBadChar;
21280 if (value.length < 6) {
21281 this.markInvalid(this.errors.PwdShort);
21282 this.errorMsg = this.errors.PwdShort;
21285 if (value.length > 16) {
21286 this.markInvalid(this.errors.PwdLong);
21287 this.errorMsg = this.errors.PwdLong;
21291 if (this.ClientSideStrongPassword(value)) {
21293 } else if (this.ClientSideMediumPassword(value)) {
21295 } else if (this.ClientSideWeakPassword(value)) {
21302 if (strength < 2) {
21303 //this.markInvalid(this.errors.TooWeak);
21304 this.errorMsg = this.errors.TooWeak;
21309 console.log('strength2: ' + strength);
21311 //var pm = this.trigger.child('div/div/div').dom;
21313 var pm = this.trigger.child('div/div');
21314 pm.removeClass(this.meterClass);
21315 pm.addClass(this.meterClass[strength]);
21317 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21319 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21321 this.errorMsg = '';
21325 CharacterSetChecks: function (type)
21328 this.fResult = false;
21331 isctype: function (character, type)
21334 case this.kCapitalLetter:
21335 if (character >= 'A' && character <= 'Z') {
21340 case this.kSmallLetter:
21341 if (character >= 'a' && character <= 'z') {
21347 if (character >= '0' && character <= '9') {
21352 case this.kPunctuation:
21353 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21364 IsLongEnough: function (pwd, size)
21366 return !(pwd == null || isNaN(size) || pwd.length < size);
21369 SpansEnoughCharacterSets: function (word, nb)
21371 if (!this.IsLongEnough(word, nb))
21376 var characterSetChecks = new Array(
21377 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21378 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21381 for (var index = 0; index < word.length; ++index) {
21382 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21383 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21384 characterSetChecks[nCharSet].fResult = true;
21391 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21392 if (characterSetChecks[nCharSet].fResult) {
21397 if (nCharSets < nb) {
21403 ClientSideStrongPassword: function (pwd)
21405 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21408 ClientSideMediumPassword: function (pwd)
21410 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21413 ClientSideWeakPassword: function (pwd)
21415 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21418 })//<script type="text/javascript">
21421 * Based Ext JS Library 1.1.1
21422 * Copyright(c) 2006-2007, Ext JS, LLC.
21428 * @class Roo.HtmlEditorCore
21429 * @extends Roo.Component
21430 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21432 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21435 Roo.HtmlEditorCore = function(config){
21438 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21443 * @event initialize
21444 * Fires when the editor is fully initialized (including the iframe)
21445 * @param {Roo.HtmlEditorCore} this
21450 * Fires when the editor is first receives the focus. Any insertion must wait
21451 * until after this event.
21452 * @param {Roo.HtmlEditorCore} this
21456 * @event beforesync
21457 * Fires before the textarea is updated with content from the editor iframe. Return false
21458 * to cancel the sync.
21459 * @param {Roo.HtmlEditorCore} this
21460 * @param {String} html
21464 * @event beforepush
21465 * Fires before the iframe editor is updated with content from the textarea. Return false
21466 * to cancel the push.
21467 * @param {Roo.HtmlEditorCore} this
21468 * @param {String} html
21473 * Fires when the textarea is updated with content from the editor iframe.
21474 * @param {Roo.HtmlEditorCore} this
21475 * @param {String} html
21480 * Fires when the iframe editor is updated with content from the textarea.
21481 * @param {Roo.HtmlEditorCore} this
21482 * @param {String} html
21487 * @event editorevent
21488 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21489 * @param {Roo.HtmlEditorCore} this
21495 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21497 // defaults : white / black...
21498 this.applyBlacklists();
21505 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21509 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21515 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21520 * @cfg {Number} height (in pixels)
21524 * @cfg {Number} width (in pixels)
21529 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21532 stylesheets: false,
21537 // private properties
21538 validationEvent : false,
21540 initialized : false,
21542 sourceEditMode : false,
21543 onFocus : Roo.emptyFn,
21545 hideMode:'offsets',
21549 // blacklist + whitelisted elements..
21556 * Protected method that will not generally be called directly. It
21557 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21558 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21560 getDocMarkup : function(){
21564 // inherit styels from page...??
21565 if (this.stylesheets === false) {
21567 Roo.get(document.head).select('style').each(function(node) {
21568 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21571 Roo.get(document.head).select('link').each(function(node) {
21572 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21575 } else if (!this.stylesheets.length) {
21577 st = '<style type="text/css">' +
21578 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21581 st = '<style type="text/css">' +
21586 st += '<style type="text/css">' +
21587 'IMG { cursor: pointer } ' +
21590 var cls = 'roo-htmleditor-body';
21592 if(this.bodyCls.length){
21593 cls += ' ' + this.bodyCls;
21596 return '<html><head>' + st +
21597 //<style type="text/css">' +
21598 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21600 ' </head><body class="' + cls + '"></body></html>';
21604 onRender : function(ct, position)
21607 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21608 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21611 this.el.dom.style.border = '0 none';
21612 this.el.dom.setAttribute('tabIndex', -1);
21613 this.el.addClass('x-hidden hide');
21617 if(Roo.isIE){ // fix IE 1px bogus margin
21618 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21622 this.frameId = Roo.id();
21626 var iframe = this.owner.wrap.createChild({
21628 cls: 'form-control', // bootstrap..
21630 name: this.frameId,
21631 frameBorder : 'no',
21632 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21637 this.iframe = iframe.dom;
21639 this.assignDocWin();
21641 this.doc.designMode = 'on';
21644 this.doc.write(this.getDocMarkup());
21648 var task = { // must defer to wait for browser to be ready
21650 //console.log("run task?" + this.doc.readyState);
21651 this.assignDocWin();
21652 if(this.doc.body || this.doc.readyState == 'complete'){
21654 this.doc.designMode="on";
21658 Roo.TaskMgr.stop(task);
21659 this.initEditor.defer(10, this);
21666 Roo.TaskMgr.start(task);
21671 onResize : function(w, h)
21673 Roo.log('resize: ' +w + ',' + h );
21674 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21678 if(typeof w == 'number'){
21680 this.iframe.style.width = w + 'px';
21682 if(typeof h == 'number'){
21684 this.iframe.style.height = h + 'px';
21686 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21693 * Toggles the editor between standard and source edit mode.
21694 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21696 toggleSourceEdit : function(sourceEditMode){
21698 this.sourceEditMode = sourceEditMode === true;
21700 if(this.sourceEditMode){
21702 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21705 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21706 //this.iframe.className = '';
21709 //this.setSize(this.owner.wrap.getSize());
21710 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21717 * Protected method that will not generally be called directly. If you need/want
21718 * custom HTML cleanup, this is the method you should override.
21719 * @param {String} html The HTML to be cleaned
21720 * return {String} The cleaned HTML
21722 cleanHtml : function(html){
21723 html = String(html);
21724 if(html.length > 5){
21725 if(Roo.isSafari){ // strip safari nonsense
21726 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21729 if(html == ' '){
21736 * HTML Editor -> Textarea
21737 * Protected method that will not generally be called directly. Syncs the contents
21738 * of the editor iframe with the textarea.
21740 syncValue : function(){
21741 if(this.initialized){
21742 var bd = (this.doc.body || this.doc.documentElement);
21743 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21744 var html = bd.innerHTML;
21746 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21747 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21749 html = '<div style="'+m[0]+'">' + html + '</div>';
21752 html = this.cleanHtml(html);
21753 // fix up the special chars.. normaly like back quotes in word...
21754 // however we do not want to do this with chinese..
21755 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21756 var cc = b.charCodeAt();
21758 (cc >= 0x4E00 && cc < 0xA000 ) ||
21759 (cc >= 0x3400 && cc < 0x4E00 ) ||
21760 (cc >= 0xf900 && cc < 0xfb00 )
21766 if(this.owner.fireEvent('beforesync', this, html) !== false){
21767 this.el.dom.value = html;
21768 this.owner.fireEvent('sync', this, html);
21774 * Protected method that will not generally be called directly. Pushes the value of the textarea
21775 * into the iframe editor.
21777 pushValue : function(){
21778 if(this.initialized){
21779 var v = this.el.dom.value.trim();
21781 // if(v.length < 1){
21785 if(this.owner.fireEvent('beforepush', this, v) !== false){
21786 var d = (this.doc.body || this.doc.documentElement);
21788 this.cleanUpPaste();
21789 this.el.dom.value = d.innerHTML;
21790 this.owner.fireEvent('push', this, v);
21796 deferFocus : function(){
21797 this.focus.defer(10, this);
21801 focus : function(){
21802 if(this.win && !this.sourceEditMode){
21809 assignDocWin: function()
21811 var iframe = this.iframe;
21814 this.doc = iframe.contentWindow.document;
21815 this.win = iframe.contentWindow;
21817 // if (!Roo.get(this.frameId)) {
21820 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21821 // this.win = Roo.get(this.frameId).dom.contentWindow;
21823 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21827 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21828 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21833 initEditor : function(){
21834 //console.log("INIT EDITOR");
21835 this.assignDocWin();
21839 this.doc.designMode="on";
21841 this.doc.write(this.getDocMarkup());
21844 var dbody = (this.doc.body || this.doc.documentElement);
21845 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21846 // this copies styles from the containing element into thsi one..
21847 // not sure why we need all of this..
21848 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21850 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21851 //ss['background-attachment'] = 'fixed'; // w3c
21852 dbody.bgProperties = 'fixed'; // ie
21853 //Roo.DomHelper.applyStyles(dbody, ss);
21854 Roo.EventManager.on(this.doc, {
21855 //'mousedown': this.onEditorEvent,
21856 'mouseup': this.onEditorEvent,
21857 'dblclick': this.onEditorEvent,
21858 'click': this.onEditorEvent,
21859 'keyup': this.onEditorEvent,
21864 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21866 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21867 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21869 this.initialized = true;
21871 this.owner.fireEvent('initialize', this);
21876 onDestroy : function(){
21882 //for (var i =0; i < this.toolbars.length;i++) {
21883 // // fixme - ask toolbars for heights?
21884 // this.toolbars[i].onDestroy();
21887 //this.wrap.dom.innerHTML = '';
21888 //this.wrap.remove();
21893 onFirstFocus : function(){
21895 this.assignDocWin();
21898 this.activated = true;
21901 if(Roo.isGecko){ // prevent silly gecko errors
21903 var s = this.win.getSelection();
21904 if(!s.focusNode || s.focusNode.nodeType != 3){
21905 var r = s.getRangeAt(0);
21906 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21911 this.execCmd('useCSS', true);
21912 this.execCmd('styleWithCSS', false);
21915 this.owner.fireEvent('activate', this);
21919 adjustFont: function(btn){
21920 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21921 //if(Roo.isSafari){ // safari
21924 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21925 if(Roo.isSafari){ // safari
21926 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21927 v = (v < 10) ? 10 : v;
21928 v = (v > 48) ? 48 : v;
21929 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21934 v = Math.max(1, v+adjust);
21936 this.execCmd('FontSize', v );
21939 onEditorEvent : function(e)
21941 this.owner.fireEvent('editorevent', this, e);
21942 // this.updateToolbar();
21943 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21946 insertTag : function(tg)
21948 // could be a bit smarter... -> wrap the current selected tRoo..
21949 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21951 range = this.createRange(this.getSelection());
21952 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21953 wrappingNode.appendChild(range.extractContents());
21954 range.insertNode(wrappingNode);
21961 this.execCmd("formatblock", tg);
21965 insertText : function(txt)
21969 var range = this.createRange();
21970 range.deleteContents();
21971 //alert(Sender.getAttribute('label'));
21973 range.insertNode(this.doc.createTextNode(txt));
21979 * Executes a Midas editor command on the editor document and performs necessary focus and
21980 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21981 * @param {String} cmd The Midas command
21982 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21984 relayCmd : function(cmd, value){
21986 this.execCmd(cmd, value);
21987 this.owner.fireEvent('editorevent', this);
21988 //this.updateToolbar();
21989 this.owner.deferFocus();
21993 * Executes a Midas editor command directly on the editor document.
21994 * For visual commands, you should use {@link #relayCmd} instead.
21995 * <b>This should only be called after the editor is initialized.</b>
21996 * @param {String} cmd The Midas command
21997 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21999 execCmd : function(cmd, value){
22000 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22007 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22009 * @param {String} text | dom node..
22011 insertAtCursor : function(text)
22014 if(!this.activated){
22020 var r = this.doc.selection.createRange();
22031 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22035 // from jquery ui (MIT licenced)
22037 var win = this.win;
22039 if (win.getSelection && win.getSelection().getRangeAt) {
22040 range = win.getSelection().getRangeAt(0);
22041 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22042 range.insertNode(node);
22043 } else if (win.document.selection && win.document.selection.createRange) {
22044 // no firefox support
22045 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22046 win.document.selection.createRange().pasteHTML(txt);
22048 // no firefox support
22049 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22050 this.execCmd('InsertHTML', txt);
22059 mozKeyPress : function(e){
22061 var c = e.getCharCode(), cmd;
22064 c = String.fromCharCode(c).toLowerCase();
22078 this.cleanUpPaste.defer(100, this);
22086 e.preventDefault();
22094 fixKeys : function(){ // load time branching for fastest keydown performance
22096 return function(e){
22097 var k = e.getKey(), r;
22100 r = this.doc.selection.createRange();
22103 r.pasteHTML('    ');
22110 r = this.doc.selection.createRange();
22112 var target = r.parentElement();
22113 if(!target || target.tagName.toLowerCase() != 'li'){
22115 r.pasteHTML('<br />');
22121 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22122 this.cleanUpPaste.defer(100, this);
22128 }else if(Roo.isOpera){
22129 return function(e){
22130 var k = e.getKey();
22134 this.execCmd('InsertHTML','    ');
22137 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22138 this.cleanUpPaste.defer(100, this);
22143 }else if(Roo.isSafari){
22144 return function(e){
22145 var k = e.getKey();
22149 this.execCmd('InsertText','\t');
22153 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22154 this.cleanUpPaste.defer(100, this);
22162 getAllAncestors: function()
22164 var p = this.getSelectedNode();
22167 a.push(p); // push blank onto stack..
22168 p = this.getParentElement();
22172 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22176 a.push(this.doc.body);
22180 lastSelNode : false,
22183 getSelection : function()
22185 this.assignDocWin();
22186 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22189 getSelectedNode: function()
22191 // this may only work on Gecko!!!
22193 // should we cache this!!!!
22198 var range = this.createRange(this.getSelection()).cloneRange();
22201 var parent = range.parentElement();
22203 var testRange = range.duplicate();
22204 testRange.moveToElementText(parent);
22205 if (testRange.inRange(range)) {
22208 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22211 parent = parent.parentElement;
22216 // is ancestor a text element.
22217 var ac = range.commonAncestorContainer;
22218 if (ac.nodeType == 3) {
22219 ac = ac.parentNode;
22222 var ar = ac.childNodes;
22225 var other_nodes = [];
22226 var has_other_nodes = false;
22227 for (var i=0;i<ar.length;i++) {
22228 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22231 // fullly contained node.
22233 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22238 // probably selected..
22239 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22240 other_nodes.push(ar[i]);
22244 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22249 has_other_nodes = true;
22251 if (!nodes.length && other_nodes.length) {
22252 nodes= other_nodes;
22254 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22260 createRange: function(sel)
22262 // this has strange effects when using with
22263 // top toolbar - not sure if it's a great idea.
22264 //this.editor.contentWindow.focus();
22265 if (typeof sel != "undefined") {
22267 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22269 return this.doc.createRange();
22272 return this.doc.createRange();
22275 getParentElement: function()
22278 this.assignDocWin();
22279 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22281 var range = this.createRange(sel);
22284 var p = range.commonAncestorContainer;
22285 while (p.nodeType == 3) { // text node
22296 * Range intersection.. the hard stuff...
22300 * [ -- selected range --- ]
22304 * if end is before start or hits it. fail.
22305 * if start is after end or hits it fail.
22307 * if either hits (but other is outside. - then it's not
22313 // @see http://www.thismuchiknow.co.uk/?p=64.
22314 rangeIntersectsNode : function(range, node)
22316 var nodeRange = node.ownerDocument.createRange();
22318 nodeRange.selectNode(node);
22320 nodeRange.selectNodeContents(node);
22323 var rangeStartRange = range.cloneRange();
22324 rangeStartRange.collapse(true);
22326 var rangeEndRange = range.cloneRange();
22327 rangeEndRange.collapse(false);
22329 var nodeStartRange = nodeRange.cloneRange();
22330 nodeStartRange.collapse(true);
22332 var nodeEndRange = nodeRange.cloneRange();
22333 nodeEndRange.collapse(false);
22335 return rangeStartRange.compareBoundaryPoints(
22336 Range.START_TO_START, nodeEndRange) == -1 &&
22337 rangeEndRange.compareBoundaryPoints(
22338 Range.START_TO_START, nodeStartRange) == 1;
22342 rangeCompareNode : function(range, node)
22344 var nodeRange = node.ownerDocument.createRange();
22346 nodeRange.selectNode(node);
22348 nodeRange.selectNodeContents(node);
22352 range.collapse(true);
22354 nodeRange.collapse(true);
22356 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22357 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22359 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22361 var nodeIsBefore = ss == 1;
22362 var nodeIsAfter = ee == -1;
22364 if (nodeIsBefore && nodeIsAfter) {
22367 if (!nodeIsBefore && nodeIsAfter) {
22368 return 1; //right trailed.
22371 if (nodeIsBefore && !nodeIsAfter) {
22372 return 2; // left trailed.
22378 // private? - in a new class?
22379 cleanUpPaste : function()
22381 // cleans up the whole document..
22382 Roo.log('cleanuppaste');
22384 this.cleanUpChildren(this.doc.body);
22385 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22386 if (clean != this.doc.body.innerHTML) {
22387 this.doc.body.innerHTML = clean;
22392 cleanWordChars : function(input) {// change the chars to hex code
22393 var he = Roo.HtmlEditorCore;
22395 var output = input;
22396 Roo.each(he.swapCodes, function(sw) {
22397 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22399 output = output.replace(swapper, sw[1]);
22406 cleanUpChildren : function (n)
22408 if (!n.childNodes.length) {
22411 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22412 this.cleanUpChild(n.childNodes[i]);
22419 cleanUpChild : function (node)
22422 //console.log(node);
22423 if (node.nodeName == "#text") {
22424 // clean up silly Windows -- stuff?
22427 if (node.nodeName == "#comment") {
22428 node.parentNode.removeChild(node);
22429 // clean up silly Windows -- stuff?
22432 var lcname = node.tagName.toLowerCase();
22433 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22434 // whitelist of tags..
22436 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22438 node.parentNode.removeChild(node);
22443 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22445 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22446 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22448 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22449 // remove_keep_children = true;
22452 if (remove_keep_children) {
22453 this.cleanUpChildren(node);
22454 // inserts everything just before this node...
22455 while (node.childNodes.length) {
22456 var cn = node.childNodes[0];
22457 node.removeChild(cn);
22458 node.parentNode.insertBefore(cn, node);
22460 node.parentNode.removeChild(node);
22464 if (!node.attributes || !node.attributes.length) {
22465 this.cleanUpChildren(node);
22469 function cleanAttr(n,v)
22472 if (v.match(/^\./) || v.match(/^\//)) {
22475 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22478 if (v.match(/^#/)) {
22481 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22482 node.removeAttribute(n);
22486 var cwhite = this.cwhite;
22487 var cblack = this.cblack;
22489 function cleanStyle(n,v)
22491 if (v.match(/expression/)) { //XSS?? should we even bother..
22492 node.removeAttribute(n);
22496 var parts = v.split(/;/);
22499 Roo.each(parts, function(p) {
22500 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22504 var l = p.split(':').shift().replace(/\s+/g,'');
22505 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22507 if ( cwhite.length && cblack.indexOf(l) > -1) {
22508 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22509 //node.removeAttribute(n);
22513 // only allow 'c whitelisted system attributes'
22514 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22515 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22516 //node.removeAttribute(n);
22526 if (clean.length) {
22527 node.setAttribute(n, clean.join(';'));
22529 node.removeAttribute(n);
22535 for (var i = node.attributes.length-1; i > -1 ; i--) {
22536 var a = node.attributes[i];
22539 if (a.name.toLowerCase().substr(0,2)=='on') {
22540 node.removeAttribute(a.name);
22543 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22544 node.removeAttribute(a.name);
22547 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22548 cleanAttr(a.name,a.value); // fixme..
22551 if (a.name == 'style') {
22552 cleanStyle(a.name,a.value);
22555 /// clean up MS crap..
22556 // tecnically this should be a list of valid class'es..
22559 if (a.name == 'class') {
22560 if (a.value.match(/^Mso/)) {
22561 node.className = '';
22564 if (a.value.match(/^body$/)) {
22565 node.className = '';
22576 this.cleanUpChildren(node);
22582 * Clean up MS wordisms...
22584 cleanWord : function(node)
22589 this.cleanWord(this.doc.body);
22592 if (node.nodeName == "#text") {
22593 // clean up silly Windows -- stuff?
22596 if (node.nodeName == "#comment") {
22597 node.parentNode.removeChild(node);
22598 // clean up silly Windows -- stuff?
22602 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22603 node.parentNode.removeChild(node);
22607 // remove - but keep children..
22608 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22609 while (node.childNodes.length) {
22610 var cn = node.childNodes[0];
22611 node.removeChild(cn);
22612 node.parentNode.insertBefore(cn, node);
22614 node.parentNode.removeChild(node);
22615 this.iterateChildren(node, this.cleanWord);
22619 if (node.className.length) {
22621 var cn = node.className.split(/\W+/);
22623 Roo.each(cn, function(cls) {
22624 if (cls.match(/Mso[a-zA-Z]+/)) {
22629 node.className = cna.length ? cna.join(' ') : '';
22631 node.removeAttribute("class");
22635 if (node.hasAttribute("lang")) {
22636 node.removeAttribute("lang");
22639 if (node.hasAttribute("style")) {
22641 var styles = node.getAttribute("style").split(";");
22643 Roo.each(styles, function(s) {
22644 if (!s.match(/:/)) {
22647 var kv = s.split(":");
22648 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22651 // what ever is left... we allow.
22654 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22655 if (!nstyle.length) {
22656 node.removeAttribute('style');
22659 this.iterateChildren(node, this.cleanWord);
22665 * iterateChildren of a Node, calling fn each time, using this as the scole..
22666 * @param {DomNode} node node to iterate children of.
22667 * @param {Function} fn method of this class to call on each item.
22669 iterateChildren : function(node, fn)
22671 if (!node.childNodes.length) {
22674 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22675 fn.call(this, node.childNodes[i])
22681 * cleanTableWidths.
22683 * Quite often pasting from word etc.. results in tables with column and widths.
22684 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22687 cleanTableWidths : function(node)
22692 this.cleanTableWidths(this.doc.body);
22697 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22700 Roo.log(node.tagName);
22701 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22702 this.iterateChildren(node, this.cleanTableWidths);
22705 if (node.hasAttribute('width')) {
22706 node.removeAttribute('width');
22710 if (node.hasAttribute("style")) {
22713 var styles = node.getAttribute("style").split(";");
22715 Roo.each(styles, function(s) {
22716 if (!s.match(/:/)) {
22719 var kv = s.split(":");
22720 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22723 // what ever is left... we allow.
22726 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22727 if (!nstyle.length) {
22728 node.removeAttribute('style');
22732 this.iterateChildren(node, this.cleanTableWidths);
22740 domToHTML : function(currentElement, depth, nopadtext) {
22742 depth = depth || 0;
22743 nopadtext = nopadtext || false;
22745 if (!currentElement) {
22746 return this.domToHTML(this.doc.body);
22749 //Roo.log(currentElement);
22751 var allText = false;
22752 var nodeName = currentElement.nodeName;
22753 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22755 if (nodeName == '#text') {
22757 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22762 if (nodeName != 'BODY') {
22765 // Prints the node tagName, such as <A>, <IMG>, etc
22768 for(i = 0; i < currentElement.attributes.length;i++) {
22770 var aname = currentElement.attributes.item(i).name;
22771 if (!currentElement.attributes.item(i).value.length) {
22774 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22777 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22786 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22789 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22794 // Traverse the tree
22796 var currentElementChild = currentElement.childNodes.item(i);
22797 var allText = true;
22798 var innerHTML = '';
22800 while (currentElementChild) {
22801 // Formatting code (indent the tree so it looks nice on the screen)
22802 var nopad = nopadtext;
22803 if (lastnode == 'SPAN') {
22807 if (currentElementChild.nodeName == '#text') {
22808 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22809 toadd = nopadtext ? toadd : toadd.trim();
22810 if (!nopad && toadd.length > 80) {
22811 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22813 innerHTML += toadd;
22816 currentElementChild = currentElement.childNodes.item(i);
22822 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22824 // Recursively traverse the tree structure of the child node
22825 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22826 lastnode = currentElementChild.nodeName;
22828 currentElementChild=currentElement.childNodes.item(i);
22834 // The remaining code is mostly for formatting the tree
22835 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22840 ret+= "</"+tagName+">";
22846 applyBlacklists : function()
22848 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22849 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22853 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22854 if (b.indexOf(tag) > -1) {
22857 this.white.push(tag);
22861 Roo.each(w, function(tag) {
22862 if (b.indexOf(tag) > -1) {
22865 if (this.white.indexOf(tag) > -1) {
22868 this.white.push(tag);
22873 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22874 if (w.indexOf(tag) > -1) {
22877 this.black.push(tag);
22881 Roo.each(b, function(tag) {
22882 if (w.indexOf(tag) > -1) {
22885 if (this.black.indexOf(tag) > -1) {
22888 this.black.push(tag);
22893 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22894 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22898 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22899 if (b.indexOf(tag) > -1) {
22902 this.cwhite.push(tag);
22906 Roo.each(w, function(tag) {
22907 if (b.indexOf(tag) > -1) {
22910 if (this.cwhite.indexOf(tag) > -1) {
22913 this.cwhite.push(tag);
22918 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22919 if (w.indexOf(tag) > -1) {
22922 this.cblack.push(tag);
22926 Roo.each(b, function(tag) {
22927 if (w.indexOf(tag) > -1) {
22930 if (this.cblack.indexOf(tag) > -1) {
22933 this.cblack.push(tag);
22938 setStylesheets : function(stylesheets)
22940 if(typeof(stylesheets) == 'string'){
22941 Roo.get(this.iframe.contentDocument.head).createChild({
22943 rel : 'stylesheet',
22952 Roo.each(stylesheets, function(s) {
22957 Roo.get(_this.iframe.contentDocument.head).createChild({
22959 rel : 'stylesheet',
22968 removeStylesheets : function()
22972 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22977 setStyle : function(style)
22979 Roo.get(this.iframe.contentDocument.head).createChild({
22988 // hide stuff that is not compatible
23002 * @event specialkey
23006 * @cfg {String} fieldClass @hide
23009 * @cfg {String} focusClass @hide
23012 * @cfg {String} autoCreate @hide
23015 * @cfg {String} inputType @hide
23018 * @cfg {String} invalidClass @hide
23021 * @cfg {String} invalidText @hide
23024 * @cfg {String} msgFx @hide
23027 * @cfg {String} validateOnBlur @hide
23031 Roo.HtmlEditorCore.white = [
23032 'area', 'br', 'img', 'input', 'hr', 'wbr',
23034 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23035 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23036 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23037 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23038 'table', 'ul', 'xmp',
23040 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23043 'dir', 'menu', 'ol', 'ul', 'dl',
23049 Roo.HtmlEditorCore.black = [
23050 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23052 'base', 'basefont', 'bgsound', 'blink', 'body',
23053 'frame', 'frameset', 'head', 'html', 'ilayer',
23054 'iframe', 'layer', 'link', 'meta', 'object',
23055 'script', 'style' ,'title', 'xml' // clean later..
23057 Roo.HtmlEditorCore.clean = [
23058 'script', 'style', 'title', 'xml'
23060 Roo.HtmlEditorCore.remove = [
23065 Roo.HtmlEditorCore.ablack = [
23069 Roo.HtmlEditorCore.aclean = [
23070 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23074 Roo.HtmlEditorCore.pwhite= [
23075 'http', 'https', 'mailto'
23078 // white listed style attributes.
23079 Roo.HtmlEditorCore.cwhite= [
23080 // 'text-align', /// default is to allow most things..
23086 // black listed style attributes.
23087 Roo.HtmlEditorCore.cblack= [
23088 // 'font-size' -- this can be set by the project
23092 Roo.HtmlEditorCore.swapCodes =[
23111 * @class Roo.bootstrap.HtmlEditor
23112 * @extends Roo.bootstrap.TextArea
23113 * Bootstrap HtmlEditor class
23116 * Create a new HtmlEditor
23117 * @param {Object} config The config object
23120 Roo.bootstrap.HtmlEditor = function(config){
23121 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23122 if (!this.toolbars) {
23123 this.toolbars = [];
23126 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23129 * @event initialize
23130 * Fires when the editor is fully initialized (including the iframe)
23131 * @param {HtmlEditor} this
23136 * Fires when the editor is first receives the focus. Any insertion must wait
23137 * until after this event.
23138 * @param {HtmlEditor} this
23142 * @event beforesync
23143 * Fires before the textarea is updated with content from the editor iframe. Return false
23144 * to cancel the sync.
23145 * @param {HtmlEditor} this
23146 * @param {String} html
23150 * @event beforepush
23151 * Fires before the iframe editor is updated with content from the textarea. Return false
23152 * to cancel the push.
23153 * @param {HtmlEditor} this
23154 * @param {String} html
23159 * Fires when the textarea is updated with content from the editor iframe.
23160 * @param {HtmlEditor} this
23161 * @param {String} html
23166 * Fires when the iframe editor is updated with content from the textarea.
23167 * @param {HtmlEditor} this
23168 * @param {String} html
23172 * @event editmodechange
23173 * Fires when the editor switches edit modes
23174 * @param {HtmlEditor} this
23175 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23177 editmodechange: true,
23179 * @event editorevent
23180 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23181 * @param {HtmlEditor} this
23185 * @event firstfocus
23186 * Fires when on first focus - needed by toolbars..
23187 * @param {HtmlEditor} this
23192 * Auto save the htmlEditor value as a file into Events
23193 * @param {HtmlEditor} this
23197 * @event savedpreview
23198 * preview the saved version of htmlEditor
23199 * @param {HtmlEditor} this
23206 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23210 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23215 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23220 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23225 * @cfg {Number} height (in pixels)
23229 * @cfg {Number} width (in pixels)
23234 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23237 stylesheets: false,
23242 // private properties
23243 validationEvent : false,
23245 initialized : false,
23248 onFocus : Roo.emptyFn,
23250 hideMode:'offsets',
23252 tbContainer : false,
23256 toolbarContainer :function() {
23257 return this.wrap.select('.x-html-editor-tb',true).first();
23261 * Protected method that will not generally be called directly. It
23262 * is called when the editor creates its toolbar. Override this method if you need to
23263 * add custom toolbar buttons.
23264 * @param {HtmlEditor} editor
23266 createToolbar : function(){
23267 Roo.log('renewing');
23268 Roo.log("create toolbars");
23270 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23271 this.toolbars[0].render(this.toolbarContainer());
23275 // if (!editor.toolbars || !editor.toolbars.length) {
23276 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23279 // for (var i =0 ; i < editor.toolbars.length;i++) {
23280 // editor.toolbars[i] = Roo.factory(
23281 // typeof(editor.toolbars[i]) == 'string' ?
23282 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23283 // Roo.bootstrap.HtmlEditor);
23284 // editor.toolbars[i].init(editor);
23290 onRender : function(ct, position)
23292 // Roo.log("Call onRender: " + this.xtype);
23294 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23296 this.wrap = this.inputEl().wrap({
23297 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23300 this.editorcore.onRender(ct, position);
23302 if (this.resizable) {
23303 this.resizeEl = new Roo.Resizable(this.wrap, {
23307 minHeight : this.height,
23308 height: this.height,
23309 handles : this.resizable,
23312 resize : function(r, w, h) {
23313 _t.onResize(w,h); // -something
23319 this.createToolbar(this);
23322 if(!this.width && this.resizable){
23323 this.setSize(this.wrap.getSize());
23325 if (this.resizeEl) {
23326 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23327 // should trigger onReize..
23333 onResize : function(w, h)
23335 Roo.log('resize: ' +w + ',' + h );
23336 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23340 if(this.inputEl() ){
23341 if(typeof w == 'number'){
23342 var aw = w - this.wrap.getFrameWidth('lr');
23343 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23346 if(typeof h == 'number'){
23347 var tbh = -11; // fixme it needs to tool bar size!
23348 for (var i =0; i < this.toolbars.length;i++) {
23349 // fixme - ask toolbars for heights?
23350 tbh += this.toolbars[i].el.getHeight();
23351 //if (this.toolbars[i].footer) {
23352 // tbh += this.toolbars[i].footer.el.getHeight();
23360 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23361 ah -= 5; // knock a few pixes off for look..
23362 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23366 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23367 this.editorcore.onResize(ew,eh);
23372 * Toggles the editor between standard and source edit mode.
23373 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23375 toggleSourceEdit : function(sourceEditMode)
23377 this.editorcore.toggleSourceEdit(sourceEditMode);
23379 if(this.editorcore.sourceEditMode){
23380 Roo.log('editor - showing textarea');
23383 // Roo.log(this.syncValue());
23385 this.inputEl().removeClass(['hide', 'x-hidden']);
23386 this.inputEl().dom.removeAttribute('tabIndex');
23387 this.inputEl().focus();
23389 Roo.log('editor - hiding textarea');
23391 // Roo.log(this.pushValue());
23394 this.inputEl().addClass(['hide', 'x-hidden']);
23395 this.inputEl().dom.setAttribute('tabIndex', -1);
23396 //this.deferFocus();
23399 if(this.resizable){
23400 this.setSize(this.wrap.getSize());
23403 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23406 // private (for BoxComponent)
23407 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23409 // private (for BoxComponent)
23410 getResizeEl : function(){
23414 // private (for BoxComponent)
23415 getPositionEl : function(){
23420 initEvents : function(){
23421 this.originalValue = this.getValue();
23425 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23428 // markInvalid : Roo.emptyFn,
23430 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23433 // clearInvalid : Roo.emptyFn,
23435 setValue : function(v){
23436 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23437 this.editorcore.pushValue();
23442 deferFocus : function(){
23443 this.focus.defer(10, this);
23447 focus : function(){
23448 this.editorcore.focus();
23454 onDestroy : function(){
23460 for (var i =0; i < this.toolbars.length;i++) {
23461 // fixme - ask toolbars for heights?
23462 this.toolbars[i].onDestroy();
23465 this.wrap.dom.innerHTML = '';
23466 this.wrap.remove();
23471 onFirstFocus : function(){
23472 //Roo.log("onFirstFocus");
23473 this.editorcore.onFirstFocus();
23474 for (var i =0; i < this.toolbars.length;i++) {
23475 this.toolbars[i].onFirstFocus();
23481 syncValue : function()
23483 this.editorcore.syncValue();
23486 pushValue : function()
23488 this.editorcore.pushValue();
23492 // hide stuff that is not compatible
23506 * @event specialkey
23510 * @cfg {String} fieldClass @hide
23513 * @cfg {String} focusClass @hide
23516 * @cfg {String} autoCreate @hide
23519 * @cfg {String} inputType @hide
23522 * @cfg {String} invalidClass @hide
23525 * @cfg {String} invalidText @hide
23528 * @cfg {String} msgFx @hide
23531 * @cfg {String} validateOnBlur @hide
23540 Roo.namespace('Roo.bootstrap.htmleditor');
23542 * @class Roo.bootstrap.HtmlEditorToolbar1
23547 new Roo.bootstrap.HtmlEditor({
23550 new Roo.bootstrap.HtmlEditorToolbar1({
23551 disable : { fonts: 1 , format: 1, ..., ... , ...],
23557 * @cfg {Object} disable List of elements to disable..
23558 * @cfg {Array} btns List of additional buttons.
23562 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23565 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23568 Roo.apply(this, config);
23570 // default disabled, based on 'good practice'..
23571 this.disable = this.disable || {};
23572 Roo.applyIf(this.disable, {
23575 specialElements : true
23577 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23579 this.editor = config.editor;
23580 this.editorcore = config.editor.editorcore;
23582 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23584 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23585 // dont call parent... till later.
23587 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23592 editorcore : false,
23597 "h1","h2","h3","h4","h5","h6",
23599 "abbr", "acronym", "address", "cite", "samp", "var",
23603 onRender : function(ct, position)
23605 // Roo.log("Call onRender: " + this.xtype);
23607 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23609 this.el.dom.style.marginBottom = '0';
23611 var editorcore = this.editorcore;
23612 var editor= this.editor;
23615 var btn = function(id,cmd , toggle, handler, html){
23617 var event = toggle ? 'toggle' : 'click';
23622 xns: Roo.bootstrap,
23625 enableToggle:toggle !== false,
23627 pressed : toggle ? false : null,
23630 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23631 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23637 // var cb_box = function...
23642 xns: Roo.bootstrap,
23643 glyphicon : 'font',
23647 xns: Roo.bootstrap,
23651 Roo.each(this.formats, function(f) {
23652 style.menu.items.push({
23654 xns: Roo.bootstrap,
23655 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23660 editorcore.insertTag(this.tagname);
23667 children.push(style);
23669 btn('bold',false,true);
23670 btn('italic',false,true);
23671 btn('align-left', 'justifyleft',true);
23672 btn('align-center', 'justifycenter',true);
23673 btn('align-right' , 'justifyright',true);
23674 btn('link', false, false, function(btn) {
23675 //Roo.log("create link?");
23676 var url = prompt(this.createLinkText, this.defaultLinkValue);
23677 if(url && url != 'http:/'+'/'){
23678 this.editorcore.relayCmd('createlink', url);
23681 btn('list','insertunorderedlist',true);
23682 btn('pencil', false,true, function(btn){
23684 this.toggleSourceEdit(btn.pressed);
23687 if (this.editor.btns.length > 0) {
23688 for (var i = 0; i<this.editor.btns.length; i++) {
23689 children.push(this.editor.btns[i]);
23697 xns: Roo.bootstrap,
23702 xns: Roo.bootstrap,
23707 cog.menu.items.push({
23709 xns: Roo.bootstrap,
23710 html : Clean styles,
23715 editorcore.insertTag(this.tagname);
23724 this.xtype = 'NavSimplebar';
23726 for(var i=0;i< children.length;i++) {
23728 this.buttons.add(this.addxtypeChild(children[i]));
23732 editor.on('editorevent', this.updateToolbar, this);
23734 onBtnClick : function(id)
23736 this.editorcore.relayCmd(id);
23737 this.editorcore.focus();
23741 * Protected method that will not generally be called directly. It triggers
23742 * a toolbar update by reading the markup state of the current selection in the editor.
23744 updateToolbar: function(){
23746 if(!this.editorcore.activated){
23747 this.editor.onFirstFocus(); // is this neeed?
23751 var btns = this.buttons;
23752 var doc = this.editorcore.doc;
23753 btns.get('bold').setActive(doc.queryCommandState('bold'));
23754 btns.get('italic').setActive(doc.queryCommandState('italic'));
23755 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23757 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23758 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23759 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23761 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23762 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23765 var ans = this.editorcore.getAllAncestors();
23766 if (this.formatCombo) {
23769 var store = this.formatCombo.store;
23770 this.formatCombo.setValue("");
23771 for (var i =0; i < ans.length;i++) {
23772 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23774 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23782 // hides menus... - so this cant be on a menu...
23783 Roo.bootstrap.MenuMgr.hideAll();
23785 Roo.bootstrap.MenuMgr.hideAll();
23786 //this.editorsyncValue();
23788 onFirstFocus: function() {
23789 this.buttons.each(function(item){
23793 toggleSourceEdit : function(sourceEditMode){
23796 if(sourceEditMode){
23797 Roo.log("disabling buttons");
23798 this.buttons.each( function(item){
23799 if(item.cmd != 'pencil'){
23805 Roo.log("enabling buttons");
23806 if(this.editorcore.initialized){
23807 this.buttons.each( function(item){
23813 Roo.log("calling toggole on editor");
23814 // tell the editor that it's been pressed..
23815 this.editor.toggleSourceEdit(sourceEditMode);
23825 * @class Roo.bootstrap.Table.AbstractSelectionModel
23826 * @extends Roo.util.Observable
23827 * Abstract base class for grid SelectionModels. It provides the interface that should be
23828 * implemented by descendant classes. This class should not be directly instantiated.
23831 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23832 this.locked = false;
23833 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23837 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23838 /** @ignore Called by the grid automatically. Do not call directly. */
23839 init : function(grid){
23845 * Locks the selections.
23848 this.locked = true;
23852 * Unlocks the selections.
23854 unlock : function(){
23855 this.locked = false;
23859 * Returns true if the selections are locked.
23860 * @return {Boolean}
23862 isLocked : function(){
23863 return this.locked;
23867 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23868 * @class Roo.bootstrap.Table.RowSelectionModel
23869 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23870 * It supports multiple selections and keyboard selection/navigation.
23872 * @param {Object} config
23875 Roo.bootstrap.Table.RowSelectionModel = function(config){
23876 Roo.apply(this, config);
23877 this.selections = new Roo.util.MixedCollection(false, function(o){
23882 this.lastActive = false;
23886 * @event selectionchange
23887 * Fires when the selection changes
23888 * @param {SelectionModel} this
23890 "selectionchange" : true,
23892 * @event afterselectionchange
23893 * Fires after the selection changes (eg. by key press or clicking)
23894 * @param {SelectionModel} this
23896 "afterselectionchange" : true,
23898 * @event beforerowselect
23899 * Fires when a row is selected being selected, return false to cancel.
23900 * @param {SelectionModel} this
23901 * @param {Number} rowIndex The selected index
23902 * @param {Boolean} keepExisting False if other selections will be cleared
23904 "beforerowselect" : true,
23907 * Fires when a row is selected.
23908 * @param {SelectionModel} this
23909 * @param {Number} rowIndex The selected index
23910 * @param {Roo.data.Record} r The record
23912 "rowselect" : true,
23914 * @event rowdeselect
23915 * Fires when a row is deselected.
23916 * @param {SelectionModel} this
23917 * @param {Number} rowIndex The selected index
23919 "rowdeselect" : true
23921 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23922 this.locked = false;
23925 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23927 * @cfg {Boolean} singleSelect
23928 * True to allow selection of only one row at a time (defaults to false)
23930 singleSelect : false,
23933 initEvents : function()
23936 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23937 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23938 //}else{ // allow click to work like normal
23939 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23941 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23942 this.grid.on("rowclick", this.handleMouseDown, this);
23944 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23945 "up" : function(e){
23947 this.selectPrevious(e.shiftKey);
23948 }else if(this.last !== false && this.lastActive !== false){
23949 var last = this.last;
23950 this.selectRange(this.last, this.lastActive-1);
23951 this.grid.getView().focusRow(this.lastActive);
23952 if(last !== false){
23956 this.selectFirstRow();
23958 this.fireEvent("afterselectionchange", this);
23960 "down" : function(e){
23962 this.selectNext(e.shiftKey);
23963 }else if(this.last !== false && this.lastActive !== false){
23964 var last = this.last;
23965 this.selectRange(this.last, this.lastActive+1);
23966 this.grid.getView().focusRow(this.lastActive);
23967 if(last !== false){
23971 this.selectFirstRow();
23973 this.fireEvent("afterselectionchange", this);
23977 this.grid.store.on('load', function(){
23978 this.selections.clear();
23981 var view = this.grid.view;
23982 view.on("refresh", this.onRefresh, this);
23983 view.on("rowupdated", this.onRowUpdated, this);
23984 view.on("rowremoved", this.onRemove, this);
23989 onRefresh : function()
23991 var ds = this.grid.store, i, v = this.grid.view;
23992 var s = this.selections;
23993 s.each(function(r){
23994 if((i = ds.indexOfId(r.id)) != -1){
24003 onRemove : function(v, index, r){
24004 this.selections.remove(r);
24008 onRowUpdated : function(v, index, r){
24009 if(this.isSelected(r)){
24010 v.onRowSelect(index);
24016 * @param {Array} records The records to select
24017 * @param {Boolean} keepExisting (optional) True to keep existing selections
24019 selectRecords : function(records, keepExisting)
24022 this.clearSelections();
24024 var ds = this.grid.store;
24025 for(var i = 0, len = records.length; i < len; i++){
24026 this.selectRow(ds.indexOf(records[i]), true);
24031 * Gets the number of selected rows.
24034 getCount : function(){
24035 return this.selections.length;
24039 * Selects the first row in the grid.
24041 selectFirstRow : function(){
24046 * Select the last row.
24047 * @param {Boolean} keepExisting (optional) True to keep existing selections
24049 selectLastRow : function(keepExisting){
24050 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24051 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24055 * Selects the row immediately following the last selected row.
24056 * @param {Boolean} keepExisting (optional) True to keep existing selections
24058 selectNext : function(keepExisting)
24060 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24061 this.selectRow(this.last+1, keepExisting);
24062 this.grid.getView().focusRow(this.last);
24067 * Selects the row that precedes the last selected row.
24068 * @param {Boolean} keepExisting (optional) True to keep existing selections
24070 selectPrevious : function(keepExisting){
24072 this.selectRow(this.last-1, keepExisting);
24073 this.grid.getView().focusRow(this.last);
24078 * Returns the selected records
24079 * @return {Array} Array of selected records
24081 getSelections : function(){
24082 return [].concat(this.selections.items);
24086 * Returns the first selected record.
24089 getSelected : function(){
24090 return this.selections.itemAt(0);
24095 * Clears all selections.
24097 clearSelections : function(fast)
24103 var ds = this.grid.store;
24104 var s = this.selections;
24105 s.each(function(r){
24106 this.deselectRow(ds.indexOfId(r.id));
24110 this.selections.clear();
24117 * Selects all rows.
24119 selectAll : function(){
24123 this.selections.clear();
24124 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24125 this.selectRow(i, true);
24130 * Returns True if there is a selection.
24131 * @return {Boolean}
24133 hasSelection : function(){
24134 return this.selections.length > 0;
24138 * Returns True if the specified row is selected.
24139 * @param {Number/Record} record The record or index of the record to check
24140 * @return {Boolean}
24142 isSelected : function(index){
24143 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24144 return (r && this.selections.key(r.id) ? true : false);
24148 * Returns True if the specified record id is selected.
24149 * @param {String} id The id of record to check
24150 * @return {Boolean}
24152 isIdSelected : function(id){
24153 return (this.selections.key(id) ? true : false);
24158 handleMouseDBClick : function(e, t){
24162 handleMouseDown : function(e, t)
24164 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24165 if(this.isLocked() || rowIndex < 0 ){
24168 if(e.shiftKey && this.last !== false){
24169 var last = this.last;
24170 this.selectRange(last, rowIndex, e.ctrlKey);
24171 this.last = last; // reset the last
24175 var isSelected = this.isSelected(rowIndex);
24176 //Roo.log("select row:" + rowIndex);
24178 this.deselectRow(rowIndex);
24180 this.selectRow(rowIndex, true);
24184 if(e.button !== 0 && isSelected){
24185 alert('rowIndex 2: ' + rowIndex);
24186 view.focusRow(rowIndex);
24187 }else if(e.ctrlKey && isSelected){
24188 this.deselectRow(rowIndex);
24189 }else if(!isSelected){
24190 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24191 view.focusRow(rowIndex);
24195 this.fireEvent("afterselectionchange", this);
24198 handleDragableRowClick : function(grid, rowIndex, e)
24200 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24201 this.selectRow(rowIndex, false);
24202 grid.view.focusRow(rowIndex);
24203 this.fireEvent("afterselectionchange", this);
24208 * Selects multiple rows.
24209 * @param {Array} rows Array of the indexes of the row to select
24210 * @param {Boolean} keepExisting (optional) True to keep existing selections
24212 selectRows : function(rows, keepExisting){
24214 this.clearSelections();
24216 for(var i = 0, len = rows.length; i < len; i++){
24217 this.selectRow(rows[i], true);
24222 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24223 * @param {Number} startRow The index of the first row in the range
24224 * @param {Number} endRow The index of the last row in the range
24225 * @param {Boolean} keepExisting (optional) True to retain existing selections
24227 selectRange : function(startRow, endRow, keepExisting){
24232 this.clearSelections();
24234 if(startRow <= endRow){
24235 for(var i = startRow; i <= endRow; i++){
24236 this.selectRow(i, true);
24239 for(var i = startRow; i >= endRow; i--){
24240 this.selectRow(i, true);
24246 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24247 * @param {Number} startRow The index of the first row in the range
24248 * @param {Number} endRow The index of the last row in the range
24250 deselectRange : function(startRow, endRow, preventViewNotify){
24254 for(var i = startRow; i <= endRow; i++){
24255 this.deselectRow(i, preventViewNotify);
24261 * @param {Number} row The index of the row to select
24262 * @param {Boolean} keepExisting (optional) True to keep existing selections
24264 selectRow : function(index, keepExisting, preventViewNotify)
24266 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24269 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24270 if(!keepExisting || this.singleSelect){
24271 this.clearSelections();
24274 var r = this.grid.store.getAt(index);
24275 //console.log('selectRow - record id :' + r.id);
24277 this.selections.add(r);
24278 this.last = this.lastActive = index;
24279 if(!preventViewNotify){
24280 var proxy = new Roo.Element(
24281 this.grid.getRowDom(index)
24283 proxy.addClass('bg-info info');
24285 this.fireEvent("rowselect", this, index, r);
24286 this.fireEvent("selectionchange", this);
24292 * @param {Number} row The index of the row to deselect
24294 deselectRow : function(index, preventViewNotify)
24299 if(this.last == index){
24302 if(this.lastActive == index){
24303 this.lastActive = false;
24306 var r = this.grid.store.getAt(index);
24311 this.selections.remove(r);
24312 //.console.log('deselectRow - record id :' + r.id);
24313 if(!preventViewNotify){
24315 var proxy = new Roo.Element(
24316 this.grid.getRowDom(index)
24318 proxy.removeClass('bg-info info');
24320 this.fireEvent("rowdeselect", this, index);
24321 this.fireEvent("selectionchange", this);
24325 restoreLast : function(){
24327 this.last = this._last;
24332 acceptsNav : function(row, col, cm){
24333 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24337 onEditorKey : function(field, e){
24338 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24343 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24345 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24347 }else if(k == e.ENTER && !e.ctrlKey){
24351 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24353 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24355 }else if(k == e.ESC){
24359 g.startEditing(newCell[0], newCell[1]);
24365 * Ext JS Library 1.1.1
24366 * Copyright(c) 2006-2007, Ext JS, LLC.
24368 * Originally Released Under LGPL - original licence link has changed is not relivant.
24371 * <script type="text/javascript">
24375 * @class Roo.bootstrap.PagingToolbar
24376 * @extends Roo.bootstrap.NavSimplebar
24377 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24379 * Create a new PagingToolbar
24380 * @param {Object} config The config object
24381 * @param {Roo.data.Store} store
24383 Roo.bootstrap.PagingToolbar = function(config)
24385 // old args format still supported... - xtype is prefered..
24386 // created from xtype...
24388 this.ds = config.dataSource;
24390 if (config.store && !this.ds) {
24391 this.store= Roo.factory(config.store, Roo.data);
24392 this.ds = this.store;
24393 this.ds.xmodule = this.xmodule || false;
24396 this.toolbarItems = [];
24397 if (config.items) {
24398 this.toolbarItems = config.items;
24401 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24406 this.bind(this.ds);
24409 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24413 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24415 * @cfg {Roo.data.Store} dataSource
24416 * The underlying data store providing the paged data
24419 * @cfg {String/HTMLElement/Element} container
24420 * container The id or element that will contain the toolbar
24423 * @cfg {Boolean} displayInfo
24424 * True to display the displayMsg (defaults to false)
24427 * @cfg {Number} pageSize
24428 * The number of records to display per page (defaults to 20)
24432 * @cfg {String} displayMsg
24433 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24435 displayMsg : 'Displaying {0} - {1} of {2}',
24437 * @cfg {String} emptyMsg
24438 * The message to display when no records are found (defaults to "No data to display")
24440 emptyMsg : 'No data to display',
24442 * Customizable piece of the default paging text (defaults to "Page")
24445 beforePageText : "Page",
24447 * Customizable piece of the default paging text (defaults to "of %0")
24450 afterPageText : "of {0}",
24452 * Customizable piece of the default paging text (defaults to "First Page")
24455 firstText : "First Page",
24457 * Customizable piece of the default paging text (defaults to "Previous Page")
24460 prevText : "Previous Page",
24462 * Customizable piece of the default paging text (defaults to "Next Page")
24465 nextText : "Next Page",
24467 * Customizable piece of the default paging text (defaults to "Last Page")
24470 lastText : "Last Page",
24472 * Customizable piece of the default paging text (defaults to "Refresh")
24475 refreshText : "Refresh",
24479 onRender : function(ct, position)
24481 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24482 this.navgroup.parentId = this.id;
24483 this.navgroup.onRender(this.el, null);
24484 // add the buttons to the navgroup
24486 if(this.displayInfo){
24487 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24488 this.displayEl = this.el.select('.x-paging-info', true).first();
24489 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24490 // this.displayEl = navel.el.select('span',true).first();
24496 Roo.each(_this.buttons, function(e){ // this might need to use render????
24497 Roo.factory(e).onRender(_this.el, null);
24501 Roo.each(_this.toolbarItems, function(e) {
24502 _this.navgroup.addItem(e);
24506 this.first = this.navgroup.addItem({
24507 tooltip: this.firstText,
24509 icon : 'fa fa-backward',
24511 preventDefault: true,
24512 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24515 this.prev = this.navgroup.addItem({
24516 tooltip: this.prevText,
24518 icon : 'fa fa-step-backward',
24520 preventDefault: true,
24521 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24523 //this.addSeparator();
24526 var field = this.navgroup.addItem( {
24528 cls : 'x-paging-position',
24530 html : this.beforePageText +
24531 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24532 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24535 this.field = field.el.select('input', true).first();
24536 this.field.on("keydown", this.onPagingKeydown, this);
24537 this.field.on("focus", function(){this.dom.select();});
24540 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24541 //this.field.setHeight(18);
24542 //this.addSeparator();
24543 this.next = this.navgroup.addItem({
24544 tooltip: this.nextText,
24546 html : ' <i class="fa fa-step-forward">',
24548 preventDefault: true,
24549 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24551 this.last = this.navgroup.addItem({
24552 tooltip: this.lastText,
24553 icon : 'fa fa-forward',
24556 preventDefault: true,
24557 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24559 //this.addSeparator();
24560 this.loading = this.navgroup.addItem({
24561 tooltip: this.refreshText,
24562 icon: 'fa fa-refresh',
24563 preventDefault: true,
24564 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24570 updateInfo : function(){
24571 if(this.displayEl){
24572 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24573 var msg = count == 0 ?
24577 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24579 this.displayEl.update(msg);
24584 onLoad : function(ds, r, o)
24586 this.cursor = o.params.start ? o.params.start : 0;
24588 var d = this.getPageData(),
24593 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24594 this.field.dom.value = ap;
24595 this.first.setDisabled(ap == 1);
24596 this.prev.setDisabled(ap == 1);
24597 this.next.setDisabled(ap == ps);
24598 this.last.setDisabled(ap == ps);
24599 this.loading.enable();
24604 getPageData : function(){
24605 var total = this.ds.getTotalCount();
24608 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24609 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24614 onLoadError : function(){
24615 this.loading.enable();
24619 onPagingKeydown : function(e){
24620 var k = e.getKey();
24621 var d = this.getPageData();
24623 var v = this.field.dom.value, pageNum;
24624 if(!v || isNaN(pageNum = parseInt(v, 10))){
24625 this.field.dom.value = d.activePage;
24628 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24629 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24632 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))
24634 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24635 this.field.dom.value = pageNum;
24636 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24639 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24641 var v = this.field.dom.value, pageNum;
24642 var increment = (e.shiftKey) ? 10 : 1;
24643 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24646 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24647 this.field.dom.value = d.activePage;
24650 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24652 this.field.dom.value = parseInt(v, 10) + increment;
24653 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24654 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24661 beforeLoad : function(){
24663 this.loading.disable();
24668 onClick : function(which){
24677 ds.load({params:{start: 0, limit: this.pageSize}});
24680 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24683 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24686 var total = ds.getTotalCount();
24687 var extra = total % this.pageSize;
24688 var lastStart = extra ? (total - extra) : total-this.pageSize;
24689 ds.load({params:{start: lastStart, limit: this.pageSize}});
24692 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24698 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24699 * @param {Roo.data.Store} store The data store to unbind
24701 unbind : function(ds){
24702 ds.un("beforeload", this.beforeLoad, this);
24703 ds.un("load", this.onLoad, this);
24704 ds.un("loadexception", this.onLoadError, this);
24705 ds.un("remove", this.updateInfo, this);
24706 ds.un("add", this.updateInfo, this);
24707 this.ds = undefined;
24711 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24712 * @param {Roo.data.Store} store The data store to bind
24714 bind : function(ds){
24715 ds.on("beforeload", this.beforeLoad, this);
24716 ds.on("load", this.onLoad, this);
24717 ds.on("loadexception", this.onLoadError, this);
24718 ds.on("remove", this.updateInfo, this);
24719 ds.on("add", this.updateInfo, this);
24730 * @class Roo.bootstrap.MessageBar
24731 * @extends Roo.bootstrap.Component
24732 * Bootstrap MessageBar class
24733 * @cfg {String} html contents of the MessageBar
24734 * @cfg {String} weight (info | success | warning | danger) default info
24735 * @cfg {String} beforeClass insert the bar before the given class
24736 * @cfg {Boolean} closable (true | false) default false
24737 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24740 * Create a new Element
24741 * @param {Object} config The config object
24744 Roo.bootstrap.MessageBar = function(config){
24745 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24748 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24754 beforeClass: 'bootstrap-sticky-wrap',
24756 getAutoCreate : function(){
24760 cls: 'alert alert-dismissable alert-' + this.weight,
24765 html: this.html || ''
24771 cfg.cls += ' alert-messages-fixed';
24785 onRender : function(ct, position)
24787 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24790 var cfg = Roo.apply({}, this.getAutoCreate());
24794 cfg.cls += ' ' + this.cls;
24797 cfg.style = this.style;
24799 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24801 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24804 this.el.select('>button.close').on('click', this.hide, this);
24810 if (!this.rendered) {
24816 this.fireEvent('show', this);
24822 if (!this.rendered) {
24828 this.fireEvent('hide', this);
24831 update : function()
24833 // var e = this.el.dom.firstChild;
24835 // if(this.closable){
24836 // e = e.nextSibling;
24839 // e.data = this.html || '';
24841 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24857 * @class Roo.bootstrap.Graph
24858 * @extends Roo.bootstrap.Component
24859 * Bootstrap Graph class
24863 @cfg {String} graphtype bar | vbar | pie
24864 @cfg {number} g_x coodinator | centre x (pie)
24865 @cfg {number} g_y coodinator | centre y (pie)
24866 @cfg {number} g_r radius (pie)
24867 @cfg {number} g_height height of the chart (respected by all elements in the set)
24868 @cfg {number} g_width width of the chart (respected by all elements in the set)
24869 @cfg {Object} title The title of the chart
24872 -opts (object) options for the chart
24874 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24875 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24877 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.
24878 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24880 o stretch (boolean)
24882 -opts (object) options for the pie
24885 o startAngle (number)
24886 o endAngle (number)
24890 * Create a new Input
24891 * @param {Object} config The config object
24894 Roo.bootstrap.Graph = function(config){
24895 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24901 * The img click event for the img.
24902 * @param {Roo.EventObject} e
24908 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24919 //g_colors: this.colors,
24926 getAutoCreate : function(){
24937 onRender : function(ct,position){
24940 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24942 if (typeof(Raphael) == 'undefined') {
24943 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24947 this.raphael = Raphael(this.el.dom);
24949 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24950 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24951 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24952 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24954 r.text(160, 10, "Single Series Chart").attr(txtattr);
24955 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24956 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24957 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24959 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24960 r.barchart(330, 10, 300, 220, data1);
24961 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24962 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24965 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24966 // r.barchart(30, 30, 560, 250, xdata, {
24967 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24968 // axis : "0 0 1 1",
24969 // axisxlabels : xdata
24970 // //yvalues : cols,
24973 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24975 // this.load(null,xdata,{
24976 // axis : "0 0 1 1",
24977 // axisxlabels : xdata
24982 load : function(graphtype,xdata,opts)
24984 this.raphael.clear();
24986 graphtype = this.graphtype;
24991 var r = this.raphael,
24992 fin = function () {
24993 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24995 fout = function () {
24996 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24998 pfin = function() {
24999 this.sector.stop();
25000 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25003 this.label[0].stop();
25004 this.label[0].attr({ r: 7.5 });
25005 this.label[1].attr({ "font-weight": 800 });
25008 pfout = function() {
25009 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25012 this.label[0].animate({ r: 5 }, 500, "bounce");
25013 this.label[1].attr({ "font-weight": 400 });
25019 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25022 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25025 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25026 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25028 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25035 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25040 setTitle: function(o)
25045 initEvents: function() {
25048 this.el.on('click', this.onClick, this);
25052 onClick : function(e)
25054 Roo.log('img onclick');
25055 this.fireEvent('click', this, e);
25067 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25070 * @class Roo.bootstrap.dash.NumberBox
25071 * @extends Roo.bootstrap.Component
25072 * Bootstrap NumberBox class
25073 * @cfg {String} headline Box headline
25074 * @cfg {String} content Box content
25075 * @cfg {String} icon Box icon
25076 * @cfg {String} footer Footer text
25077 * @cfg {String} fhref Footer href
25080 * Create a new NumberBox
25081 * @param {Object} config The config object
25085 Roo.bootstrap.dash.NumberBox = function(config){
25086 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25090 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25099 getAutoCreate : function(){
25103 cls : 'small-box ',
25111 cls : 'roo-headline',
25112 html : this.headline
25116 cls : 'roo-content',
25117 html : this.content
25131 cls : 'ion ' + this.icon
25140 cls : 'small-box-footer',
25141 href : this.fhref || '#',
25145 cfg.cn.push(footer);
25152 onRender : function(ct,position){
25153 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25160 setHeadline: function (value)
25162 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25165 setFooter: function (value, href)
25167 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25170 this.el.select('a.small-box-footer',true).first().attr('href', href);
25175 setContent: function (value)
25177 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25180 initEvents: function()
25194 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25197 * @class Roo.bootstrap.dash.TabBox
25198 * @extends Roo.bootstrap.Component
25199 * Bootstrap TabBox class
25200 * @cfg {String} title Title of the TabBox
25201 * @cfg {String} icon Icon of the TabBox
25202 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25203 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25206 * Create a new TabBox
25207 * @param {Object} config The config object
25211 Roo.bootstrap.dash.TabBox = function(config){
25212 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25217 * When a pane is added
25218 * @param {Roo.bootstrap.dash.TabPane} pane
25222 * @event activatepane
25223 * When a pane is activated
25224 * @param {Roo.bootstrap.dash.TabPane} pane
25226 "activatepane" : true
25234 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25239 tabScrollable : false,
25241 getChildContainer : function()
25243 return this.el.select('.tab-content', true).first();
25246 getAutoCreate : function(){
25250 cls: 'pull-left header',
25258 cls: 'fa ' + this.icon
25264 cls: 'nav nav-tabs pull-right',
25270 if(this.tabScrollable){
25277 cls: 'nav nav-tabs pull-right',
25288 cls: 'nav-tabs-custom',
25293 cls: 'tab-content no-padding',
25301 initEvents : function()
25303 //Roo.log('add add pane handler');
25304 this.on('addpane', this.onAddPane, this);
25307 * Updates the box title
25308 * @param {String} html to set the title to.
25310 setTitle : function(value)
25312 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25314 onAddPane : function(pane)
25316 this.panes.push(pane);
25317 //Roo.log('addpane');
25319 // tabs are rendere left to right..
25320 if(!this.showtabs){
25324 var ctr = this.el.select('.nav-tabs', true).first();
25327 var existing = ctr.select('.nav-tab',true);
25328 var qty = existing.getCount();;
25331 var tab = ctr.createChild({
25333 cls : 'nav-tab' + (qty ? '' : ' active'),
25341 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25344 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25346 pane.el.addClass('active');
25351 onTabClick : function(ev,un,ob,pane)
25353 //Roo.log('tab - prev default');
25354 ev.preventDefault();
25357 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25358 pane.tab.addClass('active');
25359 //Roo.log(pane.title);
25360 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25361 // technically we should have a deactivate event.. but maybe add later.
25362 // and it should not de-activate the selected tab...
25363 this.fireEvent('activatepane', pane);
25364 pane.el.addClass('active');
25365 pane.fireEvent('activate');
25370 getActivePane : function()
25373 Roo.each(this.panes, function(p) {
25374 if(p.el.hasClass('active')){
25395 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25397 * @class Roo.bootstrap.TabPane
25398 * @extends Roo.bootstrap.Component
25399 * Bootstrap TabPane class
25400 * @cfg {Boolean} active (false | true) Default false
25401 * @cfg {String} title title of panel
25405 * Create a new TabPane
25406 * @param {Object} config The config object
25409 Roo.bootstrap.dash.TabPane = function(config){
25410 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25416 * When a pane is activated
25417 * @param {Roo.bootstrap.dash.TabPane} pane
25424 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25429 // the tabBox that this is attached to.
25432 getAutoCreate : function()
25440 cfg.cls += ' active';
25445 initEvents : function()
25447 //Roo.log('trigger add pane handler');
25448 this.parent().fireEvent('addpane', this)
25452 * Updates the tab title
25453 * @param {String} html to set the title to.
25455 setTitle: function(str)
25461 this.tab.select('a', true).first().dom.innerHTML = str;
25478 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25481 * @class Roo.bootstrap.menu.Menu
25482 * @extends Roo.bootstrap.Component
25483 * Bootstrap Menu class - container for Menu
25484 * @cfg {String} html Text of the menu
25485 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25486 * @cfg {String} icon Font awesome icon
25487 * @cfg {String} pos Menu align to (top | bottom) default bottom
25491 * Create a new Menu
25492 * @param {Object} config The config object
25496 Roo.bootstrap.menu.Menu = function(config){
25497 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25501 * @event beforeshow
25502 * Fires before this menu is displayed
25503 * @param {Roo.bootstrap.menu.Menu} this
25507 * @event beforehide
25508 * Fires before this menu is hidden
25509 * @param {Roo.bootstrap.menu.Menu} this
25514 * Fires after this menu is displayed
25515 * @param {Roo.bootstrap.menu.Menu} this
25520 * Fires after this menu is hidden
25521 * @param {Roo.bootstrap.menu.Menu} this
25526 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25527 * @param {Roo.bootstrap.menu.Menu} this
25528 * @param {Roo.EventObject} e
25535 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25539 weight : 'default',
25544 getChildContainer : function() {
25545 if(this.isSubMenu){
25549 return this.el.select('ul.dropdown-menu', true).first();
25552 getAutoCreate : function()
25557 cls : 'roo-menu-text',
25565 cls : 'fa ' + this.icon
25576 cls : 'dropdown-button btn btn-' + this.weight,
25581 cls : 'dropdown-toggle btn btn-' + this.weight,
25591 cls : 'dropdown-menu'
25597 if(this.pos == 'top'){
25598 cfg.cls += ' dropup';
25601 if(this.isSubMenu){
25604 cls : 'dropdown-menu'
25611 onRender : function(ct, position)
25613 this.isSubMenu = ct.hasClass('dropdown-submenu');
25615 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25618 initEvents : function()
25620 if(this.isSubMenu){
25624 this.hidden = true;
25626 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25627 this.triggerEl.on('click', this.onTriggerPress, this);
25629 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25630 this.buttonEl.on('click', this.onClick, this);
25636 if(this.isSubMenu){
25640 return this.el.select('ul.dropdown-menu', true).first();
25643 onClick : function(e)
25645 this.fireEvent("click", this, e);
25648 onTriggerPress : function(e)
25650 if (this.isVisible()) {
25657 isVisible : function(){
25658 return !this.hidden;
25663 this.fireEvent("beforeshow", this);
25665 this.hidden = false;
25666 this.el.addClass('open');
25668 Roo.get(document).on("mouseup", this.onMouseUp, this);
25670 this.fireEvent("show", this);
25677 this.fireEvent("beforehide", this);
25679 this.hidden = true;
25680 this.el.removeClass('open');
25682 Roo.get(document).un("mouseup", this.onMouseUp);
25684 this.fireEvent("hide", this);
25687 onMouseUp : function()
25701 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25704 * @class Roo.bootstrap.menu.Item
25705 * @extends Roo.bootstrap.Component
25706 * Bootstrap MenuItem class
25707 * @cfg {Boolean} submenu (true | false) default false
25708 * @cfg {String} html text of the item
25709 * @cfg {String} href the link
25710 * @cfg {Boolean} disable (true | false) default false
25711 * @cfg {Boolean} preventDefault (true | false) default true
25712 * @cfg {String} icon Font awesome icon
25713 * @cfg {String} pos Submenu align to (left | right) default right
25717 * Create a new Item
25718 * @param {Object} config The config object
25722 Roo.bootstrap.menu.Item = function(config){
25723 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25727 * Fires when the mouse is hovering over this menu
25728 * @param {Roo.bootstrap.menu.Item} this
25729 * @param {Roo.EventObject} e
25734 * Fires when the mouse exits this menu
25735 * @param {Roo.bootstrap.menu.Item} this
25736 * @param {Roo.EventObject} e
25742 * The raw click event for the entire grid.
25743 * @param {Roo.EventObject} e
25749 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25754 preventDefault: true,
25759 getAutoCreate : function()
25764 cls : 'roo-menu-item-text',
25772 cls : 'fa ' + this.icon
25781 href : this.href || '#',
25788 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25792 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25794 if(this.pos == 'left'){
25795 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25802 initEvents : function()
25804 this.el.on('mouseover', this.onMouseOver, this);
25805 this.el.on('mouseout', this.onMouseOut, this);
25807 this.el.select('a', true).first().on('click', this.onClick, this);
25811 onClick : function(e)
25813 if(this.preventDefault){
25814 e.preventDefault();
25817 this.fireEvent("click", this, e);
25820 onMouseOver : function(e)
25822 if(this.submenu && this.pos == 'left'){
25823 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25826 this.fireEvent("mouseover", this, e);
25829 onMouseOut : function(e)
25831 this.fireEvent("mouseout", this, e);
25843 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25846 * @class Roo.bootstrap.menu.Separator
25847 * @extends Roo.bootstrap.Component
25848 * Bootstrap Separator class
25851 * Create a new Separator
25852 * @param {Object} config The config object
25856 Roo.bootstrap.menu.Separator = function(config){
25857 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25860 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25862 getAutoCreate : function(){
25883 * @class Roo.bootstrap.Tooltip
25884 * Bootstrap Tooltip class
25885 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25886 * to determine which dom element triggers the tooltip.
25888 * It needs to add support for additional attributes like tooltip-position
25891 * Create a new Toolti
25892 * @param {Object} config The config object
25895 Roo.bootstrap.Tooltip = function(config){
25896 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25898 this.alignment = Roo.bootstrap.Tooltip.alignment;
25900 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25901 this.alignment = config.alignment;
25906 Roo.apply(Roo.bootstrap.Tooltip, {
25908 * @function init initialize tooltip monitoring.
25912 currentTip : false,
25913 currentRegion : false,
25919 Roo.get(document).on('mouseover', this.enter ,this);
25920 Roo.get(document).on('mouseout', this.leave, this);
25923 this.currentTip = new Roo.bootstrap.Tooltip();
25926 enter : function(ev)
25928 var dom = ev.getTarget();
25930 //Roo.log(['enter',dom]);
25931 var el = Roo.fly(dom);
25932 if (this.currentEl) {
25934 //Roo.log(this.currentEl);
25935 //Roo.log(this.currentEl.contains(dom));
25936 if (this.currentEl == el) {
25939 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25945 if (this.currentTip.el) {
25946 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25950 if(!el || el.dom == document){
25956 // you can not look for children, as if el is the body.. then everythign is the child..
25957 if (!el.attr('tooltip')) { //
25958 if (!el.select("[tooltip]").elements.length) {
25961 // is the mouse over this child...?
25962 bindEl = el.select("[tooltip]").first();
25963 var xy = ev.getXY();
25964 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25965 //Roo.log("not in region.");
25968 //Roo.log("child element over..");
25971 this.currentEl = bindEl;
25972 this.currentTip.bind(bindEl);
25973 this.currentRegion = Roo.lib.Region.getRegion(dom);
25974 this.currentTip.enter();
25977 leave : function(ev)
25979 var dom = ev.getTarget();
25980 //Roo.log(['leave',dom]);
25981 if (!this.currentEl) {
25986 if (dom != this.currentEl.dom) {
25989 var xy = ev.getXY();
25990 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25993 // only activate leave if mouse cursor is outside... bounding box..
25998 if (this.currentTip) {
25999 this.currentTip.leave();
26001 //Roo.log('clear currentEl');
26002 this.currentEl = false;
26007 'left' : ['r-l', [-2,0], 'right'],
26008 'right' : ['l-r', [2,0], 'left'],
26009 'bottom' : ['t-b', [0,2], 'top'],
26010 'top' : [ 'b-t', [0,-2], 'bottom']
26016 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26021 delay : null, // can be { show : 300 , hide: 500}
26025 hoverState : null, //???
26027 placement : 'bottom',
26031 getAutoCreate : function(){
26038 cls : 'tooltip-arrow'
26041 cls : 'tooltip-inner'
26048 bind : function(el)
26054 enter : function () {
26056 if (this.timeout != null) {
26057 clearTimeout(this.timeout);
26060 this.hoverState = 'in';
26061 //Roo.log("enter - show");
26062 if (!this.delay || !this.delay.show) {
26067 this.timeout = setTimeout(function () {
26068 if (_t.hoverState == 'in') {
26071 }, this.delay.show);
26075 clearTimeout(this.timeout);
26077 this.hoverState = 'out';
26078 if (!this.delay || !this.delay.hide) {
26084 this.timeout = setTimeout(function () {
26085 //Roo.log("leave - timeout");
26087 if (_t.hoverState == 'out') {
26089 Roo.bootstrap.Tooltip.currentEl = false;
26094 show : function (msg)
26097 this.render(document.body);
26100 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26102 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26104 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26106 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26108 var placement = typeof this.placement == 'function' ?
26109 this.placement.call(this, this.el, on_el) :
26112 var autoToken = /\s?auto?\s?/i;
26113 var autoPlace = autoToken.test(placement);
26115 placement = placement.replace(autoToken, '') || 'top';
26119 //this.el.setXY([0,0]);
26121 //this.el.dom.style.display='block';
26123 //this.el.appendTo(on_el);
26125 var p = this.getPosition();
26126 var box = this.el.getBox();
26132 var align = this.alignment[placement];
26134 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26136 if(placement == 'top' || placement == 'bottom'){
26138 placement = 'right';
26141 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26142 placement = 'left';
26145 var scroll = Roo.select('body', true).first().getScroll();
26147 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26153 this.el.alignTo(this.bindEl, align[0],align[1]);
26154 //var arrow = this.el.select('.arrow',true).first();
26155 //arrow.set(align[2],
26157 this.el.addClass(placement);
26159 this.el.addClass('in fade');
26161 this.hoverState = null;
26163 if (this.el.hasClass('fade')) {
26174 //this.el.setXY([0,0]);
26175 this.el.removeClass('in');
26191 * @class Roo.bootstrap.LocationPicker
26192 * @extends Roo.bootstrap.Component
26193 * Bootstrap LocationPicker class
26194 * @cfg {Number} latitude Position when init default 0
26195 * @cfg {Number} longitude Position when init default 0
26196 * @cfg {Number} zoom default 15
26197 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26198 * @cfg {Boolean} mapTypeControl default false
26199 * @cfg {Boolean} disableDoubleClickZoom default false
26200 * @cfg {Boolean} scrollwheel default true
26201 * @cfg {Boolean} streetViewControl default false
26202 * @cfg {Number} radius default 0
26203 * @cfg {String} locationName
26204 * @cfg {Boolean} draggable default true
26205 * @cfg {Boolean} enableAutocomplete default false
26206 * @cfg {Boolean} enableReverseGeocode default true
26207 * @cfg {String} markerTitle
26210 * Create a new LocationPicker
26211 * @param {Object} config The config object
26215 Roo.bootstrap.LocationPicker = function(config){
26217 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26222 * Fires when the picker initialized.
26223 * @param {Roo.bootstrap.LocationPicker} this
26224 * @param {Google Location} location
26228 * @event positionchanged
26229 * Fires when the picker position changed.
26230 * @param {Roo.bootstrap.LocationPicker} this
26231 * @param {Google Location} location
26233 positionchanged : true,
26236 * Fires when the map resize.
26237 * @param {Roo.bootstrap.LocationPicker} this
26242 * Fires when the map show.
26243 * @param {Roo.bootstrap.LocationPicker} this
26248 * Fires when the map hide.
26249 * @param {Roo.bootstrap.LocationPicker} this
26254 * Fires when click the map.
26255 * @param {Roo.bootstrap.LocationPicker} this
26256 * @param {Map event} e
26260 * @event mapRightClick
26261 * Fires when right click the map.
26262 * @param {Roo.bootstrap.LocationPicker} this
26263 * @param {Map event} e
26265 mapRightClick : true,
26267 * @event markerClick
26268 * Fires when click the marker.
26269 * @param {Roo.bootstrap.LocationPicker} this
26270 * @param {Map event} e
26272 markerClick : true,
26274 * @event markerRightClick
26275 * Fires when right click the marker.
26276 * @param {Roo.bootstrap.LocationPicker} this
26277 * @param {Map event} e
26279 markerRightClick : true,
26281 * @event OverlayViewDraw
26282 * Fires when OverlayView Draw
26283 * @param {Roo.bootstrap.LocationPicker} this
26285 OverlayViewDraw : true,
26287 * @event OverlayViewOnAdd
26288 * Fires when OverlayView Draw
26289 * @param {Roo.bootstrap.LocationPicker} this
26291 OverlayViewOnAdd : true,
26293 * @event OverlayViewOnRemove
26294 * Fires when OverlayView Draw
26295 * @param {Roo.bootstrap.LocationPicker} this
26297 OverlayViewOnRemove : true,
26299 * @event OverlayViewShow
26300 * Fires when OverlayView Draw
26301 * @param {Roo.bootstrap.LocationPicker} this
26302 * @param {Pixel} cpx
26304 OverlayViewShow : true,
26306 * @event OverlayViewHide
26307 * Fires when OverlayView Draw
26308 * @param {Roo.bootstrap.LocationPicker} this
26310 OverlayViewHide : true,
26312 * @event loadexception
26313 * Fires when load google lib failed.
26314 * @param {Roo.bootstrap.LocationPicker} this
26316 loadexception : true
26321 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26323 gMapContext: false,
26329 mapTypeControl: false,
26330 disableDoubleClickZoom: false,
26332 streetViewControl: false,
26336 enableAutocomplete: false,
26337 enableReverseGeocode: true,
26340 getAutoCreate: function()
26345 cls: 'roo-location-picker'
26351 initEvents: function(ct, position)
26353 if(!this.el.getWidth() || this.isApplied()){
26357 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26362 initial: function()
26364 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26365 this.fireEvent('loadexception', this);
26369 if(!this.mapTypeId){
26370 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26373 this.gMapContext = this.GMapContext();
26375 this.initOverlayView();
26377 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26381 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26382 _this.setPosition(_this.gMapContext.marker.position);
26385 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26386 _this.fireEvent('mapClick', this, event);
26390 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26391 _this.fireEvent('mapRightClick', this, event);
26395 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26396 _this.fireEvent('markerClick', this, event);
26400 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26401 _this.fireEvent('markerRightClick', this, event);
26405 this.setPosition(this.gMapContext.location);
26407 this.fireEvent('initial', this, this.gMapContext.location);
26410 initOverlayView: function()
26414 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26418 _this.fireEvent('OverlayViewDraw', _this);
26423 _this.fireEvent('OverlayViewOnAdd', _this);
26426 onRemove: function()
26428 _this.fireEvent('OverlayViewOnRemove', _this);
26431 show: function(cpx)
26433 _this.fireEvent('OverlayViewShow', _this, cpx);
26438 _this.fireEvent('OverlayViewHide', _this);
26444 fromLatLngToContainerPixel: function(event)
26446 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26449 isApplied: function()
26451 return this.getGmapContext() == false ? false : true;
26454 getGmapContext: function()
26456 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26459 GMapContext: function()
26461 var position = new google.maps.LatLng(this.latitude, this.longitude);
26463 var _map = new google.maps.Map(this.el.dom, {
26466 mapTypeId: this.mapTypeId,
26467 mapTypeControl: this.mapTypeControl,
26468 disableDoubleClickZoom: this.disableDoubleClickZoom,
26469 scrollwheel: this.scrollwheel,
26470 streetViewControl: this.streetViewControl,
26471 locationName: this.locationName,
26472 draggable: this.draggable,
26473 enableAutocomplete: this.enableAutocomplete,
26474 enableReverseGeocode: this.enableReverseGeocode
26477 var _marker = new google.maps.Marker({
26478 position: position,
26480 title: this.markerTitle,
26481 draggable: this.draggable
26488 location: position,
26489 radius: this.radius,
26490 locationName: this.locationName,
26491 addressComponents: {
26492 formatted_address: null,
26493 addressLine1: null,
26494 addressLine2: null,
26496 streetNumber: null,
26500 stateOrProvince: null
26503 domContainer: this.el.dom,
26504 geodecoder: new google.maps.Geocoder()
26508 drawCircle: function(center, radius, options)
26510 if (this.gMapContext.circle != null) {
26511 this.gMapContext.circle.setMap(null);
26515 options = Roo.apply({}, options, {
26516 strokeColor: "#0000FF",
26517 strokeOpacity: .35,
26519 fillColor: "#0000FF",
26523 options.map = this.gMapContext.map;
26524 options.radius = radius;
26525 options.center = center;
26526 this.gMapContext.circle = new google.maps.Circle(options);
26527 return this.gMapContext.circle;
26533 setPosition: function(location)
26535 this.gMapContext.location = location;
26536 this.gMapContext.marker.setPosition(location);
26537 this.gMapContext.map.panTo(location);
26538 this.drawCircle(location, this.gMapContext.radius, {});
26542 if (this.gMapContext.settings.enableReverseGeocode) {
26543 this.gMapContext.geodecoder.geocode({
26544 latLng: this.gMapContext.location
26545 }, function(results, status) {
26547 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26548 _this.gMapContext.locationName = results[0].formatted_address;
26549 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26551 _this.fireEvent('positionchanged', this, location);
26558 this.fireEvent('positionchanged', this, location);
26563 google.maps.event.trigger(this.gMapContext.map, "resize");
26565 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26567 this.fireEvent('resize', this);
26570 setPositionByLatLng: function(latitude, longitude)
26572 this.setPosition(new google.maps.LatLng(latitude, longitude));
26575 getCurrentPosition: function()
26578 latitude: this.gMapContext.location.lat(),
26579 longitude: this.gMapContext.location.lng()
26583 getAddressName: function()
26585 return this.gMapContext.locationName;
26588 getAddressComponents: function()
26590 return this.gMapContext.addressComponents;
26593 address_component_from_google_geocode: function(address_components)
26597 for (var i = 0; i < address_components.length; i++) {
26598 var component = address_components[i];
26599 if (component.types.indexOf("postal_code") >= 0) {
26600 result.postalCode = component.short_name;
26601 } else if (component.types.indexOf("street_number") >= 0) {
26602 result.streetNumber = component.short_name;
26603 } else if (component.types.indexOf("route") >= 0) {
26604 result.streetName = component.short_name;
26605 } else if (component.types.indexOf("neighborhood") >= 0) {
26606 result.city = component.short_name;
26607 } else if (component.types.indexOf("locality") >= 0) {
26608 result.city = component.short_name;
26609 } else if (component.types.indexOf("sublocality") >= 0) {
26610 result.district = component.short_name;
26611 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26612 result.stateOrProvince = component.short_name;
26613 } else if (component.types.indexOf("country") >= 0) {
26614 result.country = component.short_name;
26618 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26619 result.addressLine2 = "";
26623 setZoomLevel: function(zoom)
26625 this.gMapContext.map.setZoom(zoom);
26638 this.fireEvent('show', this);
26649 this.fireEvent('hide', this);
26654 Roo.apply(Roo.bootstrap.LocationPicker, {
26656 OverlayView : function(map, options)
26658 options = options || {};
26672 * @class Roo.bootstrap.Alert
26673 * @extends Roo.bootstrap.Component
26674 * Bootstrap Alert class
26675 * @cfg {String} title The title of alert
26676 * @cfg {String} html The content of alert
26677 * @cfg {String} weight ( success | info | warning | danger )
26678 * @cfg {String} faicon font-awesomeicon
26681 * Create a new alert
26682 * @param {Object} config The config object
26686 Roo.bootstrap.Alert = function(config){
26687 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26691 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26698 getAutoCreate : function()
26707 cls : 'roo-alert-icon'
26712 cls : 'roo-alert-title',
26717 cls : 'roo-alert-text',
26724 cfg.cn[0].cls += ' fa ' + this.faicon;
26728 cfg.cls += ' alert-' + this.weight;
26734 initEvents: function()
26736 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26739 setTitle : function(str)
26741 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26744 setText : function(str)
26746 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26749 setWeight : function(weight)
26752 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26755 this.weight = weight;
26757 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26760 setIcon : function(icon)
26763 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26766 this.faicon = icon;
26768 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26789 * @class Roo.bootstrap.UploadCropbox
26790 * @extends Roo.bootstrap.Component
26791 * Bootstrap UploadCropbox class
26792 * @cfg {String} emptyText show when image has been loaded
26793 * @cfg {String} rotateNotify show when image too small to rotate
26794 * @cfg {Number} errorTimeout default 3000
26795 * @cfg {Number} minWidth default 300
26796 * @cfg {Number} minHeight default 300
26797 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26798 * @cfg {Boolean} isDocument (true|false) default false
26799 * @cfg {String} url action url
26800 * @cfg {String} paramName default 'imageUpload'
26801 * @cfg {String} method default POST
26802 * @cfg {Boolean} loadMask (true|false) default true
26803 * @cfg {Boolean} loadingText default 'Loading...'
26806 * Create a new UploadCropbox
26807 * @param {Object} config The config object
26810 Roo.bootstrap.UploadCropbox = function(config){
26811 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26815 * @event beforeselectfile
26816 * Fire before select file
26817 * @param {Roo.bootstrap.UploadCropbox} this
26819 "beforeselectfile" : true,
26822 * Fire after initEvent
26823 * @param {Roo.bootstrap.UploadCropbox} this
26828 * Fire after initEvent
26829 * @param {Roo.bootstrap.UploadCropbox} this
26830 * @param {String} data
26835 * Fire when preparing the file data
26836 * @param {Roo.bootstrap.UploadCropbox} this
26837 * @param {Object} file
26842 * Fire when get exception
26843 * @param {Roo.bootstrap.UploadCropbox} this
26844 * @param {XMLHttpRequest} xhr
26846 "exception" : true,
26848 * @event beforeloadcanvas
26849 * Fire before load the canvas
26850 * @param {Roo.bootstrap.UploadCropbox} this
26851 * @param {String} src
26853 "beforeloadcanvas" : true,
26856 * Fire when trash image
26857 * @param {Roo.bootstrap.UploadCropbox} this
26862 * Fire when download the image
26863 * @param {Roo.bootstrap.UploadCropbox} this
26867 * @event footerbuttonclick
26868 * Fire when footerbuttonclick
26869 * @param {Roo.bootstrap.UploadCropbox} this
26870 * @param {String} type
26872 "footerbuttonclick" : true,
26876 * @param {Roo.bootstrap.UploadCropbox} this
26881 * Fire when rotate the image
26882 * @param {Roo.bootstrap.UploadCropbox} this
26883 * @param {String} pos
26888 * Fire when inspect the file
26889 * @param {Roo.bootstrap.UploadCropbox} this
26890 * @param {Object} file
26895 * Fire when xhr upload the file
26896 * @param {Roo.bootstrap.UploadCropbox} this
26897 * @param {Object} data
26902 * Fire when arrange the file data
26903 * @param {Roo.bootstrap.UploadCropbox} this
26904 * @param {Object} formData
26909 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26912 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26914 emptyText : 'Click to upload image',
26915 rotateNotify : 'Image is too small to rotate',
26916 errorTimeout : 3000,
26930 cropType : 'image/jpeg',
26932 canvasLoaded : false,
26933 isDocument : false,
26935 paramName : 'imageUpload',
26937 loadingText : 'Loading...',
26940 getAutoCreate : function()
26944 cls : 'roo-upload-cropbox',
26948 cls : 'roo-upload-cropbox-selector',
26953 cls : 'roo-upload-cropbox-body',
26954 style : 'cursor:pointer',
26958 cls : 'roo-upload-cropbox-preview'
26962 cls : 'roo-upload-cropbox-thumb'
26966 cls : 'roo-upload-cropbox-empty-notify',
26967 html : this.emptyText
26971 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26972 html : this.rotateNotify
26978 cls : 'roo-upload-cropbox-footer',
26981 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26991 onRender : function(ct, position)
26993 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26995 if (this.buttons.length) {
26997 Roo.each(this.buttons, function(bb) {
26999 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27001 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27007 this.maskEl = this.el;
27011 initEvents : function()
27013 this.urlAPI = (window.createObjectURL && window) ||
27014 (window.URL && URL.revokeObjectURL && URL) ||
27015 (window.webkitURL && webkitURL);
27017 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27018 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27020 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27021 this.selectorEl.hide();
27023 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27024 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27026 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27027 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27028 this.thumbEl.hide();
27030 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27031 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27033 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27034 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27035 this.errorEl.hide();
27037 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27038 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27039 this.footerEl.hide();
27041 this.setThumbBoxSize();
27047 this.fireEvent('initial', this);
27054 window.addEventListener("resize", function() { _this.resize(); } );
27056 this.bodyEl.on('click', this.beforeSelectFile, this);
27059 this.bodyEl.on('touchstart', this.onTouchStart, this);
27060 this.bodyEl.on('touchmove', this.onTouchMove, this);
27061 this.bodyEl.on('touchend', this.onTouchEnd, this);
27065 this.bodyEl.on('mousedown', this.onMouseDown, this);
27066 this.bodyEl.on('mousemove', this.onMouseMove, this);
27067 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27068 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27069 Roo.get(document).on('mouseup', this.onMouseUp, this);
27072 this.selectorEl.on('change', this.onFileSelected, this);
27078 this.baseScale = 1;
27080 this.baseRotate = 1;
27081 this.dragable = false;
27082 this.pinching = false;
27085 this.cropData = false;
27086 this.notifyEl.dom.innerHTML = this.emptyText;
27088 this.selectorEl.dom.value = '';
27092 resize : function()
27094 if(this.fireEvent('resize', this) != false){
27095 this.setThumbBoxPosition();
27096 this.setCanvasPosition();
27100 onFooterButtonClick : function(e, el, o, type)
27103 case 'rotate-left' :
27104 this.onRotateLeft(e);
27106 case 'rotate-right' :
27107 this.onRotateRight(e);
27110 this.beforeSelectFile(e);
27125 this.fireEvent('footerbuttonclick', this, type);
27128 beforeSelectFile : function(e)
27130 e.preventDefault();
27132 if(this.fireEvent('beforeselectfile', this) != false){
27133 this.selectorEl.dom.click();
27137 onFileSelected : function(e)
27139 e.preventDefault();
27141 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27145 var file = this.selectorEl.dom.files[0];
27147 if(this.fireEvent('inspect', this, file) != false){
27148 this.prepare(file);
27153 trash : function(e)
27155 this.fireEvent('trash', this);
27158 download : function(e)
27160 this.fireEvent('download', this);
27163 loadCanvas : function(src)
27165 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27169 this.imageEl = document.createElement('img');
27173 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27175 this.imageEl.src = src;
27179 onLoadCanvas : function()
27181 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27182 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27184 this.bodyEl.un('click', this.beforeSelectFile, this);
27186 this.notifyEl.hide();
27187 this.thumbEl.show();
27188 this.footerEl.show();
27190 this.baseRotateLevel();
27192 if(this.isDocument){
27193 this.setThumbBoxSize();
27196 this.setThumbBoxPosition();
27198 this.baseScaleLevel();
27204 this.canvasLoaded = true;
27207 this.maskEl.unmask();
27212 setCanvasPosition : function()
27214 if(!this.canvasEl){
27218 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27219 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27221 this.previewEl.setLeft(pw);
27222 this.previewEl.setTop(ph);
27226 onMouseDown : function(e)
27230 this.dragable = true;
27231 this.pinching = false;
27233 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27234 this.dragable = false;
27238 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27239 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27243 onMouseMove : function(e)
27247 if(!this.canvasLoaded){
27251 if (!this.dragable){
27255 var minX = Math.ceil(this.thumbEl.getLeft(true));
27256 var minY = Math.ceil(this.thumbEl.getTop(true));
27258 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27259 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27261 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27262 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27264 x = x - this.mouseX;
27265 y = y - this.mouseY;
27267 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27268 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27270 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27271 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27273 this.previewEl.setLeft(bgX);
27274 this.previewEl.setTop(bgY);
27276 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27277 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27280 onMouseUp : function(e)
27284 this.dragable = false;
27287 onMouseWheel : function(e)
27291 this.startScale = this.scale;
27293 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27295 if(!this.zoomable()){
27296 this.scale = this.startScale;
27305 zoomable : function()
27307 var minScale = this.thumbEl.getWidth() / this.minWidth;
27309 if(this.minWidth < this.minHeight){
27310 minScale = this.thumbEl.getHeight() / this.minHeight;
27313 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27314 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27318 (this.rotate == 0 || this.rotate == 180) &&
27320 width > this.imageEl.OriginWidth ||
27321 height > this.imageEl.OriginHeight ||
27322 (width < this.minWidth && height < this.minHeight)
27330 (this.rotate == 90 || this.rotate == 270) &&
27332 width > this.imageEl.OriginWidth ||
27333 height > this.imageEl.OriginHeight ||
27334 (width < this.minHeight && height < this.minWidth)
27341 !this.isDocument &&
27342 (this.rotate == 0 || this.rotate == 180) &&
27344 width < this.minWidth ||
27345 width > this.imageEl.OriginWidth ||
27346 height < this.minHeight ||
27347 height > this.imageEl.OriginHeight
27354 !this.isDocument &&
27355 (this.rotate == 90 || this.rotate == 270) &&
27357 width < this.minHeight ||
27358 width > this.imageEl.OriginWidth ||
27359 height < this.minWidth ||
27360 height > this.imageEl.OriginHeight
27370 onRotateLeft : function(e)
27372 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27374 var minScale = this.thumbEl.getWidth() / this.minWidth;
27376 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27377 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27379 this.startScale = this.scale;
27381 while (this.getScaleLevel() < minScale){
27383 this.scale = this.scale + 1;
27385 if(!this.zoomable()){
27390 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27391 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27396 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27403 this.scale = this.startScale;
27405 this.onRotateFail();
27410 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27412 if(this.isDocument){
27413 this.setThumbBoxSize();
27414 this.setThumbBoxPosition();
27415 this.setCanvasPosition();
27420 this.fireEvent('rotate', this, 'left');
27424 onRotateRight : function(e)
27426 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27428 var minScale = this.thumbEl.getWidth() / this.minWidth;
27430 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27431 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27433 this.startScale = this.scale;
27435 while (this.getScaleLevel() < minScale){
27437 this.scale = this.scale + 1;
27439 if(!this.zoomable()){
27444 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27445 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27450 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27457 this.scale = this.startScale;
27459 this.onRotateFail();
27464 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27466 if(this.isDocument){
27467 this.setThumbBoxSize();
27468 this.setThumbBoxPosition();
27469 this.setCanvasPosition();
27474 this.fireEvent('rotate', this, 'right');
27477 onRotateFail : function()
27479 this.errorEl.show(true);
27483 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27488 this.previewEl.dom.innerHTML = '';
27490 var canvasEl = document.createElement("canvas");
27492 var contextEl = canvasEl.getContext("2d");
27494 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27495 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27496 var center = this.imageEl.OriginWidth / 2;
27498 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27499 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27500 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27501 center = this.imageEl.OriginHeight / 2;
27504 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27506 contextEl.translate(center, center);
27507 contextEl.rotate(this.rotate * Math.PI / 180);
27509 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27511 this.canvasEl = document.createElement("canvas");
27513 this.contextEl = this.canvasEl.getContext("2d");
27515 switch (this.rotate) {
27518 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27519 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27521 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27526 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27527 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27529 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27530 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);
27534 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27539 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27540 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27542 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27543 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);
27547 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);
27552 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27553 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27555 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27556 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27560 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);
27567 this.previewEl.appendChild(this.canvasEl);
27569 this.setCanvasPosition();
27574 if(!this.canvasLoaded){
27578 var imageCanvas = document.createElement("canvas");
27580 var imageContext = imageCanvas.getContext("2d");
27582 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27583 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27585 var center = imageCanvas.width / 2;
27587 imageContext.translate(center, center);
27589 imageContext.rotate(this.rotate * Math.PI / 180);
27591 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27593 var canvas = document.createElement("canvas");
27595 var context = canvas.getContext("2d");
27597 canvas.width = this.minWidth;
27598 canvas.height = this.minHeight;
27600 switch (this.rotate) {
27603 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27604 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27606 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27607 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27609 var targetWidth = this.minWidth - 2 * x;
27610 var targetHeight = this.minHeight - 2 * y;
27614 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27615 scale = targetWidth / width;
27618 if(x > 0 && y == 0){
27619 scale = targetHeight / height;
27622 if(x > 0 && y > 0){
27623 scale = targetWidth / width;
27625 if(width < height){
27626 scale = targetHeight / height;
27630 context.scale(scale, scale);
27632 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27633 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27635 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27636 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27638 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27643 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27644 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27646 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27647 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27649 var targetWidth = this.minWidth - 2 * x;
27650 var targetHeight = this.minHeight - 2 * y;
27654 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27655 scale = targetWidth / width;
27658 if(x > 0 && y == 0){
27659 scale = targetHeight / height;
27662 if(x > 0 && y > 0){
27663 scale = targetWidth / width;
27665 if(width < height){
27666 scale = targetHeight / height;
27670 context.scale(scale, scale);
27672 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27673 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27675 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27676 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27678 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27680 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27685 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27686 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27688 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27689 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27691 var targetWidth = this.minWidth - 2 * x;
27692 var targetHeight = this.minHeight - 2 * y;
27696 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27697 scale = targetWidth / width;
27700 if(x > 0 && y == 0){
27701 scale = targetHeight / height;
27704 if(x > 0 && y > 0){
27705 scale = targetWidth / width;
27707 if(width < height){
27708 scale = targetHeight / height;
27712 context.scale(scale, scale);
27714 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27715 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27717 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27718 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27720 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27721 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27723 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27728 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27729 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27731 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27732 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27734 var targetWidth = this.minWidth - 2 * x;
27735 var targetHeight = this.minHeight - 2 * y;
27739 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27740 scale = targetWidth / width;
27743 if(x > 0 && y == 0){
27744 scale = targetHeight / height;
27747 if(x > 0 && y > 0){
27748 scale = targetWidth / width;
27750 if(width < height){
27751 scale = targetHeight / height;
27755 context.scale(scale, scale);
27757 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27758 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27760 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27761 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27763 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27765 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27772 this.cropData = canvas.toDataURL(this.cropType);
27774 if(this.fireEvent('crop', this, this.cropData) !== false){
27775 this.process(this.file, this.cropData);
27782 setThumbBoxSize : function()
27786 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27787 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27788 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27790 this.minWidth = width;
27791 this.minHeight = height;
27793 if(this.rotate == 90 || this.rotate == 270){
27794 this.minWidth = height;
27795 this.minHeight = width;
27800 width = Math.ceil(this.minWidth * height / this.minHeight);
27802 if(this.minWidth > this.minHeight){
27804 height = Math.ceil(this.minHeight * width / this.minWidth);
27807 this.thumbEl.setStyle({
27808 width : width + 'px',
27809 height : height + 'px'
27816 setThumbBoxPosition : function()
27818 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27819 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27821 this.thumbEl.setLeft(x);
27822 this.thumbEl.setTop(y);
27826 baseRotateLevel : function()
27828 this.baseRotate = 1;
27831 typeof(this.exif) != 'undefined' &&
27832 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27833 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27835 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27838 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27842 baseScaleLevel : function()
27846 if(this.isDocument){
27848 if(this.baseRotate == 6 || this.baseRotate == 8){
27850 height = this.thumbEl.getHeight();
27851 this.baseScale = height / this.imageEl.OriginWidth;
27853 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27854 width = this.thumbEl.getWidth();
27855 this.baseScale = width / this.imageEl.OriginHeight;
27861 height = this.thumbEl.getHeight();
27862 this.baseScale = height / this.imageEl.OriginHeight;
27864 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27865 width = this.thumbEl.getWidth();
27866 this.baseScale = width / this.imageEl.OriginWidth;
27872 if(this.baseRotate == 6 || this.baseRotate == 8){
27874 width = this.thumbEl.getHeight();
27875 this.baseScale = width / this.imageEl.OriginHeight;
27877 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27878 height = this.thumbEl.getWidth();
27879 this.baseScale = height / this.imageEl.OriginHeight;
27882 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27883 height = this.thumbEl.getWidth();
27884 this.baseScale = height / this.imageEl.OriginHeight;
27886 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27887 width = this.thumbEl.getHeight();
27888 this.baseScale = width / this.imageEl.OriginWidth;
27895 width = this.thumbEl.getWidth();
27896 this.baseScale = width / this.imageEl.OriginWidth;
27898 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27899 height = this.thumbEl.getHeight();
27900 this.baseScale = height / this.imageEl.OriginHeight;
27903 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27905 height = this.thumbEl.getHeight();
27906 this.baseScale = height / this.imageEl.OriginHeight;
27908 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27909 width = this.thumbEl.getWidth();
27910 this.baseScale = width / this.imageEl.OriginWidth;
27918 getScaleLevel : function()
27920 return this.baseScale * Math.pow(1.1, this.scale);
27923 onTouchStart : function(e)
27925 if(!this.canvasLoaded){
27926 this.beforeSelectFile(e);
27930 var touches = e.browserEvent.touches;
27936 if(touches.length == 1){
27937 this.onMouseDown(e);
27941 if(touches.length != 2){
27947 for(var i = 0, finger; finger = touches[i]; i++){
27948 coords.push(finger.pageX, finger.pageY);
27951 var x = Math.pow(coords[0] - coords[2], 2);
27952 var y = Math.pow(coords[1] - coords[3], 2);
27954 this.startDistance = Math.sqrt(x + y);
27956 this.startScale = this.scale;
27958 this.pinching = true;
27959 this.dragable = false;
27963 onTouchMove : function(e)
27965 if(!this.pinching && !this.dragable){
27969 var touches = e.browserEvent.touches;
27976 this.onMouseMove(e);
27982 for(var i = 0, finger; finger = touches[i]; i++){
27983 coords.push(finger.pageX, finger.pageY);
27986 var x = Math.pow(coords[0] - coords[2], 2);
27987 var y = Math.pow(coords[1] - coords[3], 2);
27989 this.endDistance = Math.sqrt(x + y);
27991 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27993 if(!this.zoomable()){
27994 this.scale = this.startScale;
28002 onTouchEnd : function(e)
28004 this.pinching = false;
28005 this.dragable = false;
28009 process : function(file, crop)
28012 this.maskEl.mask(this.loadingText);
28015 this.xhr = new XMLHttpRequest();
28017 file.xhr = this.xhr;
28019 this.xhr.open(this.method, this.url, true);
28022 "Accept": "application/json",
28023 "Cache-Control": "no-cache",
28024 "X-Requested-With": "XMLHttpRequest"
28027 for (var headerName in headers) {
28028 var headerValue = headers[headerName];
28030 this.xhr.setRequestHeader(headerName, headerValue);
28036 this.xhr.onload = function()
28038 _this.xhrOnLoad(_this.xhr);
28041 this.xhr.onerror = function()
28043 _this.xhrOnError(_this.xhr);
28046 var formData = new FormData();
28048 formData.append('returnHTML', 'NO');
28051 formData.append('crop', crop);
28054 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28055 formData.append(this.paramName, file, file.name);
28058 if(typeof(file.filename) != 'undefined'){
28059 formData.append('filename', file.filename);
28062 if(typeof(file.mimetype) != 'undefined'){
28063 formData.append('mimetype', file.mimetype);
28066 if(this.fireEvent('arrange', this, formData) != false){
28067 this.xhr.send(formData);
28071 xhrOnLoad : function(xhr)
28074 this.maskEl.unmask();
28077 if (xhr.readyState !== 4) {
28078 this.fireEvent('exception', this, xhr);
28082 var response = Roo.decode(xhr.responseText);
28084 if(!response.success){
28085 this.fireEvent('exception', this, xhr);
28089 var response = Roo.decode(xhr.responseText);
28091 this.fireEvent('upload', this, response);
28095 xhrOnError : function()
28098 this.maskEl.unmask();
28101 Roo.log('xhr on error');
28103 var response = Roo.decode(xhr.responseText);
28109 prepare : function(file)
28112 this.maskEl.mask(this.loadingText);
28118 if(typeof(file) === 'string'){
28119 this.loadCanvas(file);
28123 if(!file || !this.urlAPI){
28128 this.cropType = file.type;
28132 if(this.fireEvent('prepare', this, this.file) != false){
28134 var reader = new FileReader();
28136 reader.onload = function (e) {
28137 if (e.target.error) {
28138 Roo.log(e.target.error);
28142 var buffer = e.target.result,
28143 dataView = new DataView(buffer),
28145 maxOffset = dataView.byteLength - 4,
28149 if (dataView.getUint16(0) === 0xffd8) {
28150 while (offset < maxOffset) {
28151 markerBytes = dataView.getUint16(offset);
28153 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28154 markerLength = dataView.getUint16(offset + 2) + 2;
28155 if (offset + markerLength > dataView.byteLength) {
28156 Roo.log('Invalid meta data: Invalid segment size.');
28160 if(markerBytes == 0xffe1){
28161 _this.parseExifData(
28168 offset += markerLength;
28178 var url = _this.urlAPI.createObjectURL(_this.file);
28180 _this.loadCanvas(url);
28185 reader.readAsArrayBuffer(this.file);
28191 parseExifData : function(dataView, offset, length)
28193 var tiffOffset = offset + 10,
28197 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28198 // No Exif data, might be XMP data instead
28202 // Check for the ASCII code for "Exif" (0x45786966):
28203 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28204 // No Exif data, might be XMP data instead
28207 if (tiffOffset + 8 > dataView.byteLength) {
28208 Roo.log('Invalid Exif data: Invalid segment size.');
28211 // Check for the two null bytes:
28212 if (dataView.getUint16(offset + 8) !== 0x0000) {
28213 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28216 // Check the byte alignment:
28217 switch (dataView.getUint16(tiffOffset)) {
28219 littleEndian = true;
28222 littleEndian = false;
28225 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28228 // Check for the TIFF tag marker (0x002A):
28229 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28230 Roo.log('Invalid Exif data: Missing TIFF marker.');
28233 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28234 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28236 this.parseExifTags(
28239 tiffOffset + dirOffset,
28244 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28249 if (dirOffset + 6 > dataView.byteLength) {
28250 Roo.log('Invalid Exif data: Invalid directory offset.');
28253 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28254 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28255 if (dirEndOffset + 4 > dataView.byteLength) {
28256 Roo.log('Invalid Exif data: Invalid directory size.');
28259 for (i = 0; i < tagsNumber; i += 1) {
28263 dirOffset + 2 + 12 * i, // tag offset
28267 // Return the offset to the next directory:
28268 return dataView.getUint32(dirEndOffset, littleEndian);
28271 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28273 var tag = dataView.getUint16(offset, littleEndian);
28275 this.exif[tag] = this.getExifValue(
28279 dataView.getUint16(offset + 2, littleEndian), // tag type
28280 dataView.getUint32(offset + 4, littleEndian), // tag length
28285 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28287 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28296 Roo.log('Invalid Exif data: Invalid tag type.');
28300 tagSize = tagType.size * length;
28301 // Determine if the value is contained in the dataOffset bytes,
28302 // or if the value at the dataOffset is a pointer to the actual data:
28303 dataOffset = tagSize > 4 ?
28304 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28305 if (dataOffset + tagSize > dataView.byteLength) {
28306 Roo.log('Invalid Exif data: Invalid data offset.');
28309 if (length === 1) {
28310 return tagType.getValue(dataView, dataOffset, littleEndian);
28313 for (i = 0; i < length; i += 1) {
28314 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28317 if (tagType.ascii) {
28319 // Concatenate the chars:
28320 for (i = 0; i < values.length; i += 1) {
28322 // Ignore the terminating NULL byte(s):
28323 if (c === '\u0000') {
28335 Roo.apply(Roo.bootstrap.UploadCropbox, {
28337 'Orientation': 0x0112
28341 1: 0, //'top-left',
28343 3: 180, //'bottom-right',
28344 // 4: 'bottom-left',
28346 6: 90, //'right-top',
28347 // 7: 'right-bottom',
28348 8: 270 //'left-bottom'
28352 // byte, 8-bit unsigned int:
28354 getValue: function (dataView, dataOffset) {
28355 return dataView.getUint8(dataOffset);
28359 // ascii, 8-bit byte:
28361 getValue: function (dataView, dataOffset) {
28362 return String.fromCharCode(dataView.getUint8(dataOffset));
28367 // short, 16 bit int:
28369 getValue: function (dataView, dataOffset, littleEndian) {
28370 return dataView.getUint16(dataOffset, littleEndian);
28374 // long, 32 bit int:
28376 getValue: function (dataView, dataOffset, littleEndian) {
28377 return dataView.getUint32(dataOffset, littleEndian);
28381 // rational = two long values, first is numerator, second is denominator:
28383 getValue: function (dataView, dataOffset, littleEndian) {
28384 return dataView.getUint32(dataOffset, littleEndian) /
28385 dataView.getUint32(dataOffset + 4, littleEndian);
28389 // slong, 32 bit signed int:
28391 getValue: function (dataView, dataOffset, littleEndian) {
28392 return dataView.getInt32(dataOffset, littleEndian);
28396 // srational, two slongs, first is numerator, second is denominator:
28398 getValue: function (dataView, dataOffset, littleEndian) {
28399 return dataView.getInt32(dataOffset, littleEndian) /
28400 dataView.getInt32(dataOffset + 4, littleEndian);
28410 cls : 'btn-group roo-upload-cropbox-rotate-left',
28411 action : 'rotate-left',
28415 cls : 'btn btn-default',
28416 html : '<i class="fa fa-undo"></i>'
28422 cls : 'btn-group roo-upload-cropbox-picture',
28423 action : 'picture',
28427 cls : 'btn btn-default',
28428 html : '<i class="fa fa-picture-o"></i>'
28434 cls : 'btn-group roo-upload-cropbox-rotate-right',
28435 action : 'rotate-right',
28439 cls : 'btn btn-default',
28440 html : '<i class="fa fa-repeat"></i>'
28448 cls : 'btn-group roo-upload-cropbox-rotate-left',
28449 action : 'rotate-left',
28453 cls : 'btn btn-default',
28454 html : '<i class="fa fa-undo"></i>'
28460 cls : 'btn-group roo-upload-cropbox-download',
28461 action : 'download',
28465 cls : 'btn btn-default',
28466 html : '<i class="fa fa-download"></i>'
28472 cls : 'btn-group roo-upload-cropbox-crop',
28477 cls : 'btn btn-default',
28478 html : '<i class="fa fa-crop"></i>'
28484 cls : 'btn-group roo-upload-cropbox-trash',
28489 cls : 'btn btn-default',
28490 html : '<i class="fa fa-trash"></i>'
28496 cls : 'btn-group roo-upload-cropbox-rotate-right',
28497 action : 'rotate-right',
28501 cls : 'btn btn-default',
28502 html : '<i class="fa fa-repeat"></i>'
28510 cls : 'btn-group roo-upload-cropbox-rotate-left',
28511 action : 'rotate-left',
28515 cls : 'btn btn-default',
28516 html : '<i class="fa fa-undo"></i>'
28522 cls : 'btn-group roo-upload-cropbox-rotate-right',
28523 action : 'rotate-right',
28527 cls : 'btn btn-default',
28528 html : '<i class="fa fa-repeat"></i>'
28541 * @class Roo.bootstrap.DocumentManager
28542 * @extends Roo.bootstrap.Component
28543 * Bootstrap DocumentManager class
28544 * @cfg {String} paramName default 'imageUpload'
28545 * @cfg {String} toolTipName default 'filename'
28546 * @cfg {String} method default POST
28547 * @cfg {String} url action url
28548 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28549 * @cfg {Boolean} multiple multiple upload default true
28550 * @cfg {Number} thumbSize default 300
28551 * @cfg {String} fieldLabel
28552 * @cfg {Number} labelWidth default 4
28553 * @cfg {String} labelAlign (left|top) default left
28554 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28555 * @cfg {Number} labellg set the width of label (1-12)
28556 * @cfg {Number} labelmd set the width of label (1-12)
28557 * @cfg {Number} labelsm set the width of label (1-12)
28558 * @cfg {Number} labelxs set the width of label (1-12)
28561 * Create a new DocumentManager
28562 * @param {Object} config The config object
28565 Roo.bootstrap.DocumentManager = function(config){
28566 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28569 this.delegates = [];
28574 * Fire when initial the DocumentManager
28575 * @param {Roo.bootstrap.DocumentManager} this
28580 * inspect selected file
28581 * @param {Roo.bootstrap.DocumentManager} this
28582 * @param {File} file
28587 * Fire when xhr load exception
28588 * @param {Roo.bootstrap.DocumentManager} this
28589 * @param {XMLHttpRequest} xhr
28591 "exception" : true,
28593 * @event afterupload
28594 * Fire when xhr load exception
28595 * @param {Roo.bootstrap.DocumentManager} this
28596 * @param {XMLHttpRequest} xhr
28598 "afterupload" : true,
28601 * prepare the form data
28602 * @param {Roo.bootstrap.DocumentManager} this
28603 * @param {Object} formData
28608 * Fire when remove the file
28609 * @param {Roo.bootstrap.DocumentManager} this
28610 * @param {Object} file
28615 * Fire after refresh the file
28616 * @param {Roo.bootstrap.DocumentManager} this
28621 * Fire after click the image
28622 * @param {Roo.bootstrap.DocumentManager} this
28623 * @param {Object} file
28628 * Fire when upload a image and editable set to true
28629 * @param {Roo.bootstrap.DocumentManager} this
28630 * @param {Object} file
28634 * @event beforeselectfile
28635 * Fire before select file
28636 * @param {Roo.bootstrap.DocumentManager} this
28638 "beforeselectfile" : true,
28641 * Fire before process file
28642 * @param {Roo.bootstrap.DocumentManager} this
28643 * @param {Object} file
28647 * @event previewrendered
28648 * Fire when preview rendered
28649 * @param {Roo.bootstrap.DocumentManager} this
28650 * @param {Object} file
28652 "previewrendered" : true
28657 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28666 paramName : 'imageUpload',
28667 toolTipName : 'filename',
28670 labelAlign : 'left',
28680 getAutoCreate : function()
28682 var managerWidget = {
28684 cls : 'roo-document-manager',
28688 cls : 'roo-document-manager-selector',
28693 cls : 'roo-document-manager-uploader',
28697 cls : 'roo-document-manager-upload-btn',
28698 html : '<i class="fa fa-plus"></i>'
28709 cls : 'column col-md-12',
28714 if(this.fieldLabel.length){
28719 cls : 'column col-md-12',
28720 html : this.fieldLabel
28724 cls : 'column col-md-12',
28729 if(this.labelAlign == 'left'){
28734 html : this.fieldLabel
28743 if(this.labelWidth > 12){
28744 content[0].style = "width: " + this.labelWidth + 'px';
28747 if(this.labelWidth < 13 && this.labelmd == 0){
28748 this.labelmd = this.labelWidth;
28751 if(this.labellg > 0){
28752 content[0].cls += ' col-lg-' + this.labellg;
28753 content[1].cls += ' col-lg-' + (12 - this.labellg);
28756 if(this.labelmd > 0){
28757 content[0].cls += ' col-md-' + this.labelmd;
28758 content[1].cls += ' col-md-' + (12 - this.labelmd);
28761 if(this.labelsm > 0){
28762 content[0].cls += ' col-sm-' + this.labelsm;
28763 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28766 if(this.labelxs > 0){
28767 content[0].cls += ' col-xs-' + this.labelxs;
28768 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28776 cls : 'row clearfix',
28784 initEvents : function()
28786 this.managerEl = this.el.select('.roo-document-manager', true).first();
28787 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28789 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28790 this.selectorEl.hide();
28793 this.selectorEl.attr('multiple', 'multiple');
28796 this.selectorEl.on('change', this.onFileSelected, this);
28798 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28799 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28801 this.uploader.on('click', this.onUploaderClick, this);
28803 this.renderProgressDialog();
28807 window.addEventListener("resize", function() { _this.refresh(); } );
28809 this.fireEvent('initial', this);
28812 renderProgressDialog : function()
28816 this.progressDialog = new Roo.bootstrap.Modal({
28817 cls : 'roo-document-manager-progress-dialog',
28818 allow_close : false,
28828 btnclick : function() {
28829 _this.uploadCancel();
28835 this.progressDialog.render(Roo.get(document.body));
28837 this.progress = new Roo.bootstrap.Progress({
28838 cls : 'roo-document-manager-progress',
28843 this.progress.render(this.progressDialog.getChildContainer());
28845 this.progressBar = new Roo.bootstrap.ProgressBar({
28846 cls : 'roo-document-manager-progress-bar',
28849 aria_valuemax : 12,
28853 this.progressBar.render(this.progress.getChildContainer());
28856 onUploaderClick : function(e)
28858 e.preventDefault();
28860 if(this.fireEvent('beforeselectfile', this) != false){
28861 this.selectorEl.dom.click();
28866 onFileSelected : function(e)
28868 e.preventDefault();
28870 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28874 Roo.each(this.selectorEl.dom.files, function(file){
28875 if(this.fireEvent('inspect', this, file) != false){
28876 this.files.push(file);
28886 this.selectorEl.dom.value = '';
28888 if(!this.files || !this.files.length){
28892 if(this.boxes > 0 && this.files.length > this.boxes){
28893 this.files = this.files.slice(0, this.boxes);
28896 this.uploader.show();
28898 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28899 this.uploader.hide();
28908 Roo.each(this.files, function(file){
28910 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28911 var f = this.renderPreview(file);
28916 if(file.type.indexOf('image') != -1){
28917 this.delegates.push(
28919 _this.process(file);
28920 }).createDelegate(this)
28928 _this.process(file);
28929 }).createDelegate(this)
28934 this.files = files;
28936 this.delegates = this.delegates.concat(docs);
28938 if(!this.delegates.length){
28943 this.progressBar.aria_valuemax = this.delegates.length;
28950 arrange : function()
28952 if(!this.delegates.length){
28953 this.progressDialog.hide();
28958 var delegate = this.delegates.shift();
28960 this.progressDialog.show();
28962 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28964 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28969 refresh : function()
28971 this.uploader.show();
28973 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28974 this.uploader.hide();
28977 Roo.isTouch ? this.closable(false) : this.closable(true);
28979 this.fireEvent('refresh', this);
28982 onRemove : function(e, el, o)
28984 e.preventDefault();
28986 this.fireEvent('remove', this, o);
28990 remove : function(o)
28994 Roo.each(this.files, function(file){
28995 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29004 this.files = files;
29011 Roo.each(this.files, function(file){
29016 file.target.remove();
29025 onClick : function(e, el, o)
29027 e.preventDefault();
29029 this.fireEvent('click', this, o);
29033 closable : function(closable)
29035 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29037 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29049 xhrOnLoad : function(xhr)
29051 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29055 if (xhr.readyState !== 4) {
29057 this.fireEvent('exception', this, xhr);
29061 var response = Roo.decode(xhr.responseText);
29063 if(!response.success){
29065 this.fireEvent('exception', this, xhr);
29069 var file = this.renderPreview(response.data);
29071 this.files.push(file);
29075 this.fireEvent('afterupload', this, xhr);
29079 xhrOnError : function(xhr)
29081 Roo.log('xhr on error');
29083 var response = Roo.decode(xhr.responseText);
29090 process : function(file)
29092 if(this.fireEvent('process', this, file) !== false){
29093 if(this.editable && file.type.indexOf('image') != -1){
29094 this.fireEvent('edit', this, file);
29098 this.uploadStart(file, false);
29105 uploadStart : function(file, crop)
29107 this.xhr = new XMLHttpRequest();
29109 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29114 file.xhr = this.xhr;
29116 this.managerEl.createChild({
29118 cls : 'roo-document-manager-loading',
29122 tooltip : file.name,
29123 cls : 'roo-document-manager-thumb',
29124 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29130 this.xhr.open(this.method, this.url, true);
29133 "Accept": "application/json",
29134 "Cache-Control": "no-cache",
29135 "X-Requested-With": "XMLHttpRequest"
29138 for (var headerName in headers) {
29139 var headerValue = headers[headerName];
29141 this.xhr.setRequestHeader(headerName, headerValue);
29147 this.xhr.onload = function()
29149 _this.xhrOnLoad(_this.xhr);
29152 this.xhr.onerror = function()
29154 _this.xhrOnError(_this.xhr);
29157 var formData = new FormData();
29159 formData.append('returnHTML', 'NO');
29162 formData.append('crop', crop);
29165 formData.append(this.paramName, file, file.name);
29172 if(this.fireEvent('prepare', this, formData, options) != false){
29174 if(options.manually){
29178 this.xhr.send(formData);
29182 this.uploadCancel();
29185 uploadCancel : function()
29191 this.delegates = [];
29193 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29200 renderPreview : function(file)
29202 if(typeof(file.target) != 'undefined' && file.target){
29206 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29208 var previewEl = this.managerEl.createChild({
29210 cls : 'roo-document-manager-preview',
29214 tooltip : file[this.toolTipName],
29215 cls : 'roo-document-manager-thumb',
29216 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29221 html : '<i class="fa fa-times-circle"></i>'
29226 var close = previewEl.select('button.close', true).first();
29228 close.on('click', this.onRemove, this, file);
29230 file.target = previewEl;
29232 var image = previewEl.select('img', true).first();
29236 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29238 image.on('click', this.onClick, this, file);
29240 this.fireEvent('previewrendered', this, file);
29246 onPreviewLoad : function(file, image)
29248 if(typeof(file.target) == 'undefined' || !file.target){
29252 var width = image.dom.naturalWidth || image.dom.width;
29253 var height = image.dom.naturalHeight || image.dom.height;
29255 if(width > height){
29256 file.target.addClass('wide');
29260 file.target.addClass('tall');
29265 uploadFromSource : function(file, crop)
29267 this.xhr = new XMLHttpRequest();
29269 this.managerEl.createChild({
29271 cls : 'roo-document-manager-loading',
29275 tooltip : file.name,
29276 cls : 'roo-document-manager-thumb',
29277 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29283 this.xhr.open(this.method, this.url, true);
29286 "Accept": "application/json",
29287 "Cache-Control": "no-cache",
29288 "X-Requested-With": "XMLHttpRequest"
29291 for (var headerName in headers) {
29292 var headerValue = headers[headerName];
29294 this.xhr.setRequestHeader(headerName, headerValue);
29300 this.xhr.onload = function()
29302 _this.xhrOnLoad(_this.xhr);
29305 this.xhr.onerror = function()
29307 _this.xhrOnError(_this.xhr);
29310 var formData = new FormData();
29312 formData.append('returnHTML', 'NO');
29314 formData.append('crop', crop);
29316 if(typeof(file.filename) != 'undefined'){
29317 formData.append('filename', file.filename);
29320 if(typeof(file.mimetype) != 'undefined'){
29321 formData.append('mimetype', file.mimetype);
29326 if(this.fireEvent('prepare', this, formData) != false){
29327 this.xhr.send(formData);
29337 * @class Roo.bootstrap.DocumentViewer
29338 * @extends Roo.bootstrap.Component
29339 * Bootstrap DocumentViewer class
29340 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29341 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29344 * Create a new DocumentViewer
29345 * @param {Object} config The config object
29348 Roo.bootstrap.DocumentViewer = function(config){
29349 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29354 * Fire after initEvent
29355 * @param {Roo.bootstrap.DocumentViewer} this
29361 * @param {Roo.bootstrap.DocumentViewer} this
29366 * Fire after download button
29367 * @param {Roo.bootstrap.DocumentViewer} this
29372 * Fire after trash button
29373 * @param {Roo.bootstrap.DocumentViewer} this
29380 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29382 showDownload : true,
29386 getAutoCreate : function()
29390 cls : 'roo-document-viewer',
29394 cls : 'roo-document-viewer-body',
29398 cls : 'roo-document-viewer-thumb',
29402 cls : 'roo-document-viewer-image'
29410 cls : 'roo-document-viewer-footer',
29413 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29417 cls : 'btn-group roo-document-viewer-download',
29421 cls : 'btn btn-default',
29422 html : '<i class="fa fa-download"></i>'
29428 cls : 'btn-group roo-document-viewer-trash',
29432 cls : 'btn btn-default',
29433 html : '<i class="fa fa-trash"></i>'
29446 initEvents : function()
29448 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29449 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29451 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29452 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29454 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29455 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29457 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29458 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29460 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29461 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29463 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29464 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29466 this.bodyEl.on('click', this.onClick, this);
29467 this.downloadBtn.on('click', this.onDownload, this);
29468 this.trashBtn.on('click', this.onTrash, this);
29470 this.downloadBtn.hide();
29471 this.trashBtn.hide();
29473 if(this.showDownload){
29474 this.downloadBtn.show();
29477 if(this.showTrash){
29478 this.trashBtn.show();
29481 if(!this.showDownload && !this.showTrash) {
29482 this.footerEl.hide();
29487 initial : function()
29489 this.fireEvent('initial', this);
29493 onClick : function(e)
29495 e.preventDefault();
29497 this.fireEvent('click', this);
29500 onDownload : function(e)
29502 e.preventDefault();
29504 this.fireEvent('download', this);
29507 onTrash : function(e)
29509 e.preventDefault();
29511 this.fireEvent('trash', this);
29523 * @class Roo.bootstrap.NavProgressBar
29524 * @extends Roo.bootstrap.Component
29525 * Bootstrap NavProgressBar class
29528 * Create a new nav progress bar
29529 * @param {Object} config The config object
29532 Roo.bootstrap.NavProgressBar = function(config){
29533 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29535 this.bullets = this.bullets || [];
29537 // Roo.bootstrap.NavProgressBar.register(this);
29541 * Fires when the active item changes
29542 * @param {Roo.bootstrap.NavProgressBar} this
29543 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29544 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29551 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29556 getAutoCreate : function()
29558 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29562 cls : 'roo-navigation-bar-group',
29566 cls : 'roo-navigation-top-bar'
29570 cls : 'roo-navigation-bullets-bar',
29574 cls : 'roo-navigation-bar'
29581 cls : 'roo-navigation-bottom-bar'
29591 initEvents: function()
29596 onRender : function(ct, position)
29598 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29600 if(this.bullets.length){
29601 Roo.each(this.bullets, function(b){
29610 addItem : function(cfg)
29612 var item = new Roo.bootstrap.NavProgressItem(cfg);
29614 item.parentId = this.id;
29615 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29618 var top = new Roo.bootstrap.Element({
29620 cls : 'roo-navigation-bar-text'
29623 var bottom = new Roo.bootstrap.Element({
29625 cls : 'roo-navigation-bar-text'
29628 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29629 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29631 var topText = new Roo.bootstrap.Element({
29633 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29636 var bottomText = new Roo.bootstrap.Element({
29638 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29641 topText.onRender(top.el, null);
29642 bottomText.onRender(bottom.el, null);
29645 item.bottomEl = bottom;
29648 this.barItems.push(item);
29653 getActive : function()
29655 var active = false;
29657 Roo.each(this.barItems, function(v){
29659 if (!v.isActive()) {
29671 setActiveItem : function(item)
29675 Roo.each(this.barItems, function(v){
29676 if (v.rid == item.rid) {
29680 if (v.isActive()) {
29681 v.setActive(false);
29686 item.setActive(true);
29688 this.fireEvent('changed', this, item, prev);
29691 getBarItem: function(rid)
29695 Roo.each(this.barItems, function(e) {
29696 if (e.rid != rid) {
29707 indexOfItem : function(item)
29711 Roo.each(this.barItems, function(v, i){
29713 if (v.rid != item.rid) {
29724 setActiveNext : function()
29726 var i = this.indexOfItem(this.getActive());
29728 if (i > this.barItems.length) {
29732 this.setActiveItem(this.barItems[i+1]);
29735 setActivePrev : function()
29737 var i = this.indexOfItem(this.getActive());
29743 this.setActiveItem(this.barItems[i-1]);
29746 format : function()
29748 if(!this.barItems.length){
29752 var width = 100 / this.barItems.length;
29754 Roo.each(this.barItems, function(i){
29755 i.el.setStyle('width', width + '%');
29756 i.topEl.el.setStyle('width', width + '%');
29757 i.bottomEl.el.setStyle('width', width + '%');
29766 * Nav Progress Item
29771 * @class Roo.bootstrap.NavProgressItem
29772 * @extends Roo.bootstrap.Component
29773 * Bootstrap NavProgressItem class
29774 * @cfg {String} rid the reference id
29775 * @cfg {Boolean} active (true|false) Is item active default false
29776 * @cfg {Boolean} disabled (true|false) Is item active default false
29777 * @cfg {String} html
29778 * @cfg {String} position (top|bottom) text position default bottom
29779 * @cfg {String} icon show icon instead of number
29782 * Create a new NavProgressItem
29783 * @param {Object} config The config object
29785 Roo.bootstrap.NavProgressItem = function(config){
29786 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29791 * The raw click event for the entire grid.
29792 * @param {Roo.bootstrap.NavProgressItem} this
29793 * @param {Roo.EventObject} e
29800 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29806 position : 'bottom',
29809 getAutoCreate : function()
29811 var iconCls = 'roo-navigation-bar-item-icon';
29813 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29817 cls: 'roo-navigation-bar-item',
29827 cfg.cls += ' active';
29830 cfg.cls += ' disabled';
29836 disable : function()
29838 this.setDisabled(true);
29841 enable : function()
29843 this.setDisabled(false);
29846 initEvents: function()
29848 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29850 this.iconEl.on('click', this.onClick, this);
29853 onClick : function(e)
29855 e.preventDefault();
29861 if(this.fireEvent('click', this, e) === false){
29865 this.parent().setActiveItem(this);
29868 isActive: function ()
29870 return this.active;
29873 setActive : function(state)
29875 if(this.active == state){
29879 this.active = state;
29882 this.el.addClass('active');
29886 this.el.removeClass('active');
29891 setDisabled : function(state)
29893 if(this.disabled == state){
29897 this.disabled = state;
29900 this.el.addClass('disabled');
29904 this.el.removeClass('disabled');
29907 tooltipEl : function()
29909 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29922 * @class Roo.bootstrap.FieldLabel
29923 * @extends Roo.bootstrap.Component
29924 * Bootstrap FieldLabel class
29925 * @cfg {String} html contents of the element
29926 * @cfg {String} tag tag of the element default label
29927 * @cfg {String} cls class of the element
29928 * @cfg {String} target label target
29929 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29930 * @cfg {String} invalidClass default "text-warning"
29931 * @cfg {String} validClass default "text-success"
29932 * @cfg {String} iconTooltip default "This field is required"
29933 * @cfg {String} indicatorpos (left|right) default left
29936 * Create a new FieldLabel
29937 * @param {Object} config The config object
29940 Roo.bootstrap.FieldLabel = function(config){
29941 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29946 * Fires after the field has been marked as invalid.
29947 * @param {Roo.form.FieldLabel} this
29948 * @param {String} msg The validation message
29953 * Fires after the field has been validated with no errors.
29954 * @param {Roo.form.FieldLabel} this
29960 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29967 invalidClass : 'has-warning',
29968 validClass : 'has-success',
29969 iconTooltip : 'This field is required',
29970 indicatorpos : 'left',
29972 getAutoCreate : function(){
29976 cls : 'roo-bootstrap-field-label ' + this.cls,
29981 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29982 tooltip : this.iconTooltip
29991 if(this.indicatorpos == 'right'){
29994 cls : 'roo-bootstrap-field-label ' + this.cls,
30003 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30004 tooltip : this.iconTooltip
30013 initEvents: function()
30015 Roo.bootstrap.Element.superclass.initEvents.call(this);
30017 this.indicator = this.indicatorEl();
30019 if(this.indicator){
30020 this.indicator.removeClass('visible');
30021 this.indicator.addClass('invisible');
30024 Roo.bootstrap.FieldLabel.register(this);
30027 indicatorEl : function()
30029 var indicator = this.el.select('i.roo-required-indicator',true).first();
30040 * Mark this field as valid
30042 markValid : function()
30044 if(this.indicator){
30045 this.indicator.removeClass('visible');
30046 this.indicator.addClass('invisible');
30049 this.el.removeClass(this.invalidClass);
30051 this.el.addClass(this.validClass);
30053 this.fireEvent('valid', this);
30057 * Mark this field as invalid
30058 * @param {String} msg The validation message
30060 markInvalid : function(msg)
30062 if(this.indicator){
30063 this.indicator.removeClass('invisible');
30064 this.indicator.addClass('visible');
30067 this.el.removeClass(this.validClass);
30069 this.el.addClass(this.invalidClass);
30071 this.fireEvent('invalid', this, msg);
30077 Roo.apply(Roo.bootstrap.FieldLabel, {
30082 * register a FieldLabel Group
30083 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30085 register : function(label)
30087 if(this.groups.hasOwnProperty(label.target)){
30091 this.groups[label.target] = label;
30095 * fetch a FieldLabel Group based on the target
30096 * @param {string} target
30097 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30099 get: function(target) {
30100 if (typeof(this.groups[target]) == 'undefined') {
30104 return this.groups[target] ;
30113 * page DateSplitField.
30119 * @class Roo.bootstrap.DateSplitField
30120 * @extends Roo.bootstrap.Component
30121 * Bootstrap DateSplitField class
30122 * @cfg {string} fieldLabel - the label associated
30123 * @cfg {Number} labelWidth set the width of label (0-12)
30124 * @cfg {String} labelAlign (top|left)
30125 * @cfg {Boolean} dayAllowBlank (true|false) default false
30126 * @cfg {Boolean} monthAllowBlank (true|false) default false
30127 * @cfg {Boolean} yearAllowBlank (true|false) default false
30128 * @cfg {string} dayPlaceholder
30129 * @cfg {string} monthPlaceholder
30130 * @cfg {string} yearPlaceholder
30131 * @cfg {string} dayFormat default 'd'
30132 * @cfg {string} monthFormat default 'm'
30133 * @cfg {string} yearFormat default 'Y'
30134 * @cfg {Number} labellg set the width of label (1-12)
30135 * @cfg {Number} labelmd set the width of label (1-12)
30136 * @cfg {Number} labelsm set the width of label (1-12)
30137 * @cfg {Number} labelxs set the width of label (1-12)
30141 * Create a new DateSplitField
30142 * @param {Object} config The config object
30145 Roo.bootstrap.DateSplitField = function(config){
30146 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30152 * getting the data of years
30153 * @param {Roo.bootstrap.DateSplitField} this
30154 * @param {Object} years
30159 * getting the data of days
30160 * @param {Roo.bootstrap.DateSplitField} this
30161 * @param {Object} days
30166 * Fires after the field has been marked as invalid.
30167 * @param {Roo.form.Field} this
30168 * @param {String} msg The validation message
30173 * Fires after the field has been validated with no errors.
30174 * @param {Roo.form.Field} this
30180 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30183 labelAlign : 'top',
30185 dayAllowBlank : false,
30186 monthAllowBlank : false,
30187 yearAllowBlank : false,
30188 dayPlaceholder : '',
30189 monthPlaceholder : '',
30190 yearPlaceholder : '',
30194 isFormField : true,
30200 getAutoCreate : function()
30204 cls : 'row roo-date-split-field-group',
30209 cls : 'form-hidden-field roo-date-split-field-group-value',
30215 var labelCls = 'col-md-12';
30216 var contentCls = 'col-md-4';
30218 if(this.fieldLabel){
30222 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30226 html : this.fieldLabel
30231 if(this.labelAlign == 'left'){
30233 if(this.labelWidth > 12){
30234 label.style = "width: " + this.labelWidth + 'px';
30237 if(this.labelWidth < 13 && this.labelmd == 0){
30238 this.labelmd = this.labelWidth;
30241 if(this.labellg > 0){
30242 labelCls = ' col-lg-' + this.labellg;
30243 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30246 if(this.labelmd > 0){
30247 labelCls = ' col-md-' + this.labelmd;
30248 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30251 if(this.labelsm > 0){
30252 labelCls = ' col-sm-' + this.labelsm;
30253 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30256 if(this.labelxs > 0){
30257 labelCls = ' col-xs-' + this.labelxs;
30258 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30262 label.cls += ' ' + labelCls;
30264 cfg.cn.push(label);
30267 Roo.each(['day', 'month', 'year'], function(t){
30270 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30277 inputEl: function ()
30279 return this.el.select('.roo-date-split-field-group-value', true).first();
30282 onRender : function(ct, position)
30286 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30288 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30290 this.dayField = new Roo.bootstrap.ComboBox({
30291 allowBlank : this.dayAllowBlank,
30292 alwaysQuery : true,
30293 displayField : 'value',
30296 forceSelection : true,
30298 placeholder : this.dayPlaceholder,
30299 selectOnFocus : true,
30300 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30301 triggerAction : 'all',
30303 valueField : 'value',
30304 store : new Roo.data.SimpleStore({
30305 data : (function() {
30307 _this.fireEvent('days', _this, days);
30310 fields : [ 'value' ]
30313 select : function (_self, record, index)
30315 _this.setValue(_this.getValue());
30320 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30322 this.monthField = new Roo.bootstrap.MonthField({
30323 after : '<i class=\"fa fa-calendar\"></i>',
30324 allowBlank : this.monthAllowBlank,
30325 placeholder : this.monthPlaceholder,
30328 render : function (_self)
30330 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30331 e.preventDefault();
30335 select : function (_self, oldvalue, newvalue)
30337 _this.setValue(_this.getValue());
30342 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30344 this.yearField = new Roo.bootstrap.ComboBox({
30345 allowBlank : this.yearAllowBlank,
30346 alwaysQuery : true,
30347 displayField : 'value',
30350 forceSelection : true,
30352 placeholder : this.yearPlaceholder,
30353 selectOnFocus : true,
30354 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30355 triggerAction : 'all',
30357 valueField : 'value',
30358 store : new Roo.data.SimpleStore({
30359 data : (function() {
30361 _this.fireEvent('years', _this, years);
30364 fields : [ 'value' ]
30367 select : function (_self, record, index)
30369 _this.setValue(_this.getValue());
30374 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30377 setValue : function(v, format)
30379 this.inputEl.dom.value = v;
30381 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30383 var d = Date.parseDate(v, f);
30390 this.setDay(d.format(this.dayFormat));
30391 this.setMonth(d.format(this.monthFormat));
30392 this.setYear(d.format(this.yearFormat));
30399 setDay : function(v)
30401 this.dayField.setValue(v);
30402 this.inputEl.dom.value = this.getValue();
30407 setMonth : function(v)
30409 this.monthField.setValue(v, true);
30410 this.inputEl.dom.value = this.getValue();
30415 setYear : function(v)
30417 this.yearField.setValue(v);
30418 this.inputEl.dom.value = this.getValue();
30423 getDay : function()
30425 return this.dayField.getValue();
30428 getMonth : function()
30430 return this.monthField.getValue();
30433 getYear : function()
30435 return this.yearField.getValue();
30438 getValue : function()
30440 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30442 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30452 this.inputEl.dom.value = '';
30457 validate : function()
30459 var d = this.dayField.validate();
30460 var m = this.monthField.validate();
30461 var y = this.yearField.validate();
30466 (!this.dayAllowBlank && !d) ||
30467 (!this.monthAllowBlank && !m) ||
30468 (!this.yearAllowBlank && !y)
30473 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30482 this.markInvalid();
30487 markValid : function()
30490 var label = this.el.select('label', true).first();
30491 var icon = this.el.select('i.fa-star', true).first();
30497 this.fireEvent('valid', this);
30501 * Mark this field as invalid
30502 * @param {String} msg The validation message
30504 markInvalid : function(msg)
30507 var label = this.el.select('label', true).first();
30508 var icon = this.el.select('i.fa-star', true).first();
30510 if(label && !icon){
30511 this.el.select('.roo-date-split-field-label', true).createChild({
30513 cls : 'text-danger fa fa-lg fa-star',
30514 tooltip : 'This field is required',
30515 style : 'margin-right:5px;'
30519 this.fireEvent('invalid', this, msg);
30522 clearInvalid : function()
30524 var label = this.el.select('label', true).first();
30525 var icon = this.el.select('i.fa-star', true).first();
30531 this.fireEvent('valid', this);
30534 getName: function()
30544 * http://masonry.desandro.com
30546 * The idea is to render all the bricks based on vertical width...
30548 * The original code extends 'outlayer' - we might need to use that....
30554 * @class Roo.bootstrap.LayoutMasonry
30555 * @extends Roo.bootstrap.Component
30556 * Bootstrap Layout Masonry class
30559 * Create a new Element
30560 * @param {Object} config The config object
30563 Roo.bootstrap.LayoutMasonry = function(config){
30565 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30569 Roo.bootstrap.LayoutMasonry.register(this);
30575 * Fire after layout the items
30576 * @param {Roo.bootstrap.LayoutMasonry} this
30577 * @param {Roo.EventObject} e
30584 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30587 * @cfg {Boolean} isLayoutInstant = no animation?
30589 isLayoutInstant : false, // needed?
30592 * @cfg {Number} boxWidth width of the columns
30597 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30602 * @cfg {Number} padWidth padding below box..
30607 * @cfg {Number} gutter gutter width..
30612 * @cfg {Number} maxCols maximum number of columns
30618 * @cfg {Boolean} isAutoInitial defalut true
30620 isAutoInitial : true,
30625 * @cfg {Boolean} isHorizontal defalut false
30627 isHorizontal : false,
30629 currentSize : null,
30635 bricks: null, //CompositeElement
30639 _isLayoutInited : false,
30641 // isAlternative : false, // only use for vertical layout...
30644 * @cfg {Number} alternativePadWidth padding below box..
30646 alternativePadWidth : 50,
30648 selectedBrick : [],
30650 getAutoCreate : function(){
30652 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30656 cls: 'blog-masonary-wrapper ' + this.cls,
30658 cls : 'mas-boxes masonary'
30665 getChildContainer: function( )
30667 if (this.boxesEl) {
30668 return this.boxesEl;
30671 this.boxesEl = this.el.select('.mas-boxes').first();
30673 return this.boxesEl;
30677 initEvents : function()
30681 if(this.isAutoInitial){
30682 Roo.log('hook children rendered');
30683 this.on('childrenrendered', function() {
30684 Roo.log('children rendered');
30690 initial : function()
30692 this.selectedBrick = [];
30694 this.currentSize = this.el.getBox(true);
30696 Roo.EventManager.onWindowResize(this.resize, this);
30698 if(!this.isAutoInitial){
30706 //this.layout.defer(500,this);
30710 resize : function()
30712 var cs = this.el.getBox(true);
30715 this.currentSize.width == cs.width &&
30716 this.currentSize.x == cs.x &&
30717 this.currentSize.height == cs.height &&
30718 this.currentSize.y == cs.y
30720 Roo.log("no change in with or X or Y");
30724 this.currentSize = cs;
30730 layout : function()
30732 this._resetLayout();
30734 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30736 this.layoutItems( isInstant );
30738 this._isLayoutInited = true;
30740 this.fireEvent('layout', this);
30744 _resetLayout : function()
30746 if(this.isHorizontal){
30747 this.horizontalMeasureColumns();
30751 this.verticalMeasureColumns();
30755 verticalMeasureColumns : function()
30757 this.getContainerWidth();
30759 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30760 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30764 var boxWidth = this.boxWidth + this.padWidth;
30766 if(this.containerWidth < this.boxWidth){
30767 boxWidth = this.containerWidth
30770 var containerWidth = this.containerWidth;
30772 var cols = Math.floor(containerWidth / boxWidth);
30774 this.cols = Math.max( cols, 1 );
30776 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30778 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30780 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30782 this.colWidth = boxWidth + avail - this.padWidth;
30784 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30785 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30788 horizontalMeasureColumns : function()
30790 this.getContainerWidth();
30792 var boxWidth = this.boxWidth;
30794 if(this.containerWidth < boxWidth){
30795 boxWidth = this.containerWidth;
30798 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30800 this.el.setHeight(boxWidth);
30804 getContainerWidth : function()
30806 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30809 layoutItems : function( isInstant )
30811 Roo.log(this.bricks);
30813 var items = Roo.apply([], this.bricks);
30815 if(this.isHorizontal){
30816 this._horizontalLayoutItems( items , isInstant );
30820 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30821 // this._verticalAlternativeLayoutItems( items , isInstant );
30825 this._verticalLayoutItems( items , isInstant );
30829 _verticalLayoutItems : function ( items , isInstant)
30831 if ( !items || !items.length ) {
30836 ['xs', 'xs', 'xs', 'tall'],
30837 ['xs', 'xs', 'tall'],
30838 ['xs', 'xs', 'sm'],
30839 ['xs', 'xs', 'xs'],
30845 ['sm', 'xs', 'xs'],
30849 ['tall', 'xs', 'xs', 'xs'],
30850 ['tall', 'xs', 'xs'],
30862 Roo.each(items, function(item, k){
30864 switch (item.size) {
30865 // these layouts take up a full box,
30876 boxes.push([item]);
30899 var filterPattern = function(box, length)
30907 var pattern = box.slice(0, length);
30911 Roo.each(pattern, function(i){
30912 format.push(i.size);
30915 Roo.each(standard, function(s){
30917 if(String(s) != String(format)){
30926 if(!match && length == 1){
30931 filterPattern(box, length - 1);
30935 queue.push(pattern);
30937 box = box.slice(length, box.length);
30939 filterPattern(box, 4);
30945 Roo.each(boxes, function(box, k){
30951 if(box.length == 1){
30956 filterPattern(box, 4);
30960 this._processVerticalLayoutQueue( queue, isInstant );
30964 // _verticalAlternativeLayoutItems : function( items , isInstant )
30966 // if ( !items || !items.length ) {
30970 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30974 _horizontalLayoutItems : function ( items , isInstant)
30976 if ( !items || !items.length || items.length < 3) {
30982 var eItems = items.slice(0, 3);
30984 items = items.slice(3, items.length);
30987 ['xs', 'xs', 'xs', 'wide'],
30988 ['xs', 'xs', 'wide'],
30989 ['xs', 'xs', 'sm'],
30990 ['xs', 'xs', 'xs'],
30996 ['sm', 'xs', 'xs'],
31000 ['wide', 'xs', 'xs', 'xs'],
31001 ['wide', 'xs', 'xs'],
31014 Roo.each(items, function(item, k){
31016 switch (item.size) {
31027 boxes.push([item]);
31051 var filterPattern = function(box, length)
31059 var pattern = box.slice(0, length);
31063 Roo.each(pattern, function(i){
31064 format.push(i.size);
31067 Roo.each(standard, function(s){
31069 if(String(s) != String(format)){
31078 if(!match && length == 1){
31083 filterPattern(box, length - 1);
31087 queue.push(pattern);
31089 box = box.slice(length, box.length);
31091 filterPattern(box, 4);
31097 Roo.each(boxes, function(box, k){
31103 if(box.length == 1){
31108 filterPattern(box, 4);
31115 var pos = this.el.getBox(true);
31119 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31121 var hit_end = false;
31123 Roo.each(queue, function(box){
31127 Roo.each(box, function(b){
31129 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31139 Roo.each(box, function(b){
31141 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31144 mx = Math.max(mx, b.x);
31148 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31152 Roo.each(box, function(b){
31154 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31168 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31171 /** Sets position of item in DOM
31172 * @param {Element} item
31173 * @param {Number} x - horizontal position
31174 * @param {Number} y - vertical position
31175 * @param {Boolean} isInstant - disables transitions
31177 _processVerticalLayoutQueue : function( queue, isInstant )
31179 var pos = this.el.getBox(true);
31184 for (var i = 0; i < this.cols; i++){
31188 Roo.each(queue, function(box, k){
31190 var col = k % this.cols;
31192 Roo.each(box, function(b,kk){
31194 b.el.position('absolute');
31196 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31197 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31199 if(b.size == 'md-left' || b.size == 'md-right'){
31200 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31201 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31204 b.el.setWidth(width);
31205 b.el.setHeight(height);
31207 b.el.select('iframe',true).setSize(width,height);
31211 for (var i = 0; i < this.cols; i++){
31213 if(maxY[i] < maxY[col]){
31218 col = Math.min(col, i);
31222 x = pos.x + col * (this.colWidth + this.padWidth);
31226 var positions = [];
31228 switch (box.length){
31230 positions = this.getVerticalOneBoxColPositions(x, y, box);
31233 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31236 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31239 positions = this.getVerticalFourBoxColPositions(x, y, box);
31245 Roo.each(box, function(b,kk){
31247 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31249 var sz = b.el.getSize();
31251 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31259 for (var i = 0; i < this.cols; i++){
31260 mY = Math.max(mY, maxY[i]);
31263 this.el.setHeight(mY - pos.y);
31267 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31269 // var pos = this.el.getBox(true);
31272 // var maxX = pos.right;
31274 // var maxHeight = 0;
31276 // Roo.each(items, function(item, k){
31280 // item.el.position('absolute');
31282 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31284 // item.el.setWidth(width);
31286 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31288 // item.el.setHeight(height);
31291 // item.el.setXY([x, y], isInstant ? false : true);
31293 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31296 // y = y + height + this.alternativePadWidth;
31298 // maxHeight = maxHeight + height + this.alternativePadWidth;
31302 // this.el.setHeight(maxHeight);
31306 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31308 var pos = this.el.getBox(true);
31313 var maxX = pos.right;
31315 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31317 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31319 Roo.each(queue, function(box, k){
31321 Roo.each(box, function(b, kk){
31323 b.el.position('absolute');
31325 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31326 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31328 if(b.size == 'md-left' || b.size == 'md-right'){
31329 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31330 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31333 b.el.setWidth(width);
31334 b.el.setHeight(height);
31342 var positions = [];
31344 switch (box.length){
31346 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31349 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31352 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31355 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31361 Roo.each(box, function(b,kk){
31363 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31365 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31373 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31375 Roo.each(eItems, function(b,k){
31377 b.size = (k == 0) ? 'sm' : 'xs';
31378 b.x = (k == 0) ? 2 : 1;
31379 b.y = (k == 0) ? 2 : 1;
31381 b.el.position('absolute');
31383 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31385 b.el.setWidth(width);
31387 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31389 b.el.setHeight(height);
31393 var positions = [];
31396 x : maxX - this.unitWidth * 2 - this.gutter,
31401 x : maxX - this.unitWidth,
31402 y : minY + (this.unitWidth + this.gutter) * 2
31406 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31410 Roo.each(eItems, function(b,k){
31412 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31418 getVerticalOneBoxColPositions : function(x, y, box)
31422 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31424 if(box[0].size == 'md-left'){
31428 if(box[0].size == 'md-right'){
31433 x : x + (this.unitWidth + this.gutter) * rand,
31440 getVerticalTwoBoxColPositions : function(x, y, box)
31444 if(box[0].size == 'xs'){
31448 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31452 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31466 x : x + (this.unitWidth + this.gutter) * 2,
31467 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31474 getVerticalThreeBoxColPositions : function(x, y, box)
31478 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31486 x : x + (this.unitWidth + this.gutter) * 1,
31491 x : x + (this.unitWidth + this.gutter) * 2,
31499 if(box[0].size == 'xs' && box[1].size == 'xs'){
31508 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31512 x : x + (this.unitWidth + this.gutter) * 1,
31526 x : x + (this.unitWidth + this.gutter) * 2,
31531 x : x + (this.unitWidth + this.gutter) * 2,
31532 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31539 getVerticalFourBoxColPositions : function(x, y, box)
31543 if(box[0].size == 'xs'){
31552 y : y + (this.unitHeight + this.gutter) * 1
31557 y : y + (this.unitHeight + this.gutter) * 2
31561 x : x + (this.unitWidth + this.gutter) * 1,
31575 x : x + (this.unitWidth + this.gutter) * 2,
31580 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31581 y : y + (this.unitHeight + this.gutter) * 1
31585 x : x + (this.unitWidth + this.gutter) * 2,
31586 y : y + (this.unitWidth + this.gutter) * 2
31593 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31597 if(box[0].size == 'md-left'){
31599 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31606 if(box[0].size == 'md-right'){
31608 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31609 y : minY + (this.unitWidth + this.gutter) * 1
31615 var rand = Math.floor(Math.random() * (4 - box[0].y));
31618 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31619 y : minY + (this.unitWidth + this.gutter) * rand
31626 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31630 if(box[0].size == 'xs'){
31633 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31638 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31639 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31647 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31652 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31653 y : minY + (this.unitWidth + this.gutter) * 2
31660 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31664 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31667 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31672 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31673 y : minY + (this.unitWidth + this.gutter) * 1
31677 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31678 y : minY + (this.unitWidth + this.gutter) * 2
31685 if(box[0].size == 'xs' && box[1].size == 'xs'){
31688 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31693 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31698 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31699 y : minY + (this.unitWidth + this.gutter) * 1
31707 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31712 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31713 y : minY + (this.unitWidth + this.gutter) * 2
31717 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31718 y : minY + (this.unitWidth + this.gutter) * 2
31725 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31729 if(box[0].size == 'xs'){
31732 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31737 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31742 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),
31747 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31748 y : minY + (this.unitWidth + this.gutter) * 1
31756 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31761 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31762 y : minY + (this.unitWidth + this.gutter) * 2
31766 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31767 y : minY + (this.unitWidth + this.gutter) * 2
31771 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),
31772 y : minY + (this.unitWidth + this.gutter) * 2
31780 * remove a Masonry Brick
31781 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31783 removeBrick : function(brick_id)
31789 for (var i = 0; i<this.bricks.length; i++) {
31790 if (this.bricks[i].id == brick_id) {
31791 this.bricks.splice(i,1);
31792 this.el.dom.removeChild(Roo.get(brick_id).dom);
31799 * adds a Masonry Brick
31800 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31802 addBrick : function(cfg)
31804 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31805 //this.register(cn);
31806 cn.parentId = this.id;
31807 cn.onRender(this.el, null);
31812 * register a Masonry Brick
31813 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31816 register : function(brick)
31818 this.bricks.push(brick);
31819 brick.masonryId = this.id;
31823 * clear all the Masonry Brick
31825 clearAll : function()
31828 //this.getChildContainer().dom.innerHTML = "";
31829 this.el.dom.innerHTML = '';
31832 getSelected : function()
31834 if (!this.selectedBrick) {
31838 return this.selectedBrick;
31842 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31846 * register a Masonry Layout
31847 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31850 register : function(layout)
31852 this.groups[layout.id] = layout;
31855 * fetch a Masonry Layout based on the masonry layout ID
31856 * @param {string} the masonry layout to add
31857 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31860 get: function(layout_id) {
31861 if (typeof(this.groups[layout_id]) == 'undefined') {
31864 return this.groups[layout_id] ;
31876 * http://masonry.desandro.com
31878 * The idea is to render all the bricks based on vertical width...
31880 * The original code extends 'outlayer' - we might need to use that....
31886 * @class Roo.bootstrap.LayoutMasonryAuto
31887 * @extends Roo.bootstrap.Component
31888 * Bootstrap Layout Masonry class
31891 * Create a new Element
31892 * @param {Object} config The config object
31895 Roo.bootstrap.LayoutMasonryAuto = function(config){
31896 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31899 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31902 * @cfg {Boolean} isFitWidth - resize the width..
31904 isFitWidth : false, // options..
31906 * @cfg {Boolean} isOriginLeft = left align?
31908 isOriginLeft : true,
31910 * @cfg {Boolean} isOriginTop = top align?
31912 isOriginTop : false,
31914 * @cfg {Boolean} isLayoutInstant = no animation?
31916 isLayoutInstant : false, // needed?
31918 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31920 isResizingContainer : true,
31922 * @cfg {Number} columnWidth width of the columns
31928 * @cfg {Number} maxCols maximum number of columns
31933 * @cfg {Number} padHeight padding below box..
31939 * @cfg {Boolean} isAutoInitial defalut true
31942 isAutoInitial : true,
31948 initialColumnWidth : 0,
31949 currentSize : null,
31951 colYs : null, // array.
31958 bricks: null, //CompositeElement
31959 cols : 0, // array?
31960 // element : null, // wrapped now this.el
31961 _isLayoutInited : null,
31964 getAutoCreate : function(){
31968 cls: 'blog-masonary-wrapper ' + this.cls,
31970 cls : 'mas-boxes masonary'
31977 getChildContainer: function( )
31979 if (this.boxesEl) {
31980 return this.boxesEl;
31983 this.boxesEl = this.el.select('.mas-boxes').first();
31985 return this.boxesEl;
31989 initEvents : function()
31993 if(this.isAutoInitial){
31994 Roo.log('hook children rendered');
31995 this.on('childrenrendered', function() {
31996 Roo.log('children rendered');
32003 initial : function()
32005 this.reloadItems();
32007 this.currentSize = this.el.getBox(true);
32009 /// was window resize... - let's see if this works..
32010 Roo.EventManager.onWindowResize(this.resize, this);
32012 if(!this.isAutoInitial){
32017 this.layout.defer(500,this);
32020 reloadItems: function()
32022 this.bricks = this.el.select('.masonry-brick', true);
32024 this.bricks.each(function(b) {
32025 //Roo.log(b.getSize());
32026 if (!b.attr('originalwidth')) {
32027 b.attr('originalwidth', b.getSize().width);
32032 Roo.log(this.bricks.elements.length);
32035 resize : function()
32038 var cs = this.el.getBox(true);
32040 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32041 Roo.log("no change in with or X");
32044 this.currentSize = cs;
32048 layout : function()
32051 this._resetLayout();
32052 //this._manageStamps();
32054 // don't animate first layout
32055 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32056 this.layoutItems( isInstant );
32058 // flag for initalized
32059 this._isLayoutInited = true;
32062 layoutItems : function( isInstant )
32064 //var items = this._getItemsForLayout( this.items );
32065 // original code supports filtering layout items.. we just ignore it..
32067 this._layoutItems( this.bricks , isInstant );
32069 this._postLayout();
32071 _layoutItems : function ( items , isInstant)
32073 //this.fireEvent( 'layout', this, items );
32076 if ( !items || !items.elements.length ) {
32077 // no items, emit event with empty array
32082 items.each(function(item) {
32083 Roo.log("layout item");
32085 // get x/y object from method
32086 var position = this._getItemLayoutPosition( item );
32088 position.item = item;
32089 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32090 queue.push( position );
32093 this._processLayoutQueue( queue );
32095 /** Sets position of item in DOM
32096 * @param {Element} item
32097 * @param {Number} x - horizontal position
32098 * @param {Number} y - vertical position
32099 * @param {Boolean} isInstant - disables transitions
32101 _processLayoutQueue : function( queue )
32103 for ( var i=0, len = queue.length; i < len; i++ ) {
32104 var obj = queue[i];
32105 obj.item.position('absolute');
32106 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32112 * Any logic you want to do after each layout,
32113 * i.e. size the container
32115 _postLayout : function()
32117 this.resizeContainer();
32120 resizeContainer : function()
32122 if ( !this.isResizingContainer ) {
32125 var size = this._getContainerSize();
32127 this.el.setSize(size.width,size.height);
32128 this.boxesEl.setSize(size.width,size.height);
32134 _resetLayout : function()
32136 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32137 this.colWidth = this.el.getWidth();
32138 //this.gutter = this.el.getWidth();
32140 this.measureColumns();
32146 this.colYs.push( 0 );
32152 measureColumns : function()
32154 this.getContainerWidth();
32155 // if columnWidth is 0, default to outerWidth of first item
32156 if ( !this.columnWidth ) {
32157 var firstItem = this.bricks.first();
32158 Roo.log(firstItem);
32159 this.columnWidth = this.containerWidth;
32160 if (firstItem && firstItem.attr('originalwidth') ) {
32161 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32163 // columnWidth fall back to item of first element
32164 Roo.log("set column width?");
32165 this.initialColumnWidth = this.columnWidth ;
32167 // if first elem has no width, default to size of container
32172 if (this.initialColumnWidth) {
32173 this.columnWidth = this.initialColumnWidth;
32178 // column width is fixed at the top - however if container width get's smaller we should
32181 // this bit calcs how man columns..
32183 var columnWidth = this.columnWidth += this.gutter;
32185 // calculate columns
32186 var containerWidth = this.containerWidth + this.gutter;
32188 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32189 // fix rounding errors, typically with gutters
32190 var excess = columnWidth - containerWidth % columnWidth;
32193 // if overshoot is less than a pixel, round up, otherwise floor it
32194 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32195 cols = Math[ mathMethod ]( cols );
32196 this.cols = Math.max( cols, 1 );
32197 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32199 // padding positioning..
32200 var totalColWidth = this.cols * this.columnWidth;
32201 var padavail = this.containerWidth - totalColWidth;
32202 // so for 2 columns - we need 3 'pads'
32204 var padNeeded = (1+this.cols) * this.padWidth;
32206 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32208 this.columnWidth += padExtra
32209 //this.padWidth = Math.floor(padavail / ( this.cols));
32211 // adjust colum width so that padding is fixed??
32213 // we have 3 columns ... total = width * 3
32214 // we have X left over... that should be used by
32216 //if (this.expandC) {
32224 getContainerWidth : function()
32226 /* // container is parent if fit width
32227 var container = this.isFitWidth ? this.element.parentNode : this.element;
32228 // check that this.size and size are there
32229 // IE8 triggers resize on body size change, so they might not be
32231 var size = getSize( container ); //FIXME
32232 this.containerWidth = size && size.innerWidth; //FIXME
32235 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32239 _getItemLayoutPosition : function( item ) // what is item?
32241 // we resize the item to our columnWidth..
32243 item.setWidth(this.columnWidth);
32244 item.autoBoxAdjust = false;
32246 var sz = item.getSize();
32248 // how many columns does this brick span
32249 var remainder = this.containerWidth % this.columnWidth;
32251 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32252 // round if off by 1 pixel, otherwise use ceil
32253 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32254 colSpan = Math.min( colSpan, this.cols );
32256 // normally this should be '1' as we dont' currently allow multi width columns..
32258 var colGroup = this._getColGroup( colSpan );
32259 // get the minimum Y value from the columns
32260 var minimumY = Math.min.apply( Math, colGroup );
32261 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32263 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32265 // position the brick
32267 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32268 y: this.currentSize.y + minimumY + this.padHeight
32272 // apply setHeight to necessary columns
32273 var setHeight = minimumY + sz.height + this.padHeight;
32274 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32276 var setSpan = this.cols + 1 - colGroup.length;
32277 for ( var i = 0; i < setSpan; i++ ) {
32278 this.colYs[ shortColIndex + i ] = setHeight ;
32285 * @param {Number} colSpan - number of columns the element spans
32286 * @returns {Array} colGroup
32288 _getColGroup : function( colSpan )
32290 if ( colSpan < 2 ) {
32291 // if brick spans only one column, use all the column Ys
32296 // how many different places could this brick fit horizontally
32297 var groupCount = this.cols + 1 - colSpan;
32298 // for each group potential horizontal position
32299 for ( var i = 0; i < groupCount; i++ ) {
32300 // make an array of colY values for that one group
32301 var groupColYs = this.colYs.slice( i, i + colSpan );
32302 // and get the max value of the array
32303 colGroup[i] = Math.max.apply( Math, groupColYs );
32308 _manageStamp : function( stamp )
32310 var stampSize = stamp.getSize();
32311 var offset = stamp.getBox();
32312 // get the columns that this stamp affects
32313 var firstX = this.isOriginLeft ? offset.x : offset.right;
32314 var lastX = firstX + stampSize.width;
32315 var firstCol = Math.floor( firstX / this.columnWidth );
32316 firstCol = Math.max( 0, firstCol );
32318 var lastCol = Math.floor( lastX / this.columnWidth );
32319 // lastCol should not go over if multiple of columnWidth #425
32320 lastCol -= lastX % this.columnWidth ? 0 : 1;
32321 lastCol = Math.min( this.cols - 1, lastCol );
32323 // set colYs to bottom of the stamp
32324 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32327 for ( var i = firstCol; i <= lastCol; i++ ) {
32328 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32333 _getContainerSize : function()
32335 this.maxY = Math.max.apply( Math, this.colYs );
32340 if ( this.isFitWidth ) {
32341 size.width = this._getContainerFitWidth();
32347 _getContainerFitWidth : function()
32349 var unusedCols = 0;
32350 // count unused columns
32353 if ( this.colYs[i] !== 0 ) {
32358 // fit container to columns that have been used
32359 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32362 needsResizeLayout : function()
32364 var previousWidth = this.containerWidth;
32365 this.getContainerWidth();
32366 return previousWidth !== this.containerWidth;
32381 * @class Roo.bootstrap.MasonryBrick
32382 * @extends Roo.bootstrap.Component
32383 * Bootstrap MasonryBrick class
32386 * Create a new MasonryBrick
32387 * @param {Object} config The config object
32390 Roo.bootstrap.MasonryBrick = function(config){
32392 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32394 Roo.bootstrap.MasonryBrick.register(this);
32400 * When a MasonryBrick is clcik
32401 * @param {Roo.bootstrap.MasonryBrick} this
32402 * @param {Roo.EventObject} e
32408 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32411 * @cfg {String} title
32415 * @cfg {String} html
32419 * @cfg {String} bgimage
32423 * @cfg {String} videourl
32427 * @cfg {String} cls
32431 * @cfg {String} href
32435 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32440 * @cfg {String} placetitle (center|bottom)
32445 * @cfg {Boolean} isFitContainer defalut true
32447 isFitContainer : true,
32450 * @cfg {Boolean} preventDefault defalut false
32452 preventDefault : false,
32455 * @cfg {Boolean} inverse defalut false
32457 maskInverse : false,
32459 getAutoCreate : function()
32461 if(!this.isFitContainer){
32462 return this.getSplitAutoCreate();
32465 var cls = 'masonry-brick masonry-brick-full';
32467 if(this.href.length){
32468 cls += ' masonry-brick-link';
32471 if(this.bgimage.length){
32472 cls += ' masonry-brick-image';
32475 if(this.maskInverse){
32476 cls += ' mask-inverse';
32479 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32480 cls += ' enable-mask';
32484 cls += ' masonry-' + this.size + '-brick';
32487 if(this.placetitle.length){
32489 switch (this.placetitle) {
32491 cls += ' masonry-center-title';
32494 cls += ' masonry-bottom-title';
32501 if(!this.html.length && !this.bgimage.length){
32502 cls += ' masonry-center-title';
32505 if(!this.html.length && this.bgimage.length){
32506 cls += ' masonry-bottom-title';
32511 cls += ' ' + this.cls;
32515 tag: (this.href.length) ? 'a' : 'div',
32520 cls: 'masonry-brick-mask'
32524 cls: 'masonry-brick-paragraph',
32530 if(this.href.length){
32531 cfg.href = this.href;
32534 var cn = cfg.cn[1].cn;
32536 if(this.title.length){
32539 cls: 'masonry-brick-title',
32544 if(this.html.length){
32547 cls: 'masonry-brick-text',
32552 if (!this.title.length && !this.html.length) {
32553 cfg.cn[1].cls += ' hide';
32556 if(this.bgimage.length){
32559 cls: 'masonry-brick-image-view',
32564 if(this.videourl.length){
32565 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32566 // youtube support only?
32569 cls: 'masonry-brick-image-view',
32572 allowfullscreen : true
32580 getSplitAutoCreate : function()
32582 var cls = 'masonry-brick masonry-brick-split';
32584 if(this.href.length){
32585 cls += ' masonry-brick-link';
32588 if(this.bgimage.length){
32589 cls += ' masonry-brick-image';
32593 cls += ' masonry-' + this.size + '-brick';
32596 switch (this.placetitle) {
32598 cls += ' masonry-center-title';
32601 cls += ' masonry-bottom-title';
32604 if(!this.bgimage.length){
32605 cls += ' masonry-center-title';
32608 if(this.bgimage.length){
32609 cls += ' masonry-bottom-title';
32615 cls += ' ' + this.cls;
32619 tag: (this.href.length) ? 'a' : 'div',
32624 cls: 'masonry-brick-split-head',
32628 cls: 'masonry-brick-paragraph',
32635 cls: 'masonry-brick-split-body',
32641 if(this.href.length){
32642 cfg.href = this.href;
32645 if(this.title.length){
32646 cfg.cn[0].cn[0].cn.push({
32648 cls: 'masonry-brick-title',
32653 if(this.html.length){
32654 cfg.cn[1].cn.push({
32656 cls: 'masonry-brick-text',
32661 if(this.bgimage.length){
32662 cfg.cn[0].cn.push({
32664 cls: 'masonry-brick-image-view',
32669 if(this.videourl.length){
32670 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32671 // youtube support only?
32672 cfg.cn[0].cn.cn.push({
32674 cls: 'masonry-brick-image-view',
32677 allowfullscreen : true
32684 initEvents: function()
32686 switch (this.size) {
32719 this.el.on('touchstart', this.onTouchStart, this);
32720 this.el.on('touchmove', this.onTouchMove, this);
32721 this.el.on('touchend', this.onTouchEnd, this);
32722 this.el.on('contextmenu', this.onContextMenu, this);
32724 this.el.on('mouseenter' ,this.enter, this);
32725 this.el.on('mouseleave', this.leave, this);
32726 this.el.on('click', this.onClick, this);
32729 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32730 this.parent().bricks.push(this);
32735 onClick: function(e, el)
32737 var time = this.endTimer - this.startTimer;
32738 // Roo.log(e.preventDefault());
32741 e.preventDefault();
32746 if(!this.preventDefault){
32750 e.preventDefault();
32752 if (this.activcClass != '') {
32753 this.selectBrick();
32756 this.fireEvent('click', this);
32759 enter: function(e, el)
32761 e.preventDefault();
32763 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32767 if(this.bgimage.length && this.html.length){
32768 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32772 leave: function(e, el)
32774 e.preventDefault();
32776 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32780 if(this.bgimage.length && this.html.length){
32781 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32785 onTouchStart: function(e, el)
32787 // e.preventDefault();
32789 this.touchmoved = false;
32791 if(!this.isFitContainer){
32795 if(!this.bgimage.length || !this.html.length){
32799 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32801 this.timer = new Date().getTime();
32805 onTouchMove: function(e, el)
32807 this.touchmoved = true;
32810 onContextMenu : function(e,el)
32812 e.preventDefault();
32813 e.stopPropagation();
32817 onTouchEnd: function(e, el)
32819 // e.preventDefault();
32821 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32828 if(!this.bgimage.length || !this.html.length){
32830 if(this.href.length){
32831 window.location.href = this.href;
32837 if(!this.isFitContainer){
32841 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32843 window.location.href = this.href;
32846 //selection on single brick only
32847 selectBrick : function() {
32849 if (!this.parentId) {
32853 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32854 var index = m.selectedBrick.indexOf(this.id);
32857 m.selectedBrick.splice(index,1);
32858 this.el.removeClass(this.activeClass);
32862 for(var i = 0; i < m.selectedBrick.length; i++) {
32863 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32864 b.el.removeClass(b.activeClass);
32867 m.selectedBrick = [];
32869 m.selectedBrick.push(this.id);
32870 this.el.addClass(this.activeClass);
32876 Roo.apply(Roo.bootstrap.MasonryBrick, {
32879 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32881 * register a Masonry Brick
32882 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32885 register : function(brick)
32887 //this.groups[brick.id] = brick;
32888 this.groups.add(brick.id, brick);
32891 * fetch a masonry brick based on the masonry brick ID
32892 * @param {string} the masonry brick to add
32893 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32896 get: function(brick_id)
32898 // if (typeof(this.groups[brick_id]) == 'undefined') {
32901 // return this.groups[brick_id] ;
32903 if(this.groups.key(brick_id)) {
32904 return this.groups.key(brick_id);
32922 * @class Roo.bootstrap.Brick
32923 * @extends Roo.bootstrap.Component
32924 * Bootstrap Brick class
32927 * Create a new Brick
32928 * @param {Object} config The config object
32931 Roo.bootstrap.Brick = function(config){
32932 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32938 * When a Brick is click
32939 * @param {Roo.bootstrap.Brick} this
32940 * @param {Roo.EventObject} e
32946 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32949 * @cfg {String} title
32953 * @cfg {String} html
32957 * @cfg {String} bgimage
32961 * @cfg {String} cls
32965 * @cfg {String} href
32969 * @cfg {String} video
32973 * @cfg {Boolean} square
32977 getAutoCreate : function()
32979 var cls = 'roo-brick';
32981 if(this.href.length){
32982 cls += ' roo-brick-link';
32985 if(this.bgimage.length){
32986 cls += ' roo-brick-image';
32989 if(!this.html.length && !this.bgimage.length){
32990 cls += ' roo-brick-center-title';
32993 if(!this.html.length && this.bgimage.length){
32994 cls += ' roo-brick-bottom-title';
32998 cls += ' ' + this.cls;
33002 tag: (this.href.length) ? 'a' : 'div',
33007 cls: 'roo-brick-paragraph',
33013 if(this.href.length){
33014 cfg.href = this.href;
33017 var cn = cfg.cn[0].cn;
33019 if(this.title.length){
33022 cls: 'roo-brick-title',
33027 if(this.html.length){
33030 cls: 'roo-brick-text',
33037 if(this.bgimage.length){
33040 cls: 'roo-brick-image-view',
33048 initEvents: function()
33050 if(this.title.length || this.html.length){
33051 this.el.on('mouseenter' ,this.enter, this);
33052 this.el.on('mouseleave', this.leave, this);
33055 Roo.EventManager.onWindowResize(this.resize, this);
33057 if(this.bgimage.length){
33058 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33059 this.imageEl.on('load', this.onImageLoad, this);
33066 onImageLoad : function()
33071 resize : function()
33073 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33075 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33077 if(this.bgimage.length){
33078 var image = this.el.select('.roo-brick-image-view', true).first();
33080 image.setWidth(paragraph.getWidth());
33083 image.setHeight(paragraph.getWidth());
33086 this.el.setHeight(image.getHeight());
33087 paragraph.setHeight(image.getHeight());
33093 enter: function(e, el)
33095 e.preventDefault();
33097 if(this.bgimage.length){
33098 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33099 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33103 leave: function(e, el)
33105 e.preventDefault();
33107 if(this.bgimage.length){
33108 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33109 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33124 * @class Roo.bootstrap.NumberField
33125 * @extends Roo.bootstrap.Input
33126 * Bootstrap NumberField class
33132 * Create a new NumberField
33133 * @param {Object} config The config object
33136 Roo.bootstrap.NumberField = function(config){
33137 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33140 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33143 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33145 allowDecimals : true,
33147 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33149 decimalSeparator : ".",
33151 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33153 decimalPrecision : 2,
33155 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33157 allowNegative : true,
33160 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33164 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33166 minValue : Number.NEGATIVE_INFINITY,
33168 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33170 maxValue : Number.MAX_VALUE,
33172 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33174 minText : "The minimum value for this field is {0}",
33176 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33178 maxText : "The maximum value for this field is {0}",
33180 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33181 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33183 nanText : "{0} is not a valid number",
33185 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33189 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33191 thousandsDelimiter : false,
33193 * @cfg {String} valueAlign alignment of value
33195 valueAlign : "left",
33197 getAutoCreate : function()
33199 var hiddenInput = {
33203 cls: 'hidden-number-input'
33207 hiddenInput.name = this.name;
33212 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33214 this.name = hiddenInput.name;
33216 if(cfg.cn.length > 0) {
33217 cfg.cn.push(hiddenInput);
33224 initEvents : function()
33226 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33228 var allowed = "0123456789";
33230 if(this.allowDecimals){
33231 allowed += this.decimalSeparator;
33234 if(this.allowNegative){
33238 if(this.thousandsDelimiter) {
33242 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33244 var keyPress = function(e){
33246 var k = e.getKey();
33248 var c = e.getCharCode();
33251 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33252 allowed.indexOf(String.fromCharCode(c)) === -1
33258 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33262 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33267 this.el.on("keypress", keyPress, this);
33270 validateValue : function(value)
33273 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33277 var num = this.parseValue(value);
33280 this.markInvalid(String.format(this.nanText, value));
33284 if(num < this.minValue){
33285 this.markInvalid(String.format(this.minText, this.minValue));
33289 if(num > this.maxValue){
33290 this.markInvalid(String.format(this.maxText, this.maxValue));
33297 getValue : function()
33299 var v = this.hiddenEl().getValue();
33301 return this.fixPrecision(this.parseValue(v));
33304 parseValue : function(value)
33306 if(this.thousandsDelimiter) {
33308 r = new RegExp(",", "g");
33309 value = value.replace(r, "");
33312 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33313 return isNaN(value) ? '' : value;
33316 fixPrecision : function(value)
33318 if(this.thousandsDelimiter) {
33320 r = new RegExp(",", "g");
33321 value = value.replace(r, "");
33324 var nan = isNaN(value);
33326 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33327 return nan ? '' : value;
33329 return parseFloat(value).toFixed(this.decimalPrecision);
33332 setValue : function(v)
33334 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33340 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33342 this.inputEl().dom.value = (v == '') ? '' :
33343 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33345 if(!this.allowZero && v === '0') {
33346 this.hiddenEl().dom.value = '';
33347 this.inputEl().dom.value = '';
33354 decimalPrecisionFcn : function(v)
33356 return Math.floor(v);
33359 beforeBlur : function()
33365 var v = this.parseValue(this.getRawValue());
33372 hiddenEl : function()
33374 return this.el.select('input.hidden-number-input',true).first();
33386 * @class Roo.bootstrap.DocumentSlider
33387 * @extends Roo.bootstrap.Component
33388 * Bootstrap DocumentSlider class
33391 * Create a new DocumentViewer
33392 * @param {Object} config The config object
33395 Roo.bootstrap.DocumentSlider = function(config){
33396 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33403 * Fire after initEvent
33404 * @param {Roo.bootstrap.DocumentSlider} this
33409 * Fire after update
33410 * @param {Roo.bootstrap.DocumentSlider} this
33416 * @param {Roo.bootstrap.DocumentSlider} this
33422 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33428 getAutoCreate : function()
33432 cls : 'roo-document-slider',
33436 cls : 'roo-document-slider-header',
33440 cls : 'roo-document-slider-header-title'
33446 cls : 'roo-document-slider-body',
33450 cls : 'roo-document-slider-prev',
33454 cls : 'fa fa-chevron-left'
33460 cls : 'roo-document-slider-thumb',
33464 cls : 'roo-document-slider-image'
33470 cls : 'roo-document-slider-next',
33474 cls : 'fa fa-chevron-right'
33486 initEvents : function()
33488 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33489 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33491 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33492 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33494 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33495 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33497 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33498 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33500 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33501 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33503 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33504 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33506 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33507 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33509 this.thumbEl.on('click', this.onClick, this);
33511 this.prevIndicator.on('click', this.prev, this);
33513 this.nextIndicator.on('click', this.next, this);
33517 initial : function()
33519 if(this.files.length){
33520 this.indicator = 1;
33524 this.fireEvent('initial', this);
33527 update : function()
33529 this.imageEl.attr('src', this.files[this.indicator - 1]);
33531 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33533 this.prevIndicator.show();
33535 if(this.indicator == 1){
33536 this.prevIndicator.hide();
33539 this.nextIndicator.show();
33541 if(this.indicator == this.files.length){
33542 this.nextIndicator.hide();
33545 this.thumbEl.scrollTo('top');
33547 this.fireEvent('update', this);
33550 onClick : function(e)
33552 e.preventDefault();
33554 this.fireEvent('click', this);
33559 e.preventDefault();
33561 this.indicator = Math.max(1, this.indicator - 1);
33568 e.preventDefault();
33570 this.indicator = Math.min(this.files.length, this.indicator + 1);
33584 * @class Roo.bootstrap.RadioSet
33585 * @extends Roo.bootstrap.Input
33586 * Bootstrap RadioSet class
33587 * @cfg {String} indicatorpos (left|right) default left
33588 * @cfg {Boolean} inline (true|false) inline the element (default true)
33589 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33591 * Create a new RadioSet
33592 * @param {Object} config The config object
33595 Roo.bootstrap.RadioSet = function(config){
33597 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33601 Roo.bootstrap.RadioSet.register(this);
33606 * Fires when the element is checked or unchecked.
33607 * @param {Roo.bootstrap.RadioSet} this This radio
33608 * @param {Roo.bootstrap.Radio} item The checked item
33613 * Fires when the element is click.
33614 * @param {Roo.bootstrap.RadioSet} this This radio set
33615 * @param {Roo.bootstrap.Radio} item The checked item
33616 * @param {Roo.EventObject} e The event object
33623 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33631 indicatorpos : 'left',
33633 getAutoCreate : function()
33637 cls : 'roo-radio-set-label',
33641 html : this.fieldLabel
33646 if(this.indicatorpos == 'left'){
33649 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33650 tooltip : 'This field is required'
33655 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33656 tooltip : 'This field is required'
33662 cls : 'roo-radio-set-items'
33665 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33667 if (align === 'left' && this.fieldLabel.length) {
33670 cls : "roo-radio-set-right",
33676 if(this.labelWidth > 12){
33677 label.style = "width: " + this.labelWidth + 'px';
33680 if(this.labelWidth < 13 && this.labelmd == 0){
33681 this.labelmd = this.labelWidth;
33684 if(this.labellg > 0){
33685 label.cls += ' col-lg-' + this.labellg;
33686 items.cls += ' col-lg-' + (12 - this.labellg);
33689 if(this.labelmd > 0){
33690 label.cls += ' col-md-' + this.labelmd;
33691 items.cls += ' col-md-' + (12 - this.labelmd);
33694 if(this.labelsm > 0){
33695 label.cls += ' col-sm-' + this.labelsm;
33696 items.cls += ' col-sm-' + (12 - this.labelsm);
33699 if(this.labelxs > 0){
33700 label.cls += ' col-xs-' + this.labelxs;
33701 items.cls += ' col-xs-' + (12 - this.labelxs);
33707 cls : 'roo-radio-set',
33711 cls : 'roo-radio-set-input',
33714 value : this.value ? this.value : ''
33721 if(this.weight.length){
33722 cfg.cls += ' roo-radio-' + this.weight;
33726 cfg.cls += ' roo-radio-set-inline';
33730 ['xs','sm','md','lg'].map(function(size){
33731 if (settings[size]) {
33732 cfg.cls += ' col-' + size + '-' + settings[size];
33740 initEvents : function()
33742 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33743 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33745 if(!this.fieldLabel.length){
33746 this.labelEl.hide();
33749 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33750 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33752 this.indicatorEl().addClass('invisible');
33754 this.originalValue = this.getValue();
33758 inputEl: function ()
33760 return this.el.select('.roo-radio-set-input', true).first();
33763 getChildContainer : function()
33765 return this.itemsEl;
33768 register : function(item)
33770 this.radioes.push(item);
33774 validate : function()
33776 if(this.getVisibilityEl().hasClass('hidden')){
33782 Roo.each(this.radioes, function(i){
33791 if(this.allowBlank) {
33795 if(this.disabled || valid){
33800 this.markInvalid();
33805 markValid : function()
33807 if(this.labelEl.isVisible(true)){
33808 this.indicatorEl().removeClass('visible');
33809 this.indicatorEl().addClass('invisible');
33812 this.el.removeClass([this.invalidClass, this.validClass]);
33813 this.el.addClass(this.validClass);
33815 this.fireEvent('valid', this);
33818 markInvalid : function(msg)
33820 if(this.allowBlank || this.disabled){
33824 if(this.labelEl.isVisible(true)){
33825 this.indicatorEl().removeClass('invisible');
33826 this.indicatorEl().addClass('visible');
33829 this.el.removeClass([this.invalidClass, this.validClass]);
33830 this.el.addClass(this.invalidClass);
33832 this.fireEvent('invalid', this, msg);
33836 setValue : function(v, suppressEvent)
33838 if(this.value === v){
33845 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33848 Roo.each(this.radioes, function(i){
33850 i.el.removeClass('checked');
33853 Roo.each(this.radioes, function(i){
33855 if(i.value === v || i.value.toString() === v.toString()){
33857 i.el.addClass('checked');
33859 if(suppressEvent !== true){
33860 this.fireEvent('check', this, i);
33871 clearInvalid : function(){
33873 if(!this.el || this.preventMark){
33877 this.el.removeClass([this.invalidClass]);
33879 this.fireEvent('valid', this);
33884 Roo.apply(Roo.bootstrap.RadioSet, {
33888 register : function(set)
33890 this.groups[set.name] = set;
33893 get: function(name)
33895 if (typeof(this.groups[name]) == 'undefined') {
33899 return this.groups[name] ;
33905 * Ext JS Library 1.1.1
33906 * Copyright(c) 2006-2007, Ext JS, LLC.
33908 * Originally Released Under LGPL - original licence link has changed is not relivant.
33911 * <script type="text/javascript">
33916 * @class Roo.bootstrap.SplitBar
33917 * @extends Roo.util.Observable
33918 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33922 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33923 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33924 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33925 split.minSize = 100;
33926 split.maxSize = 600;
33927 split.animate = true;
33928 split.on('moved', splitterMoved);
33931 * Create a new SplitBar
33932 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33933 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33934 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33935 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33936 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33937 position of the SplitBar).
33939 Roo.bootstrap.SplitBar = function(cfg){
33944 // dragElement : elm
33945 // resizingElement: el,
33947 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33948 // placement : Roo.bootstrap.SplitBar.LEFT ,
33949 // existingProxy ???
33952 this.el = Roo.get(cfg.dragElement, true);
33953 this.el.dom.unselectable = "on";
33955 this.resizingEl = Roo.get(cfg.resizingElement, true);
33959 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33960 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33963 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33966 * The minimum size of the resizing element. (Defaults to 0)
33972 * The maximum size of the resizing element. (Defaults to 2000)
33975 this.maxSize = 2000;
33978 * Whether to animate the transition to the new size
33981 this.animate = false;
33984 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33987 this.useShim = false;
33992 if(!cfg.existingProxy){
33994 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33996 this.proxy = Roo.get(cfg.existingProxy).dom;
33999 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34002 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34005 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34008 this.dragSpecs = {};
34011 * @private The adapter to use to positon and resize elements
34013 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34014 this.adapter.init(this);
34016 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34018 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34019 this.el.addClass("roo-splitbar-h");
34022 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34023 this.el.addClass("roo-splitbar-v");
34029 * Fires when the splitter is moved (alias for {@link #event-moved})
34030 * @param {Roo.bootstrap.SplitBar} this
34031 * @param {Number} newSize the new width or height
34036 * Fires when the splitter is moved
34037 * @param {Roo.bootstrap.SplitBar} this
34038 * @param {Number} newSize the new width or height
34042 * @event beforeresize
34043 * Fires before the splitter is dragged
34044 * @param {Roo.bootstrap.SplitBar} this
34046 "beforeresize" : true,
34048 "beforeapply" : true
34051 Roo.util.Observable.call(this);
34054 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34055 onStartProxyDrag : function(x, y){
34056 this.fireEvent("beforeresize", this);
34058 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34060 o.enableDisplayMode("block");
34061 // all splitbars share the same overlay
34062 Roo.bootstrap.SplitBar.prototype.overlay = o;
34064 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34065 this.overlay.show();
34066 Roo.get(this.proxy).setDisplayed("block");
34067 var size = this.adapter.getElementSize(this);
34068 this.activeMinSize = this.getMinimumSize();;
34069 this.activeMaxSize = this.getMaximumSize();;
34070 var c1 = size - this.activeMinSize;
34071 var c2 = Math.max(this.activeMaxSize - size, 0);
34072 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34073 this.dd.resetConstraints();
34074 this.dd.setXConstraint(
34075 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34076 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34078 this.dd.setYConstraint(0, 0);
34080 this.dd.resetConstraints();
34081 this.dd.setXConstraint(0, 0);
34082 this.dd.setYConstraint(
34083 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34084 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34087 this.dragSpecs.startSize = size;
34088 this.dragSpecs.startPoint = [x, y];
34089 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34093 * @private Called after the drag operation by the DDProxy
34095 onEndProxyDrag : function(e){
34096 Roo.get(this.proxy).setDisplayed(false);
34097 var endPoint = Roo.lib.Event.getXY(e);
34099 this.overlay.hide();
34102 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34103 newSize = this.dragSpecs.startSize +
34104 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34105 endPoint[0] - this.dragSpecs.startPoint[0] :
34106 this.dragSpecs.startPoint[0] - endPoint[0]
34109 newSize = this.dragSpecs.startSize +
34110 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34111 endPoint[1] - this.dragSpecs.startPoint[1] :
34112 this.dragSpecs.startPoint[1] - endPoint[1]
34115 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34116 if(newSize != this.dragSpecs.startSize){
34117 if(this.fireEvent('beforeapply', this, newSize) !== false){
34118 this.adapter.setElementSize(this, newSize);
34119 this.fireEvent("moved", this, newSize);
34120 this.fireEvent("resize", this, newSize);
34126 * Get the adapter this SplitBar uses
34127 * @return The adapter object
34129 getAdapter : function(){
34130 return this.adapter;
34134 * Set the adapter this SplitBar uses
34135 * @param {Object} adapter A SplitBar adapter object
34137 setAdapter : function(adapter){
34138 this.adapter = adapter;
34139 this.adapter.init(this);
34143 * Gets the minimum size for the resizing element
34144 * @return {Number} The minimum size
34146 getMinimumSize : function(){
34147 return this.minSize;
34151 * Sets the minimum size for the resizing element
34152 * @param {Number} minSize The minimum size
34154 setMinimumSize : function(minSize){
34155 this.minSize = minSize;
34159 * Gets the maximum size for the resizing element
34160 * @return {Number} The maximum size
34162 getMaximumSize : function(){
34163 return this.maxSize;
34167 * Sets the maximum size for the resizing element
34168 * @param {Number} maxSize The maximum size
34170 setMaximumSize : function(maxSize){
34171 this.maxSize = maxSize;
34175 * Sets the initialize size for the resizing element
34176 * @param {Number} size The initial size
34178 setCurrentSize : function(size){
34179 var oldAnimate = this.animate;
34180 this.animate = false;
34181 this.adapter.setElementSize(this, size);
34182 this.animate = oldAnimate;
34186 * Destroy this splitbar.
34187 * @param {Boolean} removeEl True to remove the element
34189 destroy : function(removeEl){
34191 this.shim.remove();
34194 this.proxy.parentNode.removeChild(this.proxy);
34202 * @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.
34204 Roo.bootstrap.SplitBar.createProxy = function(dir){
34205 var proxy = new Roo.Element(document.createElement("div"));
34206 proxy.unselectable();
34207 var cls = 'roo-splitbar-proxy';
34208 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34209 document.body.appendChild(proxy.dom);
34214 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34215 * Default Adapter. It assumes the splitter and resizing element are not positioned
34216 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34218 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34221 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34222 // do nothing for now
34223 init : function(s){
34227 * Called before drag operations to get the current size of the resizing element.
34228 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34230 getElementSize : function(s){
34231 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34232 return s.resizingEl.getWidth();
34234 return s.resizingEl.getHeight();
34239 * Called after drag operations to set the size of the resizing element.
34240 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34241 * @param {Number} newSize The new size to set
34242 * @param {Function} onComplete A function to be invoked when resizing is complete
34244 setElementSize : function(s, newSize, onComplete){
34245 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34247 s.resizingEl.setWidth(newSize);
34249 onComplete(s, newSize);
34252 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34257 s.resizingEl.setHeight(newSize);
34259 onComplete(s, newSize);
34262 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34269 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34270 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34271 * Adapter that moves the splitter element to align with the resized sizing element.
34272 * Used with an absolute positioned SplitBar.
34273 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34274 * document.body, make sure you assign an id to the body element.
34276 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34277 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34278 this.container = Roo.get(container);
34281 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34282 init : function(s){
34283 this.basic.init(s);
34286 getElementSize : function(s){
34287 return this.basic.getElementSize(s);
34290 setElementSize : function(s, newSize, onComplete){
34291 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34294 moveSplitter : function(s){
34295 var yes = Roo.bootstrap.SplitBar;
34296 switch(s.placement){
34298 s.el.setX(s.resizingEl.getRight());
34301 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34304 s.el.setY(s.resizingEl.getBottom());
34307 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34314 * Orientation constant - Create a vertical SplitBar
34318 Roo.bootstrap.SplitBar.VERTICAL = 1;
34321 * Orientation constant - Create a horizontal SplitBar
34325 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34328 * Placement constant - The resizing element is to the left of the splitter element
34332 Roo.bootstrap.SplitBar.LEFT = 1;
34335 * Placement constant - The resizing element is to the right of the splitter element
34339 Roo.bootstrap.SplitBar.RIGHT = 2;
34342 * Placement constant - The resizing element is positioned above the splitter element
34346 Roo.bootstrap.SplitBar.TOP = 3;
34349 * Placement constant - The resizing element is positioned under splitter element
34353 Roo.bootstrap.SplitBar.BOTTOM = 4;
34354 Roo.namespace("Roo.bootstrap.layout");/*
34356 * Ext JS Library 1.1.1
34357 * Copyright(c) 2006-2007, Ext JS, LLC.
34359 * Originally Released Under LGPL - original licence link has changed is not relivant.
34362 * <script type="text/javascript">
34366 * @class Roo.bootstrap.layout.Manager
34367 * @extends Roo.bootstrap.Component
34368 * Base class for layout managers.
34370 Roo.bootstrap.layout.Manager = function(config)
34372 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34378 /** false to disable window resize monitoring @type Boolean */
34379 this.monitorWindowResize = true;
34384 * Fires when a layout is performed.
34385 * @param {Roo.LayoutManager} this
34389 * @event regionresized
34390 * Fires when the user resizes a region.
34391 * @param {Roo.LayoutRegion} region The resized region
34392 * @param {Number} newSize The new size (width for east/west, height for north/south)
34394 "regionresized" : true,
34396 * @event regioncollapsed
34397 * Fires when a region is collapsed.
34398 * @param {Roo.LayoutRegion} region The collapsed region
34400 "regioncollapsed" : true,
34402 * @event regionexpanded
34403 * Fires when a region is expanded.
34404 * @param {Roo.LayoutRegion} region The expanded region
34406 "regionexpanded" : true
34408 this.updating = false;
34411 this.el = Roo.get(config.el);
34417 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34422 monitorWindowResize : true,
34428 onRender : function(ct, position)
34431 this.el = Roo.get(ct);
34434 //this.fireEvent('render',this);
34438 initEvents: function()
34442 // ie scrollbar fix
34443 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34444 document.body.scroll = "no";
34445 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34446 this.el.position('relative');
34448 this.id = this.el.id;
34449 this.el.addClass("roo-layout-container");
34450 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34451 if(this.el.dom != document.body ) {
34452 this.el.on('resize', this.layout,this);
34453 this.el.on('show', this.layout,this);
34459 * Returns true if this layout is currently being updated
34460 * @return {Boolean}
34462 isUpdating : function(){
34463 return this.updating;
34467 * Suspend the LayoutManager from doing auto-layouts while
34468 * making multiple add or remove calls
34470 beginUpdate : function(){
34471 this.updating = true;
34475 * Restore auto-layouts and optionally disable the manager from performing a layout
34476 * @param {Boolean} noLayout true to disable a layout update
34478 endUpdate : function(noLayout){
34479 this.updating = false;
34485 layout: function(){
34489 onRegionResized : function(region, newSize){
34490 this.fireEvent("regionresized", region, newSize);
34494 onRegionCollapsed : function(region){
34495 this.fireEvent("regioncollapsed", region);
34498 onRegionExpanded : function(region){
34499 this.fireEvent("regionexpanded", region);
34503 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34504 * performs box-model adjustments.
34505 * @return {Object} The size as an object {width: (the width), height: (the height)}
34507 getViewSize : function()
34510 if(this.el.dom != document.body){
34511 size = this.el.getSize();
34513 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34515 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34516 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34521 * Returns the Element this layout is bound to.
34522 * @return {Roo.Element}
34524 getEl : function(){
34529 * Returns the specified region.
34530 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34531 * @return {Roo.LayoutRegion}
34533 getRegion : function(target){
34534 return this.regions[target.toLowerCase()];
34537 onWindowResize : function(){
34538 if(this.monitorWindowResize){
34545 * Ext JS Library 1.1.1
34546 * Copyright(c) 2006-2007, Ext JS, LLC.
34548 * Originally Released Under LGPL - original licence link has changed is not relivant.
34551 * <script type="text/javascript">
34554 * @class Roo.bootstrap.layout.Border
34555 * @extends Roo.bootstrap.layout.Manager
34556 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34557 * please see: examples/bootstrap/nested.html<br><br>
34559 <b>The container the layout is rendered into can be either the body element or any other element.
34560 If it is not the body element, the container needs to either be an absolute positioned element,
34561 or you will need to add "position:relative" to the css of the container. You will also need to specify
34562 the container size if it is not the body element.</b>
34565 * Create a new Border
34566 * @param {Object} config Configuration options
34568 Roo.bootstrap.layout.Border = function(config){
34569 config = config || {};
34570 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34574 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34575 if(config[region]){
34576 config[region].region = region;
34577 this.addRegion(config[region]);
34583 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34585 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34587 * Creates and adds a new region if it doesn't already exist.
34588 * @param {String} target The target region key (north, south, east, west or center).
34589 * @param {Object} config The regions config object
34590 * @return {BorderLayoutRegion} The new region
34592 addRegion : function(config)
34594 if(!this.regions[config.region]){
34595 var r = this.factory(config);
34596 this.bindRegion(r);
34598 return this.regions[config.region];
34602 bindRegion : function(r){
34603 this.regions[r.config.region] = r;
34605 r.on("visibilitychange", this.layout, this);
34606 r.on("paneladded", this.layout, this);
34607 r.on("panelremoved", this.layout, this);
34608 r.on("invalidated", this.layout, this);
34609 r.on("resized", this.onRegionResized, this);
34610 r.on("collapsed", this.onRegionCollapsed, this);
34611 r.on("expanded", this.onRegionExpanded, this);
34615 * Performs a layout update.
34617 layout : function()
34619 if(this.updating) {
34623 // render all the rebions if they have not been done alreayd?
34624 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34625 if(this.regions[region] && !this.regions[region].bodyEl){
34626 this.regions[region].onRender(this.el)
34630 var size = this.getViewSize();
34631 var w = size.width;
34632 var h = size.height;
34637 //var x = 0, y = 0;
34639 var rs = this.regions;
34640 var north = rs["north"];
34641 var south = rs["south"];
34642 var west = rs["west"];
34643 var east = rs["east"];
34644 var center = rs["center"];
34645 //if(this.hideOnLayout){ // not supported anymore
34646 //c.el.setStyle("display", "none");
34648 if(north && north.isVisible()){
34649 var b = north.getBox();
34650 var m = north.getMargins();
34651 b.width = w - (m.left+m.right);
34654 centerY = b.height + b.y + m.bottom;
34655 centerH -= centerY;
34656 north.updateBox(this.safeBox(b));
34658 if(south && south.isVisible()){
34659 var b = south.getBox();
34660 var m = south.getMargins();
34661 b.width = w - (m.left+m.right);
34663 var totalHeight = (b.height + m.top + m.bottom);
34664 b.y = h - totalHeight + m.top;
34665 centerH -= totalHeight;
34666 south.updateBox(this.safeBox(b));
34668 if(west && west.isVisible()){
34669 var b = west.getBox();
34670 var m = west.getMargins();
34671 b.height = centerH - (m.top+m.bottom);
34673 b.y = centerY + m.top;
34674 var totalWidth = (b.width + m.left + m.right);
34675 centerX += totalWidth;
34676 centerW -= totalWidth;
34677 west.updateBox(this.safeBox(b));
34679 if(east && east.isVisible()){
34680 var b = east.getBox();
34681 var m = east.getMargins();
34682 b.height = centerH - (m.top+m.bottom);
34683 var totalWidth = (b.width + m.left + m.right);
34684 b.x = w - totalWidth + m.left;
34685 b.y = centerY + m.top;
34686 centerW -= totalWidth;
34687 east.updateBox(this.safeBox(b));
34690 var m = center.getMargins();
34692 x: centerX + m.left,
34693 y: centerY + m.top,
34694 width: centerW - (m.left+m.right),
34695 height: centerH - (m.top+m.bottom)
34697 //if(this.hideOnLayout){
34698 //center.el.setStyle("display", "block");
34700 center.updateBox(this.safeBox(centerBox));
34703 this.fireEvent("layout", this);
34707 safeBox : function(box){
34708 box.width = Math.max(0, box.width);
34709 box.height = Math.max(0, box.height);
34714 * Adds a ContentPanel (or subclass) to this layout.
34715 * @param {String} target The target region key (north, south, east, west or center).
34716 * @param {Roo.ContentPanel} panel The panel to add
34717 * @return {Roo.ContentPanel} The added panel
34719 add : function(target, panel){
34721 target = target.toLowerCase();
34722 return this.regions[target].add(panel);
34726 * Remove a ContentPanel (or subclass) to this layout.
34727 * @param {String} target The target region key (north, south, east, west or center).
34728 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34729 * @return {Roo.ContentPanel} The removed panel
34731 remove : function(target, panel){
34732 target = target.toLowerCase();
34733 return this.regions[target].remove(panel);
34737 * Searches all regions for a panel with the specified id
34738 * @param {String} panelId
34739 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34741 findPanel : function(panelId){
34742 var rs = this.regions;
34743 for(var target in rs){
34744 if(typeof rs[target] != "function"){
34745 var p = rs[target].getPanel(panelId);
34755 * Searches all regions for a panel with the specified id and activates (shows) it.
34756 * @param {String/ContentPanel} panelId The panels id or the panel itself
34757 * @return {Roo.ContentPanel} The shown panel or null
34759 showPanel : function(panelId) {
34760 var rs = this.regions;
34761 for(var target in rs){
34762 var r = rs[target];
34763 if(typeof r != "function"){
34764 if(r.hasPanel(panelId)){
34765 return r.showPanel(panelId);
34773 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34774 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34777 restoreState : function(provider){
34779 provider = Roo.state.Manager;
34781 var sm = new Roo.LayoutStateManager();
34782 sm.init(this, provider);
34788 * Adds a xtype elements to the layout.
34792 xtype : 'ContentPanel',
34799 xtype : 'NestedLayoutPanel',
34805 items : [ ... list of content panels or nested layout panels.. ]
34809 * @param {Object} cfg Xtype definition of item to add.
34811 addxtype : function(cfg)
34813 // basically accepts a pannel...
34814 // can accept a layout region..!?!?
34815 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34818 // theory? children can only be panels??
34820 //if (!cfg.xtype.match(/Panel$/)) {
34825 if (typeof(cfg.region) == 'undefined') {
34826 Roo.log("Failed to add Panel, region was not set");
34830 var region = cfg.region;
34836 xitems = cfg.items;
34843 case 'Content': // ContentPanel (el, cfg)
34844 case 'Scroll': // ContentPanel (el, cfg)
34846 cfg.autoCreate = true;
34847 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34849 // var el = this.el.createChild();
34850 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34853 this.add(region, ret);
34857 case 'TreePanel': // our new panel!
34858 cfg.el = this.el.createChild();
34859 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34860 this.add(region, ret);
34865 // create a new Layout (which is a Border Layout...
34867 var clayout = cfg.layout;
34868 clayout.el = this.el.createChild();
34869 clayout.items = clayout.items || [];
34873 // replace this exitems with the clayout ones..
34874 xitems = clayout.items;
34876 // force background off if it's in center...
34877 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34878 cfg.background = false;
34880 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34883 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34884 //console.log('adding nested layout panel ' + cfg.toSource());
34885 this.add(region, ret);
34886 nb = {}; /// find first...
34891 // needs grid and region
34893 //var el = this.getRegion(region).el.createChild();
34895 *var el = this.el.createChild();
34896 // create the grid first...
34897 cfg.grid.container = el;
34898 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34901 if (region == 'center' && this.active ) {
34902 cfg.background = false;
34905 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34907 this.add(region, ret);
34909 if (cfg.background) {
34910 // render grid on panel activation (if panel background)
34911 ret.on('activate', function(gp) {
34912 if (!gp.grid.rendered) {
34913 // gp.grid.render(el);
34917 // cfg.grid.render(el);
34923 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34924 // it was the old xcomponent building that caused this before.
34925 // espeically if border is the top element in the tree.
34935 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34937 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34938 this.add(region, ret);
34942 throw "Can not add '" + cfg.xtype + "' to Border";
34948 this.beginUpdate();
34952 Roo.each(xitems, function(i) {
34953 region = nb && i.region ? i.region : false;
34955 var add = ret.addxtype(i);
34958 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34959 if (!i.background) {
34960 abn[region] = nb[region] ;
34967 // make the last non-background panel active..
34968 //if (nb) { Roo.log(abn); }
34971 for(var r in abn) {
34972 region = this.getRegion(r);
34974 // tried using nb[r], but it does not work..
34976 region.showPanel(abn[r]);
34987 factory : function(cfg)
34990 var validRegions = Roo.bootstrap.layout.Border.regions;
34992 var target = cfg.region;
34995 var r = Roo.bootstrap.layout;
34999 return new r.North(cfg);
35001 return new r.South(cfg);
35003 return new r.East(cfg);
35005 return new r.West(cfg);
35007 return new r.Center(cfg);
35009 throw 'Layout region "'+target+'" not supported.';
35016 * Ext JS Library 1.1.1
35017 * Copyright(c) 2006-2007, Ext JS, LLC.
35019 * Originally Released Under LGPL - original licence link has changed is not relivant.
35022 * <script type="text/javascript">
35026 * @class Roo.bootstrap.layout.Basic
35027 * @extends Roo.util.Observable
35028 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35029 * and does not have a titlebar, tabs or any other features. All it does is size and position
35030 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35031 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35032 * @cfg {string} region the region that it inhabits..
35033 * @cfg {bool} skipConfig skip config?
35037 Roo.bootstrap.layout.Basic = function(config){
35039 this.mgr = config.mgr;
35041 this.position = config.region;
35043 var skipConfig = config.skipConfig;
35047 * @scope Roo.BasicLayoutRegion
35051 * @event beforeremove
35052 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35053 * @param {Roo.LayoutRegion} this
35054 * @param {Roo.ContentPanel} panel The panel
35055 * @param {Object} e The cancel event object
35057 "beforeremove" : true,
35059 * @event invalidated
35060 * Fires when the layout for this region is changed.
35061 * @param {Roo.LayoutRegion} this
35063 "invalidated" : true,
35065 * @event visibilitychange
35066 * Fires when this region is shown or hidden
35067 * @param {Roo.LayoutRegion} this
35068 * @param {Boolean} visibility true or false
35070 "visibilitychange" : true,
35072 * @event paneladded
35073 * Fires when a panel is added.
35074 * @param {Roo.LayoutRegion} this
35075 * @param {Roo.ContentPanel} panel The panel
35077 "paneladded" : true,
35079 * @event panelremoved
35080 * Fires when a panel is removed.
35081 * @param {Roo.LayoutRegion} this
35082 * @param {Roo.ContentPanel} panel The panel
35084 "panelremoved" : true,
35086 * @event beforecollapse
35087 * Fires when this region before collapse.
35088 * @param {Roo.LayoutRegion} this
35090 "beforecollapse" : true,
35093 * Fires when this region is collapsed.
35094 * @param {Roo.LayoutRegion} this
35096 "collapsed" : true,
35099 * Fires when this region is expanded.
35100 * @param {Roo.LayoutRegion} this
35105 * Fires when this region is slid into view.
35106 * @param {Roo.LayoutRegion} this
35108 "slideshow" : true,
35111 * Fires when this region slides out of view.
35112 * @param {Roo.LayoutRegion} this
35114 "slidehide" : true,
35116 * @event panelactivated
35117 * Fires when a panel is activated.
35118 * @param {Roo.LayoutRegion} this
35119 * @param {Roo.ContentPanel} panel The activated panel
35121 "panelactivated" : true,
35124 * Fires when the user resizes this region.
35125 * @param {Roo.LayoutRegion} this
35126 * @param {Number} newSize The new size (width for east/west, height for north/south)
35130 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35131 this.panels = new Roo.util.MixedCollection();
35132 this.panels.getKey = this.getPanelId.createDelegate(this);
35134 this.activePanel = null;
35135 // ensure listeners are added...
35137 if (config.listeners || config.events) {
35138 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35139 listeners : config.listeners || {},
35140 events : config.events || {}
35144 if(skipConfig !== true){
35145 this.applyConfig(config);
35149 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35151 getPanelId : function(p){
35155 applyConfig : function(config){
35156 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35157 this.config = config;
35162 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35163 * the width, for horizontal (north, south) the height.
35164 * @param {Number} newSize The new width or height
35166 resizeTo : function(newSize){
35167 var el = this.el ? this.el :
35168 (this.activePanel ? this.activePanel.getEl() : null);
35170 switch(this.position){
35173 el.setWidth(newSize);
35174 this.fireEvent("resized", this, newSize);
35178 el.setHeight(newSize);
35179 this.fireEvent("resized", this, newSize);
35185 getBox : function(){
35186 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35189 getMargins : function(){
35190 return this.margins;
35193 updateBox : function(box){
35195 var el = this.activePanel.getEl();
35196 el.dom.style.left = box.x + "px";
35197 el.dom.style.top = box.y + "px";
35198 this.activePanel.setSize(box.width, box.height);
35202 * Returns the container element for this region.
35203 * @return {Roo.Element}
35205 getEl : function(){
35206 return this.activePanel;
35210 * Returns true if this region is currently visible.
35211 * @return {Boolean}
35213 isVisible : function(){
35214 return this.activePanel ? true : false;
35217 setActivePanel : function(panel){
35218 panel = this.getPanel(panel);
35219 if(this.activePanel && this.activePanel != panel){
35220 this.activePanel.setActiveState(false);
35221 this.activePanel.getEl().setLeftTop(-10000,-10000);
35223 this.activePanel = panel;
35224 panel.setActiveState(true);
35226 panel.setSize(this.box.width, this.box.height);
35228 this.fireEvent("panelactivated", this, panel);
35229 this.fireEvent("invalidated");
35233 * Show the specified panel.
35234 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35235 * @return {Roo.ContentPanel} The shown panel or null
35237 showPanel : function(panel){
35238 panel = this.getPanel(panel);
35240 this.setActivePanel(panel);
35246 * Get the active panel for this region.
35247 * @return {Roo.ContentPanel} The active panel or null
35249 getActivePanel : function(){
35250 return this.activePanel;
35254 * Add the passed ContentPanel(s)
35255 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35256 * @return {Roo.ContentPanel} The panel added (if only one was added)
35258 add : function(panel){
35259 if(arguments.length > 1){
35260 for(var i = 0, len = arguments.length; i < len; i++) {
35261 this.add(arguments[i]);
35265 if(this.hasPanel(panel)){
35266 this.showPanel(panel);
35269 var el = panel.getEl();
35270 if(el.dom.parentNode != this.mgr.el.dom){
35271 this.mgr.el.dom.appendChild(el.dom);
35273 if(panel.setRegion){
35274 panel.setRegion(this);
35276 this.panels.add(panel);
35277 el.setStyle("position", "absolute");
35278 if(!panel.background){
35279 this.setActivePanel(panel);
35280 if(this.config.initialSize && this.panels.getCount()==1){
35281 this.resizeTo(this.config.initialSize);
35284 this.fireEvent("paneladded", this, panel);
35289 * Returns true if the panel is in this region.
35290 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35291 * @return {Boolean}
35293 hasPanel : function(panel){
35294 if(typeof panel == "object"){ // must be panel obj
35295 panel = panel.getId();
35297 return this.getPanel(panel) ? true : false;
35301 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35302 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35303 * @param {Boolean} preservePanel Overrides the config preservePanel option
35304 * @return {Roo.ContentPanel} The panel that was removed
35306 remove : function(panel, preservePanel){
35307 panel = this.getPanel(panel);
35312 this.fireEvent("beforeremove", this, panel, e);
35313 if(e.cancel === true){
35316 var panelId = panel.getId();
35317 this.panels.removeKey(panelId);
35322 * Returns the panel specified or null if it's not in this region.
35323 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35324 * @return {Roo.ContentPanel}
35326 getPanel : function(id){
35327 if(typeof id == "object"){ // must be panel obj
35330 return this.panels.get(id);
35334 * Returns this regions position (north/south/east/west/center).
35337 getPosition: function(){
35338 return this.position;
35342 * Ext JS Library 1.1.1
35343 * Copyright(c) 2006-2007, Ext JS, LLC.
35345 * Originally Released Under LGPL - original licence link has changed is not relivant.
35348 * <script type="text/javascript">
35352 * @class Roo.bootstrap.layout.Region
35353 * @extends Roo.bootstrap.layout.Basic
35354 * This class represents a region in a layout manager.
35356 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35357 * @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})
35358 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35359 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35360 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35361 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35362 * @cfg {String} title The title for the region (overrides panel titles)
35363 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35364 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35365 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35366 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35367 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35368 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35369 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35370 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35371 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35372 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35374 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35375 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35376 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35377 * @cfg {Number} width For East/West panels
35378 * @cfg {Number} height For North/South panels
35379 * @cfg {Boolean} split To show the splitter
35380 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35382 * @cfg {string} cls Extra CSS classes to add to region
35384 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35385 * @cfg {string} region the region that it inhabits..
35388 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35389 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35391 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35392 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35393 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35395 Roo.bootstrap.layout.Region = function(config)
35397 this.applyConfig(config);
35399 var mgr = config.mgr;
35400 var pos = config.region;
35401 config.skipConfig = true;
35402 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35405 this.onRender(mgr.el);
35408 this.visible = true;
35409 this.collapsed = false;
35410 this.unrendered_panels = [];
35413 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35415 position: '', // set by wrapper (eg. north/south etc..)
35416 unrendered_panels : null, // unrendered panels.
35417 createBody : function(){
35418 /** This region's body element
35419 * @type Roo.Element */
35420 this.bodyEl = this.el.createChild({
35422 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35426 onRender: function(ctr, pos)
35428 var dh = Roo.DomHelper;
35429 /** This region's container element
35430 * @type Roo.Element */
35431 this.el = dh.append(ctr.dom, {
35433 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35435 /** This region's title element
35436 * @type Roo.Element */
35438 this.titleEl = dh.append(this.el.dom,
35441 unselectable: "on",
35442 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35444 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35445 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35448 this.titleEl.enableDisplayMode();
35449 /** This region's title text element
35450 * @type HTMLElement */
35451 this.titleTextEl = this.titleEl.dom.firstChild;
35452 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35454 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35455 this.closeBtn.enableDisplayMode();
35456 this.closeBtn.on("click", this.closeClicked, this);
35457 this.closeBtn.hide();
35459 this.createBody(this.config);
35460 if(this.config.hideWhenEmpty){
35462 this.on("paneladded", this.validateVisibility, this);
35463 this.on("panelremoved", this.validateVisibility, this);
35465 if(this.autoScroll){
35466 this.bodyEl.setStyle("overflow", "auto");
35468 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35470 //if(c.titlebar !== false){
35471 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35472 this.titleEl.hide();
35474 this.titleEl.show();
35475 if(this.config.title){
35476 this.titleTextEl.innerHTML = this.config.title;
35480 if(this.config.collapsed){
35481 this.collapse(true);
35483 if(this.config.hidden){
35487 if (this.unrendered_panels && this.unrendered_panels.length) {
35488 for (var i =0;i< this.unrendered_panels.length; i++) {
35489 this.add(this.unrendered_panels[i]);
35491 this.unrendered_panels = null;
35497 applyConfig : function(c)
35500 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35501 var dh = Roo.DomHelper;
35502 if(c.titlebar !== false){
35503 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35504 this.collapseBtn.on("click", this.collapse, this);
35505 this.collapseBtn.enableDisplayMode();
35507 if(c.showPin === true || this.showPin){
35508 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35509 this.stickBtn.enableDisplayMode();
35510 this.stickBtn.on("click", this.expand, this);
35511 this.stickBtn.hide();
35516 /** This region's collapsed element
35517 * @type Roo.Element */
35520 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35521 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35524 if(c.floatable !== false){
35525 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35526 this.collapsedEl.on("click", this.collapseClick, this);
35529 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35530 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35531 id: "message", unselectable: "on", style:{"float":"left"}});
35532 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35534 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35535 this.expandBtn.on("click", this.expand, this);
35539 if(this.collapseBtn){
35540 this.collapseBtn.setVisible(c.collapsible == true);
35543 this.cmargins = c.cmargins || this.cmargins ||
35544 (this.position == "west" || this.position == "east" ?
35545 {top: 0, left: 2, right:2, bottom: 0} :
35546 {top: 2, left: 0, right:0, bottom: 2});
35548 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35551 this.bottomTabs = c.tabPosition != "top";
35553 this.autoScroll = c.autoScroll || false;
35558 this.duration = c.duration || .30;
35559 this.slideDuration = c.slideDuration || .45;
35564 * Returns true if this region is currently visible.
35565 * @return {Boolean}
35567 isVisible : function(){
35568 return this.visible;
35572 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35573 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35575 //setCollapsedTitle : function(title){
35576 // title = title || " ";
35577 // if(this.collapsedTitleTextEl){
35578 // this.collapsedTitleTextEl.innerHTML = title;
35582 getBox : function(){
35584 // if(!this.collapsed){
35585 b = this.el.getBox(false, true);
35587 // b = this.collapsedEl.getBox(false, true);
35592 getMargins : function(){
35593 return this.margins;
35594 //return this.collapsed ? this.cmargins : this.margins;
35597 highlight : function(){
35598 this.el.addClass("x-layout-panel-dragover");
35601 unhighlight : function(){
35602 this.el.removeClass("x-layout-panel-dragover");
35605 updateBox : function(box)
35607 if (!this.bodyEl) {
35608 return; // not rendered yet..
35612 if(!this.collapsed){
35613 this.el.dom.style.left = box.x + "px";
35614 this.el.dom.style.top = box.y + "px";
35615 this.updateBody(box.width, box.height);
35617 this.collapsedEl.dom.style.left = box.x + "px";
35618 this.collapsedEl.dom.style.top = box.y + "px";
35619 this.collapsedEl.setSize(box.width, box.height);
35622 this.tabs.autoSizeTabs();
35626 updateBody : function(w, h)
35629 this.el.setWidth(w);
35630 w -= this.el.getBorderWidth("rl");
35631 if(this.config.adjustments){
35632 w += this.config.adjustments[0];
35635 if(h !== null && h > 0){
35636 this.el.setHeight(h);
35637 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35638 h -= this.el.getBorderWidth("tb");
35639 if(this.config.adjustments){
35640 h += this.config.adjustments[1];
35642 this.bodyEl.setHeight(h);
35644 h = this.tabs.syncHeight(h);
35647 if(this.panelSize){
35648 w = w !== null ? w : this.panelSize.width;
35649 h = h !== null ? h : this.panelSize.height;
35651 if(this.activePanel){
35652 var el = this.activePanel.getEl();
35653 w = w !== null ? w : el.getWidth();
35654 h = h !== null ? h : el.getHeight();
35655 this.panelSize = {width: w, height: h};
35656 this.activePanel.setSize(w, h);
35658 if(Roo.isIE && this.tabs){
35659 this.tabs.el.repaint();
35664 * Returns the container element for this region.
35665 * @return {Roo.Element}
35667 getEl : function(){
35672 * Hides this region.
35675 //if(!this.collapsed){
35676 this.el.dom.style.left = "-2000px";
35679 // this.collapsedEl.dom.style.left = "-2000px";
35680 // this.collapsedEl.hide();
35682 this.visible = false;
35683 this.fireEvent("visibilitychange", this, false);
35687 * Shows this region if it was previously hidden.
35690 //if(!this.collapsed){
35693 // this.collapsedEl.show();
35695 this.visible = true;
35696 this.fireEvent("visibilitychange", this, true);
35699 closeClicked : function(){
35700 if(this.activePanel){
35701 this.remove(this.activePanel);
35705 collapseClick : function(e){
35707 e.stopPropagation();
35710 e.stopPropagation();
35716 * Collapses this region.
35717 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35720 collapse : function(skipAnim, skipCheck = false){
35721 if(this.collapsed) {
35725 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35727 this.collapsed = true;
35729 this.split.el.hide();
35731 if(this.config.animate && skipAnim !== true){
35732 this.fireEvent("invalidated", this);
35733 this.animateCollapse();
35735 this.el.setLocation(-20000,-20000);
35737 this.collapsedEl.show();
35738 this.fireEvent("collapsed", this);
35739 this.fireEvent("invalidated", this);
35745 animateCollapse : function(){
35750 * Expands this region if it was previously collapsed.
35751 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35752 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35755 expand : function(e, skipAnim){
35757 e.stopPropagation();
35759 if(!this.collapsed || this.el.hasActiveFx()) {
35763 this.afterSlideIn();
35766 this.collapsed = false;
35767 if(this.config.animate && skipAnim !== true){
35768 this.animateExpand();
35772 this.split.el.show();
35774 this.collapsedEl.setLocation(-2000,-2000);
35775 this.collapsedEl.hide();
35776 this.fireEvent("invalidated", this);
35777 this.fireEvent("expanded", this);
35781 animateExpand : function(){
35785 initTabs : function()
35787 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35789 var ts = new Roo.bootstrap.panel.Tabs({
35790 el: this.bodyEl.dom,
35791 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35792 disableTooltips: this.config.disableTabTips,
35793 toolbar : this.config.toolbar
35796 if(this.config.hideTabs){
35797 ts.stripWrap.setDisplayed(false);
35800 ts.resizeTabs = this.config.resizeTabs === true;
35801 ts.minTabWidth = this.config.minTabWidth || 40;
35802 ts.maxTabWidth = this.config.maxTabWidth || 250;
35803 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35804 ts.monitorResize = false;
35805 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35806 ts.bodyEl.addClass('roo-layout-tabs-body');
35807 this.panels.each(this.initPanelAsTab, this);
35810 initPanelAsTab : function(panel){
35811 var ti = this.tabs.addTab(
35815 this.config.closeOnTab && panel.isClosable(),
35818 if(panel.tabTip !== undefined){
35819 ti.setTooltip(panel.tabTip);
35821 ti.on("activate", function(){
35822 this.setActivePanel(panel);
35825 if(this.config.closeOnTab){
35826 ti.on("beforeclose", function(t, e){
35828 this.remove(panel);
35832 panel.tabItem = ti;
35837 updatePanelTitle : function(panel, title)
35839 if(this.activePanel == panel){
35840 this.updateTitle(title);
35843 var ti = this.tabs.getTab(panel.getEl().id);
35845 if(panel.tabTip !== undefined){
35846 ti.setTooltip(panel.tabTip);
35851 updateTitle : function(title){
35852 if(this.titleTextEl && !this.config.title){
35853 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35857 setActivePanel : function(panel)
35859 panel = this.getPanel(panel);
35860 if(this.activePanel && this.activePanel != panel){
35861 if(this.activePanel.setActiveState(false) === false){
35865 this.activePanel = panel;
35866 panel.setActiveState(true);
35867 if(this.panelSize){
35868 panel.setSize(this.panelSize.width, this.panelSize.height);
35871 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35873 this.updateTitle(panel.getTitle());
35875 this.fireEvent("invalidated", this);
35877 this.fireEvent("panelactivated", this, panel);
35881 * Shows the specified panel.
35882 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35883 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35885 showPanel : function(panel)
35887 panel = this.getPanel(panel);
35890 var tab = this.tabs.getTab(panel.getEl().id);
35891 if(tab.isHidden()){
35892 this.tabs.unhideTab(tab.id);
35896 this.setActivePanel(panel);
35903 * Get the active panel for this region.
35904 * @return {Roo.ContentPanel} The active panel or null
35906 getActivePanel : function(){
35907 return this.activePanel;
35910 validateVisibility : function(){
35911 if(this.panels.getCount() < 1){
35912 this.updateTitle(" ");
35913 this.closeBtn.hide();
35916 if(!this.isVisible()){
35923 * Adds the passed ContentPanel(s) to this region.
35924 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35925 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35927 add : function(panel)
35929 if(arguments.length > 1){
35930 for(var i = 0, len = arguments.length; i < len; i++) {
35931 this.add(arguments[i]);
35936 // if we have not been rendered yet, then we can not really do much of this..
35937 if (!this.bodyEl) {
35938 this.unrendered_panels.push(panel);
35945 if(this.hasPanel(panel)){
35946 this.showPanel(panel);
35949 panel.setRegion(this);
35950 this.panels.add(panel);
35951 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35952 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35953 // and hide them... ???
35954 this.bodyEl.dom.appendChild(panel.getEl().dom);
35955 if(panel.background !== true){
35956 this.setActivePanel(panel);
35958 this.fireEvent("paneladded", this, panel);
35965 this.initPanelAsTab(panel);
35969 if(panel.background !== true){
35970 this.tabs.activate(panel.getEl().id);
35972 this.fireEvent("paneladded", this, panel);
35977 * Hides the tab for the specified panel.
35978 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35980 hidePanel : function(panel){
35981 if(this.tabs && (panel = this.getPanel(panel))){
35982 this.tabs.hideTab(panel.getEl().id);
35987 * Unhides the tab for a previously hidden panel.
35988 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35990 unhidePanel : function(panel){
35991 if(this.tabs && (panel = this.getPanel(panel))){
35992 this.tabs.unhideTab(panel.getEl().id);
35996 clearPanels : function(){
35997 while(this.panels.getCount() > 0){
35998 this.remove(this.panels.first());
36003 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36004 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36005 * @param {Boolean} preservePanel Overrides the config preservePanel option
36006 * @return {Roo.ContentPanel} The panel that was removed
36008 remove : function(panel, preservePanel)
36010 panel = this.getPanel(panel);
36015 this.fireEvent("beforeremove", this, panel, e);
36016 if(e.cancel === true){
36019 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36020 var panelId = panel.getId();
36021 this.panels.removeKey(panelId);
36023 document.body.appendChild(panel.getEl().dom);
36026 this.tabs.removeTab(panel.getEl().id);
36027 }else if (!preservePanel){
36028 this.bodyEl.dom.removeChild(panel.getEl().dom);
36030 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36031 var p = this.panels.first();
36032 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36033 tempEl.appendChild(p.getEl().dom);
36034 this.bodyEl.update("");
36035 this.bodyEl.dom.appendChild(p.getEl().dom);
36037 this.updateTitle(p.getTitle());
36039 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36040 this.setActivePanel(p);
36042 panel.setRegion(null);
36043 if(this.activePanel == panel){
36044 this.activePanel = null;
36046 if(this.config.autoDestroy !== false && preservePanel !== true){
36047 try{panel.destroy();}catch(e){}
36049 this.fireEvent("panelremoved", this, panel);
36054 * Returns the TabPanel component used by this region
36055 * @return {Roo.TabPanel}
36057 getTabs : function(){
36061 createTool : function(parentEl, className){
36062 var btn = Roo.DomHelper.append(parentEl, {
36064 cls: "x-layout-tools-button",
36067 cls: "roo-layout-tools-button-inner " + className,
36071 btn.addClassOnOver("roo-layout-tools-button-over");
36076 * Ext JS Library 1.1.1
36077 * Copyright(c) 2006-2007, Ext JS, LLC.
36079 * Originally Released Under LGPL - original licence link has changed is not relivant.
36082 * <script type="text/javascript">
36088 * @class Roo.SplitLayoutRegion
36089 * @extends Roo.LayoutRegion
36090 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36092 Roo.bootstrap.layout.Split = function(config){
36093 this.cursor = config.cursor;
36094 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36097 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36099 splitTip : "Drag to resize.",
36100 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36101 useSplitTips : false,
36103 applyConfig : function(config){
36104 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36107 onRender : function(ctr,pos) {
36109 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36110 if(!this.config.split){
36115 var splitEl = Roo.DomHelper.append(ctr.dom, {
36117 id: this.el.id + "-split",
36118 cls: "roo-layout-split roo-layout-split-"+this.position,
36121 /** The SplitBar for this region
36122 * @type Roo.SplitBar */
36123 // does not exist yet...
36124 Roo.log([this.position, this.orientation]);
36126 this.split = new Roo.bootstrap.SplitBar({
36127 dragElement : splitEl,
36128 resizingElement: this.el,
36129 orientation : this.orientation
36132 this.split.on("moved", this.onSplitMove, this);
36133 this.split.useShim = this.config.useShim === true;
36134 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36135 if(this.useSplitTips){
36136 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36138 //if(config.collapsible){
36139 // this.split.el.on("dblclick", this.collapse, this);
36142 if(typeof this.config.minSize != "undefined"){
36143 this.split.minSize = this.config.minSize;
36145 if(typeof this.config.maxSize != "undefined"){
36146 this.split.maxSize = this.config.maxSize;
36148 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36149 this.hideSplitter();
36154 getHMaxSize : function(){
36155 var cmax = this.config.maxSize || 10000;
36156 var center = this.mgr.getRegion("center");
36157 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36160 getVMaxSize : function(){
36161 var cmax = this.config.maxSize || 10000;
36162 var center = this.mgr.getRegion("center");
36163 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36166 onSplitMove : function(split, newSize){
36167 this.fireEvent("resized", this, newSize);
36171 * Returns the {@link Roo.SplitBar} for this region.
36172 * @return {Roo.SplitBar}
36174 getSplitBar : function(){
36179 this.hideSplitter();
36180 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36183 hideSplitter : function(){
36185 this.split.el.setLocation(-2000,-2000);
36186 this.split.el.hide();
36192 this.split.el.show();
36194 Roo.bootstrap.layout.Split.superclass.show.call(this);
36197 beforeSlide: function(){
36198 if(Roo.isGecko){// firefox overflow auto bug workaround
36199 this.bodyEl.clip();
36201 this.tabs.bodyEl.clip();
36203 if(this.activePanel){
36204 this.activePanel.getEl().clip();
36206 if(this.activePanel.beforeSlide){
36207 this.activePanel.beforeSlide();
36213 afterSlide : function(){
36214 if(Roo.isGecko){// firefox overflow auto bug workaround
36215 this.bodyEl.unclip();
36217 this.tabs.bodyEl.unclip();
36219 if(this.activePanel){
36220 this.activePanel.getEl().unclip();
36221 if(this.activePanel.afterSlide){
36222 this.activePanel.afterSlide();
36228 initAutoHide : function(){
36229 if(this.autoHide !== false){
36230 if(!this.autoHideHd){
36231 var st = new Roo.util.DelayedTask(this.slideIn, this);
36232 this.autoHideHd = {
36233 "mouseout": function(e){
36234 if(!e.within(this.el, true)){
36238 "mouseover" : function(e){
36244 this.el.on(this.autoHideHd);
36248 clearAutoHide : function(){
36249 if(this.autoHide !== false){
36250 this.el.un("mouseout", this.autoHideHd.mouseout);
36251 this.el.un("mouseover", this.autoHideHd.mouseover);
36255 clearMonitor : function(){
36256 Roo.get(document).un("click", this.slideInIf, this);
36259 // these names are backwards but not changed for compat
36260 slideOut : function(){
36261 if(this.isSlid || this.el.hasActiveFx()){
36264 this.isSlid = true;
36265 if(this.collapseBtn){
36266 this.collapseBtn.hide();
36268 this.closeBtnState = this.closeBtn.getStyle('display');
36269 this.closeBtn.hide();
36271 this.stickBtn.show();
36274 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36275 this.beforeSlide();
36276 this.el.setStyle("z-index", 10001);
36277 this.el.slideIn(this.getSlideAnchor(), {
36278 callback: function(){
36280 this.initAutoHide();
36281 Roo.get(document).on("click", this.slideInIf, this);
36282 this.fireEvent("slideshow", this);
36289 afterSlideIn : function(){
36290 this.clearAutoHide();
36291 this.isSlid = false;
36292 this.clearMonitor();
36293 this.el.setStyle("z-index", "");
36294 if(this.collapseBtn){
36295 this.collapseBtn.show();
36297 this.closeBtn.setStyle('display', this.closeBtnState);
36299 this.stickBtn.hide();
36301 this.fireEvent("slidehide", this);
36304 slideIn : function(cb){
36305 if(!this.isSlid || this.el.hasActiveFx()){
36309 this.isSlid = false;
36310 this.beforeSlide();
36311 this.el.slideOut(this.getSlideAnchor(), {
36312 callback: function(){
36313 this.el.setLeftTop(-10000, -10000);
36315 this.afterSlideIn();
36323 slideInIf : function(e){
36324 if(!e.within(this.el)){
36329 animateCollapse : function(){
36330 this.beforeSlide();
36331 this.el.setStyle("z-index", 20000);
36332 var anchor = this.getSlideAnchor();
36333 this.el.slideOut(anchor, {
36334 callback : function(){
36335 this.el.setStyle("z-index", "");
36336 this.collapsedEl.slideIn(anchor, {duration:.3});
36338 this.el.setLocation(-10000,-10000);
36340 this.fireEvent("collapsed", this);
36347 animateExpand : function(){
36348 this.beforeSlide();
36349 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36350 this.el.setStyle("z-index", 20000);
36351 this.collapsedEl.hide({
36354 this.el.slideIn(this.getSlideAnchor(), {
36355 callback : function(){
36356 this.el.setStyle("z-index", "");
36359 this.split.el.show();
36361 this.fireEvent("invalidated", this);
36362 this.fireEvent("expanded", this);
36390 getAnchor : function(){
36391 return this.anchors[this.position];
36394 getCollapseAnchor : function(){
36395 return this.canchors[this.position];
36398 getSlideAnchor : function(){
36399 return this.sanchors[this.position];
36402 getAlignAdj : function(){
36403 var cm = this.cmargins;
36404 switch(this.position){
36420 getExpandAdj : function(){
36421 var c = this.collapsedEl, cm = this.cmargins;
36422 switch(this.position){
36424 return [-(cm.right+c.getWidth()+cm.left), 0];
36427 return [cm.right+c.getWidth()+cm.left, 0];
36430 return [0, -(cm.top+cm.bottom+c.getHeight())];
36433 return [0, cm.top+cm.bottom+c.getHeight()];
36439 * Ext JS Library 1.1.1
36440 * Copyright(c) 2006-2007, Ext JS, LLC.
36442 * Originally Released Under LGPL - original licence link has changed is not relivant.
36445 * <script type="text/javascript">
36448 * These classes are private internal classes
36450 Roo.bootstrap.layout.Center = function(config){
36451 config.region = "center";
36452 Roo.bootstrap.layout.Region.call(this, config);
36453 this.visible = true;
36454 this.minWidth = config.minWidth || 20;
36455 this.minHeight = config.minHeight || 20;
36458 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36460 // center panel can't be hidden
36464 // center panel can't be hidden
36467 getMinWidth: function(){
36468 return this.minWidth;
36471 getMinHeight: function(){
36472 return this.minHeight;
36485 Roo.bootstrap.layout.North = function(config)
36487 config.region = 'north';
36488 config.cursor = 'n-resize';
36490 Roo.bootstrap.layout.Split.call(this, config);
36494 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36495 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36496 this.split.el.addClass("roo-layout-split-v");
36498 var size = config.initialSize || config.height;
36499 if(typeof size != "undefined"){
36500 this.el.setHeight(size);
36503 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36505 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36509 getBox : function(){
36510 if(this.collapsed){
36511 return this.collapsedEl.getBox();
36513 var box = this.el.getBox();
36515 box.height += this.split.el.getHeight();
36520 updateBox : function(box){
36521 if(this.split && !this.collapsed){
36522 box.height -= this.split.el.getHeight();
36523 this.split.el.setLeft(box.x);
36524 this.split.el.setTop(box.y+box.height);
36525 this.split.el.setWidth(box.width);
36527 if(this.collapsed){
36528 this.updateBody(box.width, null);
36530 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36538 Roo.bootstrap.layout.South = function(config){
36539 config.region = 'south';
36540 config.cursor = 's-resize';
36541 Roo.bootstrap.layout.Split.call(this, config);
36543 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36544 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36545 this.split.el.addClass("roo-layout-split-v");
36547 var size = config.initialSize || config.height;
36548 if(typeof size != "undefined"){
36549 this.el.setHeight(size);
36553 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36554 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36555 getBox : function(){
36556 if(this.collapsed){
36557 return this.collapsedEl.getBox();
36559 var box = this.el.getBox();
36561 var sh = this.split.el.getHeight();
36568 updateBox : function(box){
36569 if(this.split && !this.collapsed){
36570 var sh = this.split.el.getHeight();
36573 this.split.el.setLeft(box.x);
36574 this.split.el.setTop(box.y-sh);
36575 this.split.el.setWidth(box.width);
36577 if(this.collapsed){
36578 this.updateBody(box.width, null);
36580 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36584 Roo.bootstrap.layout.East = function(config){
36585 config.region = "east";
36586 config.cursor = "e-resize";
36587 Roo.bootstrap.layout.Split.call(this, config);
36589 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36590 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36591 this.split.el.addClass("roo-layout-split-h");
36593 var size = config.initialSize || config.width;
36594 if(typeof size != "undefined"){
36595 this.el.setWidth(size);
36598 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36599 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36600 getBox : function(){
36601 if(this.collapsed){
36602 return this.collapsedEl.getBox();
36604 var box = this.el.getBox();
36606 var sw = this.split.el.getWidth();
36613 updateBox : function(box){
36614 if(this.split && !this.collapsed){
36615 var sw = this.split.el.getWidth();
36617 this.split.el.setLeft(box.x);
36618 this.split.el.setTop(box.y);
36619 this.split.el.setHeight(box.height);
36622 if(this.collapsed){
36623 this.updateBody(null, box.height);
36625 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36629 Roo.bootstrap.layout.West = function(config){
36630 config.region = "west";
36631 config.cursor = "w-resize";
36633 Roo.bootstrap.layout.Split.call(this, config);
36635 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36636 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36637 this.split.el.addClass("roo-layout-split-h");
36641 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36642 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36644 onRender: function(ctr, pos)
36646 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36647 var size = this.config.initialSize || this.config.width;
36648 if(typeof size != "undefined"){
36649 this.el.setWidth(size);
36653 getBox : function(){
36654 if(this.collapsed){
36655 return this.collapsedEl.getBox();
36657 var box = this.el.getBox();
36659 box.width += this.split.el.getWidth();
36664 updateBox : function(box){
36665 if(this.split && !this.collapsed){
36666 var sw = this.split.el.getWidth();
36668 this.split.el.setLeft(box.x+box.width);
36669 this.split.el.setTop(box.y);
36670 this.split.el.setHeight(box.height);
36672 if(this.collapsed){
36673 this.updateBody(null, box.height);
36675 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36678 Roo.namespace("Roo.bootstrap.panel");/*
36680 * Ext JS Library 1.1.1
36681 * Copyright(c) 2006-2007, Ext JS, LLC.
36683 * Originally Released Under LGPL - original licence link has changed is not relivant.
36686 * <script type="text/javascript">
36689 * @class Roo.ContentPanel
36690 * @extends Roo.util.Observable
36691 * A basic ContentPanel element.
36692 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36693 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36694 * @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
36695 * @cfg {Boolean} closable True if the panel can be closed/removed
36696 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36697 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36698 * @cfg {Toolbar} toolbar A toolbar for this panel
36699 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36700 * @cfg {String} title The title for this panel
36701 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36702 * @cfg {String} url Calls {@link #setUrl} with this value
36703 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36704 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36705 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36706 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36707 * @cfg {Boolean} badges render the badges
36710 * Create a new ContentPanel.
36711 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36712 * @param {String/Object} config A string to set only the title or a config object
36713 * @param {String} content (optional) Set the HTML content for this panel
36714 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36716 Roo.bootstrap.panel.Content = function( config){
36718 this.tpl = config.tpl || false;
36720 var el = config.el;
36721 var content = config.content;
36723 if(config.autoCreate){ // xtype is available if this is called from factory
36726 this.el = Roo.get(el);
36727 if(!this.el && config && config.autoCreate){
36728 if(typeof config.autoCreate == "object"){
36729 if(!config.autoCreate.id){
36730 config.autoCreate.id = config.id||el;
36732 this.el = Roo.DomHelper.append(document.body,
36733 config.autoCreate, true);
36735 var elcfg = { tag: "div",
36736 cls: "roo-layout-inactive-content",
36740 elcfg.html = config.html;
36744 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36747 this.closable = false;
36748 this.loaded = false;
36749 this.active = false;
36752 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36754 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36756 this.wrapEl = this.el; //this.el.wrap();
36758 if (config.toolbar.items) {
36759 ti = config.toolbar.items ;
36760 delete config.toolbar.items ;
36764 this.toolbar.render(this.wrapEl, 'before');
36765 for(var i =0;i < ti.length;i++) {
36766 // Roo.log(['add child', items[i]]);
36767 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36769 this.toolbar.items = nitems;
36770 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36771 delete config.toolbar;
36775 // xtype created footer. - not sure if will work as we normally have to render first..
36776 if (this.footer && !this.footer.el && this.footer.xtype) {
36777 if (!this.wrapEl) {
36778 this.wrapEl = this.el.wrap();
36781 this.footer.container = this.wrapEl.createChild();
36783 this.footer = Roo.factory(this.footer, Roo);
36788 if(typeof config == "string"){
36789 this.title = config;
36791 Roo.apply(this, config);
36795 this.resizeEl = Roo.get(this.resizeEl, true);
36797 this.resizeEl = this.el;
36799 // handle view.xtype
36807 * Fires when this panel is activated.
36808 * @param {Roo.ContentPanel} this
36812 * @event deactivate
36813 * Fires when this panel is activated.
36814 * @param {Roo.ContentPanel} this
36816 "deactivate" : true,
36820 * Fires when this panel is resized if fitToFrame is true.
36821 * @param {Roo.ContentPanel} this
36822 * @param {Number} width The width after any component adjustments
36823 * @param {Number} height The height after any component adjustments
36829 * Fires when this tab is created
36830 * @param {Roo.ContentPanel} this
36841 if(this.autoScroll){
36842 this.resizeEl.setStyle("overflow", "auto");
36844 // fix randome scrolling
36845 //this.el.on('scroll', function() {
36846 // Roo.log('fix random scolling');
36847 // this.scrollTo('top',0);
36850 content = content || this.content;
36852 this.setContent(content);
36854 if(config && config.url){
36855 this.setUrl(this.url, this.params, this.loadOnce);
36860 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36862 if (this.view && typeof(this.view.xtype) != 'undefined') {
36863 this.view.el = this.el.appendChild(document.createElement("div"));
36864 this.view = Roo.factory(this.view);
36865 this.view.render && this.view.render(false, '');
36869 this.fireEvent('render', this);
36872 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36876 setRegion : function(region){
36877 this.region = region;
36878 this.setActiveClass(region && !this.background);
36882 setActiveClass: function(state)
36885 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36886 this.el.setStyle('position','relative');
36888 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36889 this.el.setStyle('position', 'absolute');
36894 * Returns the toolbar for this Panel if one was configured.
36895 * @return {Roo.Toolbar}
36897 getToolbar : function(){
36898 return this.toolbar;
36901 setActiveState : function(active)
36903 this.active = active;
36904 this.setActiveClass(active);
36906 if(this.fireEvent("deactivate", this) === false){
36911 this.fireEvent("activate", this);
36915 * Updates this panel's element
36916 * @param {String} content The new content
36917 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36919 setContent : function(content, loadScripts){
36920 this.el.update(content, loadScripts);
36923 ignoreResize : function(w, h){
36924 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36927 this.lastSize = {width: w, height: h};
36932 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36933 * @return {Roo.UpdateManager} The UpdateManager
36935 getUpdateManager : function(){
36936 return this.el.getUpdateManager();
36939 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36940 * @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:
36943 url: "your-url.php",
36944 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36945 callback: yourFunction,
36946 scope: yourObject, //(optional scope)
36949 text: "Loading...",
36954 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36955 * 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.
36956 * @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}
36957 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36958 * @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.
36959 * @return {Roo.ContentPanel} this
36962 var um = this.el.getUpdateManager();
36963 um.update.apply(um, arguments);
36969 * 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.
36970 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36971 * @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)
36972 * @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)
36973 * @return {Roo.UpdateManager} The UpdateManager
36975 setUrl : function(url, params, loadOnce){
36976 if(this.refreshDelegate){
36977 this.removeListener("activate", this.refreshDelegate);
36979 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36980 this.on("activate", this.refreshDelegate);
36981 return this.el.getUpdateManager();
36984 _handleRefresh : function(url, params, loadOnce){
36985 if(!loadOnce || !this.loaded){
36986 var updater = this.el.getUpdateManager();
36987 updater.update(url, params, this._setLoaded.createDelegate(this));
36991 _setLoaded : function(){
36992 this.loaded = true;
36996 * Returns this panel's id
36999 getId : function(){
37004 * Returns this panel's element - used by regiosn to add.
37005 * @return {Roo.Element}
37007 getEl : function(){
37008 return this.wrapEl || this.el;
37013 adjustForComponents : function(width, height)
37015 //Roo.log('adjustForComponents ');
37016 if(this.resizeEl != this.el){
37017 width -= this.el.getFrameWidth('lr');
37018 height -= this.el.getFrameWidth('tb');
37021 var te = this.toolbar.getEl();
37022 te.setWidth(width);
37023 height -= te.getHeight();
37026 var te = this.footer.getEl();
37027 te.setWidth(width);
37028 height -= te.getHeight();
37032 if(this.adjustments){
37033 width += this.adjustments[0];
37034 height += this.adjustments[1];
37036 return {"width": width, "height": height};
37039 setSize : function(width, height){
37040 if(this.fitToFrame && !this.ignoreResize(width, height)){
37041 if(this.fitContainer && this.resizeEl != this.el){
37042 this.el.setSize(width, height);
37044 var size = this.adjustForComponents(width, height);
37045 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37046 this.fireEvent('resize', this, size.width, size.height);
37051 * Returns this panel's title
37054 getTitle : function(){
37056 if (typeof(this.title) != 'object') {
37061 for (var k in this.title) {
37062 if (!this.title.hasOwnProperty(k)) {
37066 if (k.indexOf('-') >= 0) {
37067 var s = k.split('-');
37068 for (var i = 0; i<s.length; i++) {
37069 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37072 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37079 * Set this panel's title
37080 * @param {String} title
37082 setTitle : function(title){
37083 this.title = title;
37085 this.region.updatePanelTitle(this, title);
37090 * Returns true is this panel was configured to be closable
37091 * @return {Boolean}
37093 isClosable : function(){
37094 return this.closable;
37097 beforeSlide : function(){
37099 this.resizeEl.clip();
37102 afterSlide : function(){
37104 this.resizeEl.unclip();
37108 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37109 * Will fail silently if the {@link #setUrl} method has not been called.
37110 * This does not activate the panel, just updates its content.
37112 refresh : function(){
37113 if(this.refreshDelegate){
37114 this.loaded = false;
37115 this.refreshDelegate();
37120 * Destroys this panel
37122 destroy : function(){
37123 this.el.removeAllListeners();
37124 var tempEl = document.createElement("span");
37125 tempEl.appendChild(this.el.dom);
37126 tempEl.innerHTML = "";
37132 * form - if the content panel contains a form - this is a reference to it.
37133 * @type {Roo.form.Form}
37137 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37138 * This contains a reference to it.
37144 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37154 * @param {Object} cfg Xtype definition of item to add.
37158 getChildContainer: function () {
37159 return this.getEl();
37164 var ret = new Roo.factory(cfg);
37169 if (cfg.xtype.match(/^Form$/)) {
37172 //if (this.footer) {
37173 // el = this.footer.container.insertSibling(false, 'before');
37175 el = this.el.createChild();
37178 this.form = new Roo.form.Form(cfg);
37181 if ( this.form.allItems.length) {
37182 this.form.render(el.dom);
37186 // should only have one of theses..
37187 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37188 // views.. should not be just added - used named prop 'view''
37190 cfg.el = this.el.appendChild(document.createElement("div"));
37193 var ret = new Roo.factory(cfg);
37195 ret.render && ret.render(false, ''); // render blank..
37205 * @class Roo.bootstrap.panel.Grid
37206 * @extends Roo.bootstrap.panel.Content
37208 * Create a new GridPanel.
37209 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37210 * @param {Object} config A the config object
37216 Roo.bootstrap.panel.Grid = function(config)
37220 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37221 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37223 config.el = this.wrapper;
37224 //this.el = this.wrapper;
37226 if (config.container) {
37227 // ctor'ed from a Border/panel.grid
37230 this.wrapper.setStyle("overflow", "hidden");
37231 this.wrapper.addClass('roo-grid-container');
37236 if(config.toolbar){
37237 var tool_el = this.wrapper.createChild();
37238 this.toolbar = Roo.factory(config.toolbar);
37240 if (config.toolbar.items) {
37241 ti = config.toolbar.items ;
37242 delete config.toolbar.items ;
37246 this.toolbar.render(tool_el);
37247 for(var i =0;i < ti.length;i++) {
37248 // Roo.log(['add child', items[i]]);
37249 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37251 this.toolbar.items = nitems;
37253 delete config.toolbar;
37256 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37257 config.grid.scrollBody = true;;
37258 config.grid.monitorWindowResize = false; // turn off autosizing
37259 config.grid.autoHeight = false;
37260 config.grid.autoWidth = false;
37262 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37264 if (config.background) {
37265 // render grid on panel activation (if panel background)
37266 this.on('activate', function(gp) {
37267 if (!gp.grid.rendered) {
37268 gp.grid.render(this.wrapper);
37269 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37274 this.grid.render(this.wrapper);
37275 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37278 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37279 // ??? needed ??? config.el = this.wrapper;
37284 // xtype created footer. - not sure if will work as we normally have to render first..
37285 if (this.footer && !this.footer.el && this.footer.xtype) {
37287 var ctr = this.grid.getView().getFooterPanel(true);
37288 this.footer.dataSource = this.grid.dataSource;
37289 this.footer = Roo.factory(this.footer, Roo);
37290 this.footer.render(ctr);
37300 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37301 getId : function(){
37302 return this.grid.id;
37306 * Returns the grid for this panel
37307 * @return {Roo.bootstrap.Table}
37309 getGrid : function(){
37313 setSize : function(width, height){
37314 if(!this.ignoreResize(width, height)){
37315 var grid = this.grid;
37316 var size = this.adjustForComponents(width, height);
37317 var gridel = grid.getGridEl();
37318 gridel.setSize(size.width, size.height);
37320 var thd = grid.getGridEl().select('thead',true).first();
37321 var tbd = grid.getGridEl().select('tbody', true).first();
37323 tbd.setSize(width, height - thd.getHeight());
37332 beforeSlide : function(){
37333 this.grid.getView().scroller.clip();
37336 afterSlide : function(){
37337 this.grid.getView().scroller.unclip();
37340 destroy : function(){
37341 this.grid.destroy();
37343 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37348 * @class Roo.bootstrap.panel.Nest
37349 * @extends Roo.bootstrap.panel.Content
37351 * Create a new Panel, that can contain a layout.Border.
37354 * @param {Roo.BorderLayout} layout The layout for this panel
37355 * @param {String/Object} config A string to set only the title or a config object
37357 Roo.bootstrap.panel.Nest = function(config)
37359 // construct with only one argument..
37360 /* FIXME - implement nicer consturctors
37361 if (layout.layout) {
37363 layout = config.layout;
37364 delete config.layout;
37366 if (layout.xtype && !layout.getEl) {
37367 // then layout needs constructing..
37368 layout = Roo.factory(layout, Roo);
37372 config.el = config.layout.getEl();
37374 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37376 config.layout.monitorWindowResize = false; // turn off autosizing
37377 this.layout = config.layout;
37378 this.layout.getEl().addClass("roo-layout-nested-layout");
37385 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37387 setSize : function(width, height){
37388 if(!this.ignoreResize(width, height)){
37389 var size = this.adjustForComponents(width, height);
37390 var el = this.layout.getEl();
37391 if (size.height < 1) {
37392 el.setWidth(size.width);
37394 el.setSize(size.width, size.height);
37396 var touch = el.dom.offsetWidth;
37397 this.layout.layout();
37398 // ie requires a double layout on the first pass
37399 if(Roo.isIE && !this.initialized){
37400 this.initialized = true;
37401 this.layout.layout();
37406 // activate all subpanels if not currently active..
37408 setActiveState : function(active){
37409 this.active = active;
37410 this.setActiveClass(active);
37413 this.fireEvent("deactivate", this);
37417 this.fireEvent("activate", this);
37418 // not sure if this should happen before or after..
37419 if (!this.layout) {
37420 return; // should not happen..
37423 for (var r in this.layout.regions) {
37424 reg = this.layout.getRegion(r);
37425 if (reg.getActivePanel()) {
37426 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37427 reg.setActivePanel(reg.getActivePanel());
37430 if (!reg.panels.length) {
37433 reg.showPanel(reg.getPanel(0));
37442 * Returns the nested BorderLayout for this panel
37443 * @return {Roo.BorderLayout}
37445 getLayout : function(){
37446 return this.layout;
37450 * Adds a xtype elements to the layout of the nested panel
37454 xtype : 'ContentPanel',
37461 xtype : 'NestedLayoutPanel',
37467 items : [ ... list of content panels or nested layout panels.. ]
37471 * @param {Object} cfg Xtype definition of item to add.
37473 addxtype : function(cfg) {
37474 return this.layout.addxtype(cfg);
37479 * Ext JS Library 1.1.1
37480 * Copyright(c) 2006-2007, Ext JS, LLC.
37482 * Originally Released Under LGPL - original licence link has changed is not relivant.
37485 * <script type="text/javascript">
37488 * @class Roo.TabPanel
37489 * @extends Roo.util.Observable
37490 * A lightweight tab container.
37494 // basic tabs 1, built from existing content
37495 var tabs = new Roo.TabPanel("tabs1");
37496 tabs.addTab("script", "View Script");
37497 tabs.addTab("markup", "View Markup");
37498 tabs.activate("script");
37500 // more advanced tabs, built from javascript
37501 var jtabs = new Roo.TabPanel("jtabs");
37502 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37504 // set up the UpdateManager
37505 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37506 var updater = tab2.getUpdateManager();
37507 updater.setDefaultUrl("ajax1.htm");
37508 tab2.on('activate', updater.refresh, updater, true);
37510 // Use setUrl for Ajax loading
37511 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37512 tab3.setUrl("ajax2.htm", null, true);
37515 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37518 jtabs.activate("jtabs-1");
37521 * Create a new TabPanel.
37522 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37523 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37525 Roo.bootstrap.panel.Tabs = function(config){
37527 * The container element for this TabPanel.
37528 * @type Roo.Element
37530 this.el = Roo.get(config.el);
37533 if(typeof config == "boolean"){
37534 this.tabPosition = config ? "bottom" : "top";
37536 Roo.apply(this, config);
37540 if(this.tabPosition == "bottom"){
37541 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37542 this.el.addClass("roo-tabs-bottom");
37544 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37545 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37546 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37548 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37550 if(this.tabPosition != "bottom"){
37551 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37552 * @type Roo.Element
37554 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37555 this.el.addClass("roo-tabs-top");
37559 this.bodyEl.setStyle("position", "relative");
37561 this.active = null;
37562 this.activateDelegate = this.activate.createDelegate(this);
37567 * Fires when the active tab changes
37568 * @param {Roo.TabPanel} this
37569 * @param {Roo.TabPanelItem} activePanel The new active tab
37573 * @event beforetabchange
37574 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37575 * @param {Roo.TabPanel} this
37576 * @param {Object} e Set cancel to true on this object to cancel the tab change
37577 * @param {Roo.TabPanelItem} tab The tab being changed to
37579 "beforetabchange" : true
37582 Roo.EventManager.onWindowResize(this.onResize, this);
37583 this.cpad = this.el.getPadding("lr");
37584 this.hiddenCount = 0;
37587 // toolbar on the tabbar support...
37588 if (this.toolbar) {
37589 alert("no toolbar support yet");
37590 this.toolbar = false;
37592 var tcfg = this.toolbar;
37593 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37594 this.toolbar = new Roo.Toolbar(tcfg);
37595 if (Roo.isSafari) {
37596 var tbl = tcfg.container.child('table', true);
37597 tbl.setAttribute('width', '100%');
37605 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37608 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37610 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37612 tabPosition : "top",
37614 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37616 currentTabWidth : 0,
37618 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37622 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37626 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37628 preferredTabWidth : 175,
37630 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37632 resizeTabs : false,
37634 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37636 monitorResize : true,
37638 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37643 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37644 * @param {String} id The id of the div to use <b>or create</b>
37645 * @param {String} text The text for the tab
37646 * @param {String} content (optional) Content to put in the TabPanelItem body
37647 * @param {Boolean} closable (optional) True to create a close icon on the tab
37648 * @return {Roo.TabPanelItem} The created TabPanelItem
37650 addTab : function(id, text, content, closable, tpl)
37652 var item = new Roo.bootstrap.panel.TabItem({
37656 closable : closable,
37659 this.addTabItem(item);
37661 item.setContent(content);
37667 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37668 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37669 * @return {Roo.TabPanelItem}
37671 getTab : function(id){
37672 return this.items[id];
37676 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37677 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37679 hideTab : function(id){
37680 var t = this.items[id];
37683 this.hiddenCount++;
37684 this.autoSizeTabs();
37689 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37690 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37692 unhideTab : function(id){
37693 var t = this.items[id];
37695 t.setHidden(false);
37696 this.hiddenCount--;
37697 this.autoSizeTabs();
37702 * Adds an existing {@link Roo.TabPanelItem}.
37703 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37705 addTabItem : function(item){
37706 this.items[item.id] = item;
37707 this.items.push(item);
37708 // if(this.resizeTabs){
37709 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37710 // this.autoSizeTabs();
37712 // item.autoSize();
37717 * Removes a {@link Roo.TabPanelItem}.
37718 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37720 removeTab : function(id){
37721 var items = this.items;
37722 var tab = items[id];
37723 if(!tab) { return; }
37724 var index = items.indexOf(tab);
37725 if(this.active == tab && items.length > 1){
37726 var newTab = this.getNextAvailable(index);
37731 this.stripEl.dom.removeChild(tab.pnode.dom);
37732 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37733 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37735 items.splice(index, 1);
37736 delete this.items[tab.id];
37737 tab.fireEvent("close", tab);
37738 tab.purgeListeners();
37739 this.autoSizeTabs();
37742 getNextAvailable : function(start){
37743 var items = this.items;
37745 // look for a next tab that will slide over to
37746 // replace the one being removed
37747 while(index < items.length){
37748 var item = items[++index];
37749 if(item && !item.isHidden()){
37753 // if one isn't found select the previous tab (on the left)
37756 var item = items[--index];
37757 if(item && !item.isHidden()){
37765 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37766 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37768 disableTab : function(id){
37769 var tab = this.items[id];
37770 if(tab && this.active != tab){
37776 * Enables a {@link Roo.TabPanelItem} that is disabled.
37777 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37779 enableTab : function(id){
37780 var tab = this.items[id];
37785 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37786 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37787 * @return {Roo.TabPanelItem} The TabPanelItem.
37789 activate : function(id){
37790 var tab = this.items[id];
37794 if(tab == this.active || tab.disabled){
37798 this.fireEvent("beforetabchange", this, e, tab);
37799 if(e.cancel !== true && !tab.disabled){
37801 this.active.hide();
37803 this.active = this.items[id];
37804 this.active.show();
37805 this.fireEvent("tabchange", this, this.active);
37811 * Gets the active {@link Roo.TabPanelItem}.
37812 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37814 getActiveTab : function(){
37815 return this.active;
37819 * Updates the tab body element to fit the height of the container element
37820 * for overflow scrolling
37821 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37823 syncHeight : function(targetHeight){
37824 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37825 var bm = this.bodyEl.getMargins();
37826 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37827 this.bodyEl.setHeight(newHeight);
37831 onResize : function(){
37832 if(this.monitorResize){
37833 this.autoSizeTabs();
37838 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37840 beginUpdate : function(){
37841 this.updating = true;
37845 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37847 endUpdate : function(){
37848 this.updating = false;
37849 this.autoSizeTabs();
37853 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37855 autoSizeTabs : function(){
37856 var count = this.items.length;
37857 var vcount = count - this.hiddenCount;
37858 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37861 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37862 var availWidth = Math.floor(w / vcount);
37863 var b = this.stripBody;
37864 if(b.getWidth() > w){
37865 var tabs = this.items;
37866 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37867 if(availWidth < this.minTabWidth){
37868 /*if(!this.sleft){ // incomplete scrolling code
37869 this.createScrollButtons();
37872 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37875 if(this.currentTabWidth < this.preferredTabWidth){
37876 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37882 * Returns the number of tabs in this TabPanel.
37885 getCount : function(){
37886 return this.items.length;
37890 * Resizes all the tabs to the passed width
37891 * @param {Number} The new width
37893 setTabWidth : function(width){
37894 this.currentTabWidth = width;
37895 for(var i = 0, len = this.items.length; i < len; i++) {
37896 if(!this.items[i].isHidden()) {
37897 this.items[i].setWidth(width);
37903 * Destroys this TabPanel
37904 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37906 destroy : function(removeEl){
37907 Roo.EventManager.removeResizeListener(this.onResize, this);
37908 for(var i = 0, len = this.items.length; i < len; i++){
37909 this.items[i].purgeListeners();
37911 if(removeEl === true){
37912 this.el.update("");
37917 createStrip : function(container)
37919 var strip = document.createElement("nav");
37920 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37921 container.appendChild(strip);
37925 createStripList : function(strip)
37927 // div wrapper for retard IE
37928 // returns the "tr" element.
37929 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37930 //'<div class="x-tabs-strip-wrap">'+
37931 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37932 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37933 return strip.firstChild; //.firstChild.firstChild.firstChild;
37935 createBody : function(container)
37937 var body = document.createElement("div");
37938 Roo.id(body, "tab-body");
37939 //Roo.fly(body).addClass("x-tabs-body");
37940 Roo.fly(body).addClass("tab-content");
37941 container.appendChild(body);
37944 createItemBody :function(bodyEl, id){
37945 var body = Roo.getDom(id);
37947 body = document.createElement("div");
37950 //Roo.fly(body).addClass("x-tabs-item-body");
37951 Roo.fly(body).addClass("tab-pane");
37952 bodyEl.insertBefore(body, bodyEl.firstChild);
37956 createStripElements : function(stripEl, text, closable, tpl)
37958 var td = document.createElement("li"); // was td..
37961 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37964 stripEl.appendChild(td);
37966 td.className = "x-tabs-closable";
37967 if(!this.closeTpl){
37968 this.closeTpl = new Roo.Template(
37969 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37970 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37971 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37974 var el = this.closeTpl.overwrite(td, {"text": text});
37975 var close = el.getElementsByTagName("div")[0];
37976 var inner = el.getElementsByTagName("em")[0];
37977 return {"el": el, "close": close, "inner": inner};
37980 // not sure what this is..
37981 // if(!this.tabTpl){
37982 //this.tabTpl = new Roo.Template(
37983 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37984 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37986 // this.tabTpl = new Roo.Template(
37987 // '<a href="#">' +
37988 // '<span unselectable="on"' +
37989 // (this.disableTooltips ? '' : ' title="{text}"') +
37990 // ' >{text}</span></a>'
37996 var template = tpl || this.tabTpl || false;
38000 template = new Roo.Template(
38002 '<span unselectable="on"' +
38003 (this.disableTooltips ? '' : ' title="{text}"') +
38004 ' >{text}</span></a>'
38008 switch (typeof(template)) {
38012 template = new Roo.Template(template);
38018 var el = template.overwrite(td, {"text": text});
38020 var inner = el.getElementsByTagName("span")[0];
38022 return {"el": el, "inner": inner};
38030 * @class Roo.TabPanelItem
38031 * @extends Roo.util.Observable
38032 * Represents an individual item (tab plus body) in a TabPanel.
38033 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38034 * @param {String} id The id of this TabPanelItem
38035 * @param {String} text The text for the tab of this TabPanelItem
38036 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38038 Roo.bootstrap.panel.TabItem = function(config){
38040 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38041 * @type Roo.TabPanel
38043 this.tabPanel = config.panel;
38045 * The id for this TabPanelItem
38048 this.id = config.id;
38050 this.disabled = false;
38052 this.text = config.text;
38054 this.loaded = false;
38055 this.closable = config.closable;
38058 * The body element for this TabPanelItem.
38059 * @type Roo.Element
38061 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38062 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38063 this.bodyEl.setStyle("display", "block");
38064 this.bodyEl.setStyle("zoom", "1");
38065 //this.hideAction();
38067 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38069 this.el = Roo.get(els.el);
38070 this.inner = Roo.get(els.inner, true);
38071 this.textEl = Roo.get(this.el.dom.firstChild, true);
38072 this.pnode = Roo.get(els.el.parentNode, true);
38073 // this.el.on("mousedown", this.onTabMouseDown, this);
38074 this.el.on("click", this.onTabClick, this);
38076 if(config.closable){
38077 var c = Roo.get(els.close, true);
38078 c.dom.title = this.closeText;
38079 c.addClassOnOver("close-over");
38080 c.on("click", this.closeClick, this);
38086 * Fires when this tab becomes the active tab.
38087 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38088 * @param {Roo.TabPanelItem} this
38092 * @event beforeclose
38093 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38094 * @param {Roo.TabPanelItem} this
38095 * @param {Object} e Set cancel to true on this object to cancel the close.
38097 "beforeclose": true,
38100 * Fires when this tab is closed.
38101 * @param {Roo.TabPanelItem} this
38105 * @event deactivate
38106 * Fires when this tab is no longer the active tab.
38107 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38108 * @param {Roo.TabPanelItem} this
38110 "deactivate" : true
38112 this.hidden = false;
38114 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38117 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38119 purgeListeners : function(){
38120 Roo.util.Observable.prototype.purgeListeners.call(this);
38121 this.el.removeAllListeners();
38124 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38127 this.pnode.addClass("active");
38130 this.tabPanel.stripWrap.repaint();
38132 this.fireEvent("activate", this.tabPanel, this);
38136 * Returns true if this tab is the active tab.
38137 * @return {Boolean}
38139 isActive : function(){
38140 return this.tabPanel.getActiveTab() == this;
38144 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38147 this.pnode.removeClass("active");
38149 this.fireEvent("deactivate", this.tabPanel, this);
38152 hideAction : function(){
38153 this.bodyEl.hide();
38154 this.bodyEl.setStyle("position", "absolute");
38155 this.bodyEl.setLeft("-20000px");
38156 this.bodyEl.setTop("-20000px");
38159 showAction : function(){
38160 this.bodyEl.setStyle("position", "relative");
38161 this.bodyEl.setTop("");
38162 this.bodyEl.setLeft("");
38163 this.bodyEl.show();
38167 * Set the tooltip for the tab.
38168 * @param {String} tooltip The tab's tooltip
38170 setTooltip : function(text){
38171 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38172 this.textEl.dom.qtip = text;
38173 this.textEl.dom.removeAttribute('title');
38175 this.textEl.dom.title = text;
38179 onTabClick : function(e){
38180 e.preventDefault();
38181 this.tabPanel.activate(this.id);
38184 onTabMouseDown : function(e){
38185 e.preventDefault();
38186 this.tabPanel.activate(this.id);
38189 getWidth : function(){
38190 return this.inner.getWidth();
38193 setWidth : function(width){
38194 var iwidth = width - this.pnode.getPadding("lr");
38195 this.inner.setWidth(iwidth);
38196 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38197 this.pnode.setWidth(width);
38201 * Show or hide the tab
38202 * @param {Boolean} hidden True to hide or false to show.
38204 setHidden : function(hidden){
38205 this.hidden = hidden;
38206 this.pnode.setStyle("display", hidden ? "none" : "");
38210 * Returns true if this tab is "hidden"
38211 * @return {Boolean}
38213 isHidden : function(){
38214 return this.hidden;
38218 * Returns the text for this tab
38221 getText : function(){
38225 autoSize : function(){
38226 //this.el.beginMeasure();
38227 this.textEl.setWidth(1);
38229 * #2804 [new] Tabs in Roojs
38230 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38232 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38233 //this.el.endMeasure();
38237 * Sets the text for the tab (Note: this also sets the tooltip text)
38238 * @param {String} text The tab's text and tooltip
38240 setText : function(text){
38242 this.textEl.update(text);
38243 this.setTooltip(text);
38244 //if(!this.tabPanel.resizeTabs){
38245 // this.autoSize();
38249 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38251 activate : function(){
38252 this.tabPanel.activate(this.id);
38256 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38258 disable : function(){
38259 if(this.tabPanel.active != this){
38260 this.disabled = true;
38261 this.pnode.addClass("disabled");
38266 * Enables this TabPanelItem if it was previously disabled.
38268 enable : function(){
38269 this.disabled = false;
38270 this.pnode.removeClass("disabled");
38274 * Sets the content for this TabPanelItem.
38275 * @param {String} content The content
38276 * @param {Boolean} loadScripts true to look for and load scripts
38278 setContent : function(content, loadScripts){
38279 this.bodyEl.update(content, loadScripts);
38283 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38284 * @return {Roo.UpdateManager} The UpdateManager
38286 getUpdateManager : function(){
38287 return this.bodyEl.getUpdateManager();
38291 * Set a URL to be used to load the content for this TabPanelItem.
38292 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38293 * @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)
38294 * @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)
38295 * @return {Roo.UpdateManager} The UpdateManager
38297 setUrl : function(url, params, loadOnce){
38298 if(this.refreshDelegate){
38299 this.un('activate', this.refreshDelegate);
38301 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38302 this.on("activate", this.refreshDelegate);
38303 return this.bodyEl.getUpdateManager();
38307 _handleRefresh : function(url, params, loadOnce){
38308 if(!loadOnce || !this.loaded){
38309 var updater = this.bodyEl.getUpdateManager();
38310 updater.update(url, params, this._setLoaded.createDelegate(this));
38315 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38316 * Will fail silently if the setUrl method has not been called.
38317 * This does not activate the panel, just updates its content.
38319 refresh : function(){
38320 if(this.refreshDelegate){
38321 this.loaded = false;
38322 this.refreshDelegate();
38327 _setLoaded : function(){
38328 this.loaded = true;
38332 closeClick : function(e){
38335 this.fireEvent("beforeclose", this, o);
38336 if(o.cancel !== true){
38337 this.tabPanel.removeTab(this.id);
38341 * The text displayed in the tooltip for the close icon.
38344 closeText : "Close this tab"
38347 * This script refer to:
38348 * Title: International Telephone Input
38349 * Author: Jack O'Connor
38350 * Code version: v12.1.12
38351 * Availability: https://github.com/jackocnr/intl-tel-input.git
38354 Roo.bootstrap.PhoneInputData = function() {
38357 "Afghanistan (افغانستان)",
38362 "Albania (Shqipëri)",
38367 "Algeria (الجزائر)",
38392 "Antigua and Barbuda",
38402 "Armenia (Հայաստան)",
38418 "Austria (Österreich)",
38423 "Azerbaijan (Azərbaycan)",
38433 "Bahrain (البحرين)",
38438 "Bangladesh (বাংলাদেশ)",
38448 "Belarus (Беларусь)",
38453 "Belgium (België)",
38483 "Bosnia and Herzegovina (Босна и Херцеговина)",
38498 "British Indian Ocean Territory",
38503 "British Virgin Islands",
38513 "Bulgaria (България)",
38523 "Burundi (Uburundi)",
38528 "Cambodia (កម្ពុជា)",
38533 "Cameroon (Cameroun)",
38542 ["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"]
38545 "Cape Verde (Kabu Verdi)",
38550 "Caribbean Netherlands",
38561 "Central African Republic (République centrafricaine)",
38581 "Christmas Island",
38587 "Cocos (Keeling) Islands",
38598 "Comoros (جزر القمر)",
38603 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38608 "Congo (Republic) (Congo-Brazzaville)",
38628 "Croatia (Hrvatska)",
38649 "Czech Republic (Česká republika)",
38654 "Denmark (Danmark)",
38669 "Dominican Republic (República Dominicana)",
38673 ["809", "829", "849"]
38691 "Equatorial Guinea (Guinea Ecuatorial)",
38711 "Falkland Islands (Islas Malvinas)",
38716 "Faroe Islands (Føroyar)",
38737 "French Guiana (Guyane française)",
38742 "French Polynesia (Polynésie française)",
38757 "Georgia (საქართველო)",
38762 "Germany (Deutschland)",
38782 "Greenland (Kalaallit Nunaat)",
38819 "Guinea-Bissau (Guiné Bissau)",
38844 "Hungary (Magyarország)",
38849 "Iceland (Ísland)",
38869 "Iraq (العراق)",
38885 "Israel (ישראל)",
38912 "Jordan (الأردن)",
38917 "Kazakhstan (Казахстан)",
38938 "Kuwait (الكويت)",
38943 "Kyrgyzstan (Кыргызстан)",
38953 "Latvia (Latvija)",
38958 "Lebanon (لبنان)",
38973 "Libya (ليبيا)",
38983 "Lithuania (Lietuva)",
38998 "Macedonia (FYROM) (Македонија)",
39003 "Madagascar (Madagasikara)",
39033 "Marshall Islands",
39043 "Mauritania (موريتانيا)",
39048 "Mauritius (Moris)",
39069 "Moldova (Republica Moldova)",
39079 "Mongolia (Монгол)",
39084 "Montenegro (Crna Gora)",
39094 "Morocco (المغرب)",
39100 "Mozambique (Moçambique)",
39105 "Myanmar (Burma) (မြန်မာ)",
39110 "Namibia (Namibië)",
39125 "Netherlands (Nederland)",
39130 "New Caledonia (Nouvelle-Calédonie)",
39165 "North Korea (조선 민주주의 인민 공화국)",
39170 "Northern Mariana Islands",
39186 "Pakistan (پاکستان)",
39196 "Palestine (فلسطين)",
39206 "Papua New Guinea",
39248 "Réunion (La Réunion)",
39254 "Romania (România)",
39270 "Saint Barthélemy",
39281 "Saint Kitts and Nevis",
39291 "Saint Martin (Saint-Martin (partie française))",
39297 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39302 "Saint Vincent and the Grenadines",
39317 "São Tomé and Príncipe (São Tomé e Príncipe)",
39322 "Saudi Arabia (المملكة العربية السعودية)",
39327 "Senegal (Sénégal)",
39357 "Slovakia (Slovensko)",
39362 "Slovenia (Slovenija)",
39372 "Somalia (Soomaaliya)",
39382 "South Korea (대한민국)",
39387 "South Sudan (جنوب السودان)",
39397 "Sri Lanka (ශ්රී ලංකාව)",
39402 "Sudan (السودان)",
39412 "Svalbard and Jan Mayen",
39423 "Sweden (Sverige)",
39428 "Switzerland (Schweiz)",
39433 "Syria (سوريا)",
39478 "Trinidad and Tobago",
39483 "Tunisia (تونس)",
39488 "Turkey (Türkiye)",
39498 "Turks and Caicos Islands",
39508 "U.S. Virgin Islands",
39518 "Ukraine (Україна)",
39523 "United Arab Emirates (الإمارات العربية المتحدة)",
39545 "Uzbekistan (Oʻzbekiston)",
39555 "Vatican City (Città del Vaticano)",
39566 "Vietnam (Việt Nam)",
39571 "Wallis and Futuna (Wallis-et-Futuna)",
39576 "Western Sahara (الصحراء الغربية)",
39582 "Yemen (اليمن)",
39606 * This script refer to:
39607 * Title: International Telephone Input
39608 * Author: Jack O'Connor
39609 * Code version: v12.1.12
39610 * Availability: https://github.com/jackocnr/intl-tel-input.git
39614 * @class Roo.bootstrap.PhoneInput
39615 * @extends Roo.bootstrap.TriggerField
39616 * An input with International dial-code selection
39618 * @cfg {String} defaultDialCode default '+852'
39619 * @cfg {Array} preferedCountries default []
39622 * Create a new PhoneInput.
39623 * @param {Object} config Configuration options
39626 Roo.bootstrap.PhoneInput = function(config) {
39627 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39630 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39632 listWidth: undefined,
39634 selectedClass: 'active',
39636 invalidClass : "has-warning",
39638 validClass: 'has-success',
39640 allowed: '0123456789',
39643 * @cfg {String} defaultDialCode The default dial code when initializing the input
39645 defaultDialCode: '+852',
39648 * @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
39650 preferedCountries: false,
39652 getAutoCreate : function()
39654 var data = Roo.bootstrap.PhoneInputData();
39655 var align = this.labelAlign || this.parentLabelAlign();
39658 this.allCountries = [];
39659 this.dialCodeMapping = [];
39661 for (var i = 0; i < data.length; i++) {
39663 this.allCountries[i] = {
39667 priority: c[3] || 0,
39668 areaCodes: c[4] || null
39670 this.dialCodeMapping[c[2]] = {
39673 priority: c[3] || 0,
39674 areaCodes: c[4] || null
39686 cls : 'form-control tel-input',
39687 autocomplete: 'new-password'
39690 var hiddenInput = {
39693 cls: 'hidden-tel-input'
39697 hiddenInput.name = this.name;
39700 if (this.disabled) {
39701 input.disabled = true;
39704 var flag_container = {
39721 cls: this.hasFeedback ? 'has-feedback' : '',
39727 cls: 'dial-code-holder',
39734 cls: 'roo-select2-container input-group',
39741 if (this.fieldLabel.length) {
39744 tooltip: 'This field is required'
39750 cls: 'control-label',
39756 html: this.fieldLabel
39759 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39765 if(this.indicatorpos == 'right') {
39766 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39773 if(align == 'left') {
39781 if(this.labelWidth > 12){
39782 label.style = "width: " + this.labelWidth + 'px';
39784 if(this.labelWidth < 13 && this.labelmd == 0){
39785 this.labelmd = this.labelWidth;
39787 if(this.labellg > 0){
39788 label.cls += ' col-lg-' + this.labellg;
39789 input.cls += ' col-lg-' + (12 - this.labellg);
39791 if(this.labelmd > 0){
39792 label.cls += ' col-md-' + this.labelmd;
39793 container.cls += ' col-md-' + (12 - this.labelmd);
39795 if(this.labelsm > 0){
39796 label.cls += ' col-sm-' + this.labelsm;
39797 container.cls += ' col-sm-' + (12 - this.labelsm);
39799 if(this.labelxs > 0){
39800 label.cls += ' col-xs-' + this.labelxs;
39801 container.cls += ' col-xs-' + (12 - this.labelxs);
39811 var settings = this;
39813 ['xs','sm','md','lg'].map(function(size){
39814 if (settings[size]) {
39815 cfg.cls += ' col-' + size + '-' + settings[size];
39819 this.store = new Roo.data.Store({
39820 proxy : new Roo.data.MemoryProxy({}),
39821 reader : new Roo.data.JsonReader({
39832 'name' : 'dialCode',
39836 'name' : 'priority',
39840 'name' : 'areaCodes',
39847 if(!this.preferedCountries) {
39848 this.preferedCountries = [
39855 var p = this.preferedCountries.reverse();
39858 for (var i = 0; i < p.length; i++) {
39859 for (var j = 0; j < this.allCountries.length; j++) {
39860 if(this.allCountries[j].iso2 == p[i]) {
39861 var t = this.allCountries[j];
39862 this.allCountries.splice(j,1);
39863 this.allCountries.unshift(t);
39869 this.store.proxy.data = {
39871 data: this.allCountries
39877 initEvents : function()
39880 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39882 this.indicator = this.indicatorEl();
39883 this.flag = this.flagEl();
39884 this.dialCodeHolder = this.dialCodeHolderEl();
39886 this.trigger = this.el.select('div.flag-box',true).first();
39887 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39892 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39893 _this.list.setWidth(lw);
39896 this.list.on('mouseover', this.onViewOver, this);
39897 this.list.on('mousemove', this.onViewMove, this);
39898 this.inputEl().on("keyup", this.onKeyUp, this);
39900 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39902 this.view = new Roo.View(this.list, this.tpl, {
39903 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39906 this.view.on('click', this.onViewClick, this);
39907 this.setValue(this.defaultDialCode);
39910 onTriggerClick : function(e)
39912 Roo.log('trigger click');
39917 if(this.isExpanded()){
39919 this.hasFocus = false;
39921 this.store.load({});
39922 this.hasFocus = true;
39927 isExpanded : function()
39929 return this.list.isVisible();
39932 collapse : function()
39934 if(!this.isExpanded()){
39938 Roo.get(document).un('mousedown', this.collapseIf, this);
39939 Roo.get(document).un('mousewheel', this.collapseIf, this);
39940 this.fireEvent('collapse', this);
39944 expand : function()
39948 if(this.isExpanded() || !this.hasFocus){
39952 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39953 this.list.setWidth(lw);
39956 this.restrictHeight();
39958 Roo.get(document).on('mousedown', this.collapseIf, this);
39959 Roo.get(document).on('mousewheel', this.collapseIf, this);
39961 this.fireEvent('expand', this);
39964 restrictHeight : function()
39966 this.list.alignTo(this.inputEl(), this.listAlign);
39967 this.list.alignTo(this.inputEl(), this.listAlign);
39970 onViewOver : function(e, t)
39972 if(this.inKeyMode){
39975 var item = this.view.findItemFromChild(t);
39978 var index = this.view.indexOf(item);
39979 this.select(index, false);
39984 onViewClick : function(view, doFocus, el, e)
39986 var index = this.view.getSelectedIndexes()[0];
39988 var r = this.store.getAt(index);
39991 this.onSelect(r, index);
39993 if(doFocus !== false && !this.blockFocus){
39994 this.inputEl().focus();
39998 onViewMove : function(e, t)
40000 this.inKeyMode = false;
40003 select : function(index, scrollIntoView)
40005 this.selectedIndex = index;
40006 this.view.select(index);
40007 if(scrollIntoView !== false){
40008 var el = this.view.getNode(index);
40010 this.list.scrollChildIntoView(el, false);
40015 createList : function()
40017 this.list = Roo.get(document.body).createChild({
40019 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40020 style: 'display:none'
40022 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40025 collapseIf : function(e)
40027 var in_combo = e.within(this.el);
40028 var in_list = e.within(this.list);
40029 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40031 if (in_combo || in_list || is_list) {
40037 onSelect : function(record, index)
40039 if(this.fireEvent('beforeselect', this, record, index) !== false){
40041 this.setFlagClass(record.data.iso2);
40042 this.setDialCode(record.data.dialCode);
40043 this.hasFocus = false;
40045 this.fireEvent('select', this, record, index);
40049 flagEl : function()
40051 var flag = this.el.select('div.flag',true).first();
40058 dialCodeHolderEl : function()
40060 var d = this.el.select('input.dial-code-holder',true).first();
40067 setDialCode : function(v)
40069 this.dialCodeHolder.dom.value = '+'+v;
40072 setFlagClass : function(n)
40074 this.flag.dom.className = 'flag '+n;
40077 getValue : function()
40079 var v = this.inputEl().getValue();
40080 if(this.dialCodeHolder) {
40081 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40086 setValue : function(v)
40088 var d = this.getDialCode(v);
40090 //invalid dial code
40091 if(v.length == 0 || !d || d.length == 0) {
40093 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40094 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40100 this.setFlagClass(this.dialCodeMapping[d].iso2);
40101 this.setDialCode(d);
40102 this.inputEl().dom.value = v.replace('+'+d,'');
40103 this.hiddenEl().dom.value = this.getValue();
40108 getDialCode : function(v = '')
40110 if (v.length == 0) {
40111 return this.dialCodeHolder.dom.value;
40115 if (v.charAt(0) != "+") {
40118 var numericChars = "";
40119 for (var i = 1; i < v.length; i++) {
40120 var c = v.charAt(i);
40123 if (this.dialCodeMapping[numericChars]) {
40124 dialCode = v.substr(1, i);
40126 if (numericChars.length == 4) {
40136 this.setValue(this.defaultDialCode);
40140 hiddenEl : function()
40142 return this.el.select('input.hidden-tel-input',true).first();
40145 onKeyUp : function(e){
40147 var k = e.getKey();
40148 var c = e.getCharCode();
40151 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40152 this.allowed.indexOf(String.fromCharCode(c)) === -1
40157 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40160 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40164 this.setValue(this.getValue());
40169 * @class Roo.bootstrap.MoneyField
40170 * @extends Roo.bootstrap.ComboBox
40171 * Bootstrap MoneyField class
40174 * Create a new MoneyField.
40175 * @param {Object} config Configuration options
40178 Roo.bootstrap.MoneyField = function(config) {
40180 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40184 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40187 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40189 allowDecimals : true,
40191 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40193 decimalSeparator : ".",
40195 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40197 decimalPrecision : 0,
40199 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40201 allowNegative : true,
40203 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40205 minValue : Number.NEGATIVE_INFINITY,
40207 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40209 maxValue : Number.MAX_VALUE,
40211 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40213 minText : "The minimum value for this field is {0}",
40215 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40217 maxText : "The maximum value for this field is {0}",
40219 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40220 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40222 nanText : "{0} is not a valid number",
40224 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40228 * @cfg {String} defaults currency of the MoneyField
40229 * value should be in lkey
40231 defaultCurrency : false,
40233 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40235 thousandsDelimiter : false,
40245 getAutoCreate : function()
40247 var align = this.labelAlign || this.parentLabelAlign();
40259 cls : 'form-control roo-money-amount-input',
40260 autocomplete: 'new-password'
40263 var hiddenInput = {
40267 cls: 'hidden-number-input'
40271 hiddenInput.name = this.name;
40274 if (this.disabled) {
40275 input.disabled = true;
40278 var clg = 12 - this.inputlg;
40279 var cmd = 12 - this.inputmd;
40280 var csm = 12 - this.inputsm;
40281 var cxs = 12 - this.inputxs;
40285 cls : 'row roo-money-field',
40289 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40293 cls: 'roo-select2-container input-group',
40297 cls : 'form-control roo-money-currency-input',
40298 autocomplete: 'new-password',
40300 name : this.currencyName
40304 cls : 'input-group-addon',
40318 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40322 cls: this.hasFeedback ? 'has-feedback' : '',
40333 if (this.fieldLabel.length) {
40336 tooltip: 'This field is required'
40342 cls: 'control-label',
40348 html: this.fieldLabel
40351 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40357 if(this.indicatorpos == 'right') {
40358 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40365 if(align == 'left') {
40373 if(this.labelWidth > 12){
40374 label.style = "width: " + this.labelWidth + 'px';
40376 if(this.labelWidth < 13 && this.labelmd == 0){
40377 this.labelmd = this.labelWidth;
40379 if(this.labellg > 0){
40380 label.cls += ' col-lg-' + this.labellg;
40381 input.cls += ' col-lg-' + (12 - this.labellg);
40383 if(this.labelmd > 0){
40384 label.cls += ' col-md-' + this.labelmd;
40385 container.cls += ' col-md-' + (12 - this.labelmd);
40387 if(this.labelsm > 0){
40388 label.cls += ' col-sm-' + this.labelsm;
40389 container.cls += ' col-sm-' + (12 - this.labelsm);
40391 if(this.labelxs > 0){
40392 label.cls += ' col-xs-' + this.labelxs;
40393 container.cls += ' col-xs-' + (12 - this.labelxs);
40404 var settings = this;
40406 ['xs','sm','md','lg'].map(function(size){
40407 if (settings[size]) {
40408 cfg.cls += ' col-' + size + '-' + settings[size];
40415 initEvents : function()
40417 this.indicator = this.indicatorEl();
40419 this.initCurrencyEvent();
40421 this.initNumberEvent();
40424 initCurrencyEvent : function()
40427 throw "can not find store for combo";
40430 this.store = Roo.factory(this.store, Roo.data);
40431 this.store.parent = this;
40435 this.triggerEl = this.el.select('.input-group-addon', true).first();
40437 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40442 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40443 _this.list.setWidth(lw);
40446 this.list.on('mouseover', this.onViewOver, this);
40447 this.list.on('mousemove', this.onViewMove, this);
40448 this.list.on('scroll', this.onViewScroll, this);
40451 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40454 this.view = new Roo.View(this.list, this.tpl, {
40455 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40458 this.view.on('click', this.onViewClick, this);
40460 this.store.on('beforeload', this.onBeforeLoad, this);
40461 this.store.on('load', this.onLoad, this);
40462 this.store.on('loadexception', this.onLoadException, this);
40464 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40465 "up" : function(e){
40466 this.inKeyMode = true;
40470 "down" : function(e){
40471 if(!this.isExpanded()){
40472 this.onTriggerClick();
40474 this.inKeyMode = true;
40479 "enter" : function(e){
40482 if(this.fireEvent("specialkey", this, e)){
40483 this.onViewClick(false);
40489 "esc" : function(e){
40493 "tab" : function(e){
40496 if(this.fireEvent("specialkey", this, e)){
40497 this.onViewClick(false);
40505 doRelay : function(foo, bar, hname){
40506 if(hname == 'down' || this.scope.isExpanded()){
40507 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40515 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40519 initNumberEvent : function(e)
40521 this.inputEl().on("keydown" , this.fireKey, this);
40522 this.inputEl().on("focus", this.onFocus, this);
40523 this.inputEl().on("blur", this.onBlur, this);
40525 this.inputEl().relayEvent('keyup', this);
40527 if(this.indicator){
40528 this.indicator.addClass('invisible');
40531 this.originalValue = this.getValue();
40533 if(this.validationEvent == 'keyup'){
40534 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40535 this.inputEl().on('keyup', this.filterValidation, this);
40537 else if(this.validationEvent !== false){
40538 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40541 if(this.selectOnFocus){
40542 this.on("focus", this.preFocus, this);
40545 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40546 this.inputEl().on("keypress", this.filterKeys, this);
40548 this.inputEl().relayEvent('keypress', this);
40551 var allowed = "0123456789";
40553 if(this.allowDecimals){
40554 allowed += this.decimalSeparator;
40557 if(this.allowNegative){
40561 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40563 var keyPress = function(e){
40565 var k = e.getKey();
40567 var c = e.getCharCode();
40570 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40571 allowed.indexOf(String.fromCharCode(c)) === -1
40577 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40581 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40586 this.inputEl().on("keypress", keyPress, this);
40590 onTriggerClick : function(e)
40597 this.loadNext = false;
40599 if(this.isExpanded()){
40604 this.hasFocus = true;
40606 if(this.triggerAction == 'all') {
40607 this.doQuery(this.allQuery, true);
40611 this.doQuery(this.getRawValue());
40614 getCurrency : function()
40616 var v = this.currencyEl().getValue();
40621 restrictHeight : function()
40623 this.list.alignTo(this.currencyEl(), this.listAlign);
40624 this.list.alignTo(this.currencyEl(), this.listAlign);
40627 onViewClick : function(view, doFocus, el, e)
40629 var index = this.view.getSelectedIndexes()[0];
40631 var r = this.store.getAt(index);
40634 this.onSelect(r, index);
40638 onSelect : function(record, index){
40640 if(this.fireEvent('beforeselect', this, record, index) !== false){
40642 this.setFromCurrencyData(index > -1 ? record.data : false);
40646 this.fireEvent('select', this, record, index);
40650 setFromCurrencyData : function(o)
40654 this.lastCurrency = o;
40656 if (this.currencyField) {
40657 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40659 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40662 this.lastSelectionText = currency;
40664 //setting default currency
40665 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40666 this.setCurrency(this.defaultCurrency);
40670 this.setCurrency(currency);
40673 setFromData : function(o)
40677 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40679 this.setFromCurrencyData(c);
40684 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40686 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40689 this.setValue(value);
40693 setCurrency : function(v)
40695 this.currencyValue = v;
40698 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40703 setValue : function(v)
40705 v = this.fixPrecision(v);
40707 v = String(v).replace(".", this.decimalSeparator);
40713 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40715 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40716 this.thousandsDelimiter || ','
40719 if(this.allowBlank && !v) {
40720 this.inputEl().dom.value = '';
40727 getRawValue : function()
40729 var v = this.inputEl().getValue();
40734 getValue : function()
40736 return this.fixPrecision(this.parseValue(this.getRawValue()));
40739 parseValue : function(value)
40741 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40742 return isNaN(value) ? '' : value;
40745 fixPrecision : function(value)
40747 var nan = isNaN(value);
40749 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40750 return nan ? '' : value;
40753 return parseFloat(value).toFixed(this.decimalPrecision);
40756 decimalPrecisionFcn : function(v)
40758 return Math.floor(v);
40761 validateValue : function(value)
40763 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40767 var num = this.parseValue(value);
40770 this.markInvalid(String.format(this.nanText, value));
40774 if(num < this.minValue){
40775 this.markInvalid(String.format(this.minText, this.minValue));
40779 if(num > this.maxValue){
40780 this.markInvalid(String.format(this.maxText, this.maxValue));
40787 validate : function()
40789 if(this.disabled || this.allowBlank){
40794 var currency = this.getCurrency();
40796 if(this.validateValue(this.getRawValue()) && currency.length){
40801 this.markInvalid();
40805 getName: function()
40810 beforeBlur : function()
40816 var v = this.parseValue(this.getRawValue());
40823 onBlur : function()
40827 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40828 //this.el.removeClass(this.focusClass);
40831 this.hasFocus = false;
40833 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40837 var v = this.getValue();
40839 if(String(v) !== String(this.startValue)){
40840 this.fireEvent('change', this, v, this.startValue);
40843 this.fireEvent("blur", this);
40846 inputEl : function()
40848 return this.el.select('.roo-money-amount-input', true).first();
40851 currencyEl : function()
40853 return this.el.select('.roo-money-currency-input', true).first();
40856 hiddenEl : function()
40858 return this.el.select('input.hidden-number-input',true).first();